/*
--- CSU213 Spring 2006 Lecture Notes ---------
Copyright 2006  Viera K. Proulx

Lecture 13a: A List of Valid Names

Goals:

 - Practice designing methods for lists

Introduction:

One of the problems in the homework assignment concerned the question
whether all names in a given list are valid names. Of course, valid names
are themselves given as a list of names. The problem illustrates the use
of the design recipe in unraveling this problem's complexity.
------------------------------------------------------------------------

We start with the problem analysis. The information available is 
represented as two lists of names (String-s). The classes that represent 
these strings are ILoString, MTLoString, and ConsLoString, the first of 
them a common interface, the second representing an empty list of Strings, 
and the third a class with fields 'first' of the type String and 'rest' of
the type ILoString.

We know nothing specific about these lists. To be able to discuss them, 
we label them as valid-list and name-list. We can now try to formulate 
the purpose statement --- the question our program should answer:

'Is every element of name-list an element of valid-list.'

It is clear that we need to design a method for the list of names. 
The question is, whether 'this' should be the name-list of the valid-list. 
Looking at the problem statement we see that we are answering a question
about every element of name-list. Therefore, name-list should invoke the
method: we are asking questions about name-list, while the valid-list
is just a piece of information we need to be able to answer the question.

In ProfessoJ we use the names nameList and validList and design the 
following purpose and header:

// is every element of this list an element of the given validList?
boolean validNames(ILoString validList);

We use Scheme notation as a shorthand for describing the data we use
in our examples:

validList:(list "red" "green" "black" "blue" "white")
nameList0: empty
nameList1: (list "red" "black" "green")
nameList2: (list "red" "blue" "yellow" "green")

nameList0.validNames(validList) --> true
nameList1.validNames(validList) --> true
nameList2.validNames(validList) --> false

For the empty case the answer is always true and we are done. For the 
ConsLostring we continue with the template:

// TEMPLATE:
... this.first ...                        -- String
... this.rest ...                         -- ILoString
... this.rest.validNames(validList) ...   -- boolean

and we read aloud (or write down) the purpose statement for the last 
entry in the template:

Is every element of the rest of this list an element of the given validList?

Well, with that taken care of, we only need to find out whether the first
element of this list is an element of the validList. But that itself is a
hard question to answer. Again, it is time to bring in a helper method, but
now, the tables are reversed. The name is represented as a String and the
question whether it is contained in some list should be answered by a method
in the classes that represent the list. So, we have the following purpose 
statement and header:

// does this list contain the given name?
boolean contains(String name)

We leave it to the reader to design this method. Our template now has an
additional entry:

// TEMPLATE:
... this.first ...                        -- String
... this.rest ...                         -- ILoString
... this.rest.validNames(validList) ...   -- boolean

... validList.contains(..String..) ...    -- boolean

Note that the following are also correct entries in the template, but
are meaningless in our context:

... validList.validNames(.. ILoString..) ... -- boolean
... this.rest.contains(..String..) ...       -- boolean

As an exercise, read the purpose statements for each of these template 
entries and explain why it does not help us.

If we substitute 'this.first' for the argument in the last entry in our
template, our problem is solved:

// is every element of this list an element of the given validList?
boolean validNames(ILoString validList){
    return validList.contains(this.first) &&
           this.rest.validNames(validList);
}

Of coourse, we now run the tests. Complete code follows:
/*
             +-----------+                 
             | ILoString |<---------------+
             +-----------+                |
             +-----------+                |
                  / \                     |
                  ---                     |
                   |                      |
        ---------------------             |
        |                   |             |
  +------------+    +----------------+    |
  | MTLoString |    | ConsLoString   |    |
  +------------+    +----------------+    |
  +------------+    | String first   |    |
                    | ILoString rest |----+
                    +----------------+ 

*/

// to represent a list of Strings
interface ILoString {
  // is every element of this list an element of the given validList?
  boolean validNames(ILoString validList);

  // does this list contain the given name?
  boolean contains(String name);
}

// to represent an empty list of Strings
class MTLoString implements ILoString {

  MTLoString() {
  }

  // is every element of this list an element of the given validList?
  boolean validNames(ILoString validList){ return true; }

  // does this list contain the given name?
  boolean contains(String name){ return false; }
}

// to represent a nonempty list of Strings
class ConsLoString implements ILoString {
  String first;
  ILoString rest;

  ConsLoString(String first, ILoString rest) {
    this.first = first;
    this.rest = rest;
  }

  /* TEMPLATE:
  ... this.first ...                        -- String
  ... this.rest ...                         -- ILoString
  ... this.rest.validNames(validList) ...   -- boolean

  ... validList.contains(..String..) ...    -- boolean
  */

  // is every element of this list an element of the given validList?
  boolean validNames(ILoString validList){
    return validList.contains(this.first) &&
           this.rest.validNames(validList);
  }

  // does this list contain the given name?
  boolean contains(String name){
    return this.first.equals(name) || 
           this.rest.contains(name);
  }
}

class Examples {
  Examples() {}

  ILoString empty = new MTLoString();
  ILoString validList = new ConsLoString("red",
                        new ConsLoString("green",
                        new ConsLoString("black",
                        new ConsLoString("blue",
                        new ConsLoString("white", this.empty)))));

  ILoString nameList0 = new MTLoString();
  ILoString nameList1 = new ConsLoString("red",
                        new ConsLoString("black",
                        new ConsLoString("green", this.empty)));

  ILoString nameList2 = new ConsLoString("red",
                        new ConsLoString("blue",
                        new ConsLoString("yellow",
                        new ConsLoString("green", this.empty))));

  // tests for the method validNames
  boolean testValidNames0 = this.nameList0.validNames(this.validList) == true;
  boolean testValidNames1 = this.nameList1.validNames(this.validList) == true;
  boolean testValidNames2 = this.nameList2.validNames(this.validList) == false;

  // tests for the method contains
  boolean testContains0 = this.nameList0.contains("red") == false;
  boolean testContains1 = this.nameList1.contains("black") == true;
  boolean testContains2 = this.nameList1.contains("yellow") == false;
}



