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

Lecture 17: A Road Trip - the code
(See Lecture 16 for text and code combined.)
*/



/*
;                                           
;                                           
;                                           
;   ;    ;;;;                               
;   ;   ;    ;                              
;   ;   ;                                   
;   ;   ;      ;;;    ; ;;  ;;     ;;;      
;   ;    ;;   ;   ;   ;;  ;;  ;   ;   ;     
;   ;      ;      ;   ;   ;   ;  ;    ;     
;   ;       ;  ;;;;   ;   ;   ;  ;;;;;;     
;   ;       ; ;   ;   ;   ;   ;  ;          
;   ;   ;   ; ;   ;   ;   ;   ;   ;         
;   ;    ;;;   ;;;;;  ;   ;   ;    ;;;;     
;                                           
;                                           
;                                           
*/
interface ISame{
  // determine whether this object is the same as the given object
  boolean same(Object obj);
}

/*
;                                                            
;                                                            
;                                                            
;    ;;;;                                                    
;   ;    ;                                                   
;   ;                                                ;       
;   ;       ;;;    ;; ;   ; ;;  ;;     ;;;   ; ;;   ;;;;     
;    ;;    ;   ;  ;  ;;   ;;  ;;  ;   ;   ;  ;;  ;   ;       
;      ;  ;    ; ;    ;   ;   ;   ;  ;    ;  ;   ;   ;       
;       ; ;;;;;; ;    ;   ;   ;   ;  ;;;;;;  ;   ;   ;       
;       ; ;      ;    ;   ;   ;   ;  ;       ;   ;   ;       
;   ;   ;  ;      ;  ;;   ;   ;   ;   ;      ;   ;   ;       
;    ;;;    ;;;;   ;; ;   ;   ;   ;    ;;;;  ;   ;    ;;     
;                     ;                                      
;                ;    ;                                      
;                 ;;;;                                       
*/
// to represent a segment of a road trip
class Segment implements ISame{
  String from;
  String to;
  int miles;
  int gallons;
  int price;

  Segment(String from, String to, int miles, int gallons, int price) {
    this.from = from;
    this.to = to;
    this.miles = miles;
    this.gallons = gallons;
    this.price = price;
  }

  // determine whether this segment is the same as the given object
  boolean same(Object obj){
    return this.from.equals(((Segment)obj).from)
        && this.to.equals(((Segment)obj).to)
        && this.miles == ((Segment)obj).miles
        && this.gallons == ((Segment)obj).gallons
        && this.price == ((Segment)obj).price;
  }

  // produce the city of origin for this segment of the trip
  String makeCity(){
    return this.from;
  }

  // produce the record of gas mileage for this segment of the trip
  MPG makeMPG(){
    return new MPG(this.from, this.to, this.miles/this.gallons);
  }

  // produce the record of the cost of this segment of the trip
  Cost makeCost(){
    return new Cost(this.from, this.to, this.gallons * this.price);
  }

/*
  // ** DRAFT TEMPLATE ** Edit as needed.
  ??? mmm() {
    ... this.from ...
    ... this.to ...
    ... this.miles ...
    ... this.gallons ...
    ... this.price ...
  }
*/
}

/*
;                                     
;                                     
;                                     
;      ;     ;               ;;;;     
;      ;     ;              ;    ;    
;     ; ;    ;              ;         
;     ; ;    ;       ;;;    ;         
;    ;   ;   ;      ;   ;    ;;       
;    ;   ;   ;     ;     ;     ;      
;   ;;;;;;;  ;     ;     ;      ;     
;   ;     ;  ;     ;     ;      ;     
;   ;     ;  ;      ;   ;   ;   ;     
;  ;       ; ;;;;;;  ;;;     ;;;      
;                                     
;                                     
;                                     
*/
// to represent a list of segments of a road trip
abstract class ALoS {

  // produce a list of origins for all segments of this trip
  abstract ALoObj makeCities();

  // produce a list of MPG records for all segments of this trip
  abstract ALoObj makeMPGs();

  // produce a list of cost records for all segments of this trip
  abstract ALoObj makeCosts();

  // produce a list of records for all segments of this trip
 abstract ALoObj makeTripRecord(IObj2Obj transform);

/*
  // ** DRAFT TEMPLATE ** Edit as needed.
  // purpose statement 
  abstract ??? mmm();
*/
}

/*
;                                               
;                                               
;                                               
;   ;       ; ;;;;;;;  ;               ;;;;     
;   ;;     ;;    ;     ;              ;    ;    
;   ;;     ;;    ;     ;              ;         
;   ; ;   ; ;    ;     ;       ;;;    ;         
;   ; ;   ; ;    ;     ;      ;   ;    ;;       
;   ;  ; ;  ;    ;     ;     ;     ;     ;      
;   ;  ; ;  ;    ;     ;     ;     ;      ;     
;   ;   ;   ;    ;     ;     ;     ;      ;     
;   ;   ;   ;    ;     ;      ;   ;   ;   ;     
;   ;       ;    ;     ;;;;;;  ;;;     ;;;      
;                                               
;                                               
;                                               
*/
// to represent an empty list of segments of a road trip
class MTLoS extends ALoS {

  MTLoS() {
  }

  // produce a list of origins for all segments of this trip
  ALoObj makeCities(){ return new MTLoObj(); }

  // produce a list of MPG records for all segments of this trip
  ALoObj makeMPGs(){ return new MTLoObj(); }

  // produce a list of cost records for all segments of this trip
  ALoObj makeCosts(){ return new MTLoObj(); }

  // produce a list of records for all segments of this trip
  ALoObj makeTripRecord(IObj2Obj transform){ return new MTLoObj(); }
/*
  // ** DRAFT TEMPLATE ** Edit as needed.
  ??? mmm() {
  }
*/
}

/*
;                                                            
;                                                            
;                                                            
;     ;;;;                          ;               ;;;;     
;    ;    ;                         ;              ;    ;    
;   ;                               ;              ;         
;   ;         ;;;    ; ;;     ;;;   ;       ;;;    ;         
;   ;        ;   ;   ;;  ;   ;      ;      ;   ;    ;;       
;   ;       ;     ;  ;   ;   ;;     ;     ;     ;     ;      
;   ;       ;     ;  ;   ;    ;;    ;     ;     ;      ;     
;   ;       ;     ;  ;   ;      ;   ;     ;     ;      ;     
;    ;    ;  ;   ;   ;   ;      ;   ;      ;   ;   ;   ;     
;     ;;;;    ;;;    ;   ;   ;;;    ;;;;;;  ;;;     ;;;      
;                                                            
;                                                            
;                                                            
*/
// to represent a nonempty list of segments of a road trip
class ConsLoS extends ALoS {
  Segment first;
  ALoS rest;

  ConsLoS(Segment first, ALoS rest) {
    this.first = first;
    this.rest = rest;
  }

  // produce a list of origins for all segments of this trip
  ALoObj makeCities(){ 
    return new ConsLoObj(this.first.makeCity(), 
                         this.rest.makeCities()); 
  }

  // produce a list of MPG records for all segments of this trip
  ALoObj makeMPGs(){ 
    return new ConsLoObj(this.first.makeMPG(), 
                         this.rest.makeMPGs()); 
  }

  // produce a list of cost records for all segments of this trip
  ALoObj makeCosts(){ 
    return new ConsLoObj(this.first.makeCost(), 
                         this.rest.makeCosts()); 
  }

  // produce a list of records for all segments of this trip
  ALoObj makeTripRecord(IObj2Obj transform){ 
    return new ConsLoObj(transform.makeObject(this.first), 
                         this.rest.makeTripRecord(transform)); 
  }

/*
  // ** DRAFT TEMPLATE ** Edit as needed.
  ??? mmm() {
    ... this.first ...
    ... this.rest.mmm() ...
  }
*/
}

/*
;                                 
;                                 
;                                 
;   ;       ;  ;;;;;    ;;;;      
;   ;;     ;;  ;    ;  ;    ;     
;   ;;     ;;  ;    ; ;           
;   ; ;   ; ;  ;    ; ;           
;   ; ;   ; ;  ;    ; ;           
;   ;  ; ;  ;  ;;;;;  ;           
;   ;  ; ;  ;  ;      ;     ;     
;   ;   ;   ;  ;      ;     ;     
;   ;   ;   ;  ;       ;    ;     
;   ;       ;  ;        ;;;;;     
;                                 
;                                 
;                                 
*/
// to represent the mile per gallons consumption per segment
class MPG implements ISame{
  String from;
  String to;
  int mpg;

  MPG(String from, String to, int mpg) {
    this.from = from;
    this.to = to;
    this.mpg = mpg;
  }

  // determine whether this MPG object is the same as the given object
  boolean same(Object obj){
    return this.from.equals(((MPG)obj).from)
        && this.to.equals(((MPG)obj).to)
        && this.mpg == ((MPG)obj).mpg;
  }

/*
  // ** DRAFT TEMPLATE ** Edit as needed.
  ??? mmm() {
    ... this.from ...
    ... this.to ...
    ... this.mpg ...
  }
*/
}

/*
;                                   
;                                   
;                                   
;     ;;;;                          
;    ;    ;                         
;   ;                       ;       
;   ;         ;;;     ;;;  ;;;;     
;   ;        ;   ;   ;      ;       
;   ;       ;     ;  ;;     ;       
;   ;       ;     ;   ;;    ;       
;   ;       ;     ;     ;   ;       
;    ;    ;  ;   ;      ;   ;       
;     ;;;;    ;;;    ;;;     ;;     
;                                   
;                                   
;                                   
*/
// to represent the cost of travel for one segment of a road trip
class Cost  implements ISame{
  String from;
  String to;
  int cost;

  Cost(String from, String to, int cost) {
    this.from = from;
    this.to = to;
    this.cost = cost;
  }

  // determine whether this MPG object is the same as the given object
  boolean same(Object obj){
    return this.from.equals(((Cost)obj).from)
        && this.to.equals(((Cost)obj).to)
        && this.cost == ((Cost)obj).cost;
  }

  // produce a list of origins for all segments of this trip
  ALoObj makeCities(){ return new MTLoObj(); }

  // produce a list of MPG records for all segments of this trip
  ALoObj makeMPGs(){ return new MTLoObj(); }

  // produce a list of cost records for all segments of this trip
  ALoObj makeCosts(){ return new MTLoObj(); }

/*
  // ** DRAFT TEMPLATE ** Edit as needed.
  ??? mmm() {
    ... this.from ...
    ... this.to ...
    ... this.cost ...
  }
*/
}
/*
;                                                    
;                                                    
;                                                    
;      ;     ;                ;;;;    ;       ;      
;      ;     ;               ;    ;   ;              
;     ; ;    ;              ;      ;  ;              
;     ; ;    ;       ;;;    ;      ;  ; ;;    ;      
;    ;   ;   ;      ;   ;   ;      ;  ;;  ;   ;      
;    ;   ;   ;     ;     ;  ;      ;  ;    ;  ;      
;   ;;;;;;;  ;     ;     ;  ;      ;  ;    ;  ;      
;   ;     ;  ;     ;     ;  ;      ;  ;    ;  ;      
;   ;     ;  ;      ;   ;    ;    ;   ;;  ;   ;      
;  ;       ; ;;;;;;  ;;;      ;;;;    ; ;;    ;      
;                                             ;      
;                                             ;      
;                                           ;;       
*/
/*
            +--------+                
            | ALoObj |<--------------+
            +--------+               |
            +--------+               |
                / \                  |
                ---                  |
                 |                   |
       ------------------            |
       |                |            |
  +---------+    +--------------+    |
  | MTLoObj |    | ConsLoObj    |    |
  +---------+    +--------------+    |
  +---------+    | Object first |    |
                 | ALoObj rest  |-+  |
                 +--------------+ |  |
                                  |  |
                                  +--+

*/

// to represent a list of objects
abstract class ALoObj implements ISame{

  // determine whether this list of objects is the same as the given object
  boolean same(Object obj){
    return this.sameALoObj((ALoObj) obj);
  }

  // is this an empty list of objects
  abstract boolean isEmpty();

  // determine whether this list of objects is the same as
  // the given list of objects
  abstract boolean sameALoObj(ALoObj alist);


/*
  // ** DRAFT TEMPLATE ** Edit as needed.
  // purpose statement 
  abstract ??? mmm();
*/
}

/*
;                                                              
;                                                              
;                                                              
;   ;       ; ;;;;;;;  ;                ;;;;    ;       ;      
;   ;;     ;;    ;     ;               ;    ;   ;              
;   ;;     ;;    ;     ;              ;      ;  ;              
;   ; ;   ; ;    ;     ;       ;;;    ;      ;  ; ;;    ;      
;   ; ;   ; ;    ;     ;      ;   ;   ;      ;  ;;  ;   ;      
;   ;  ; ;  ;    ;     ;     ;     ;  ;      ;  ;    ;  ;      
;   ;  ; ;  ;    ;     ;     ;     ;  ;      ;  ;    ;  ;      
;   ;   ;   ;    ;     ;     ;     ;  ;      ;  ;    ;  ;      
;   ;   ;   ;    ;     ;      ;   ;    ;    ;   ;;  ;   ;      
;   ;       ;    ;     ;;;;;;  ;;;      ;;;;    ; ;;    ;      
;                                                       ;      
;                                                       ;      
;                                                     ;;       
*/
// to represent an empty list of objects
class MTLoObj extends ALoObj {

  MTLoObj() {
  }

  boolean isEmpty(){
    return true;
  }

  boolean sameALoObj(ALoObj alist){
    return alist.isEmpty();
  }


/* TEMPLATE ** Edit as needed.
  ??? mmm() {
  }
*/
}


/*
;                                                                           
;                                                                           
;                                                                           
;     ;;;;                          ;                ;;;;    ;       ;      
;    ;    ;                         ;               ;    ;   ;              
;   ;                               ;              ;      ;  ;              
;   ;         ;;;    ; ;;     ;;;   ;       ;;;    ;      ;  ; ;;    ;      
;   ;        ;   ;   ;;  ;   ;      ;      ;   ;   ;      ;  ;;  ;   ;      
;   ;       ;     ;  ;   ;   ;;     ;     ;     ;  ;      ;  ;    ;  ;      
;   ;       ;     ;  ;   ;    ;;    ;     ;     ;  ;      ;  ;    ;  ;      
;   ;       ;     ;  ;   ;      ;   ;     ;     ;  ;      ;  ;    ;  ;      
;    ;    ;  ;   ;   ;   ;      ;   ;      ;   ;    ;    ;   ;;  ;   ;      
;     ;;;;    ;;;    ;   ;   ;;;    ;;;;;;  ;;;      ;;;;    ; ;;    ;      
;                                                                    ;      
;                                                                    ;      
;                                                                  ;;       
*/
// to represent a nonempty list of objects
class ConsLoObj extends ALoObj {
  Object first;
  ALoObj rest;

  ConsLoObj(Object first, ALoObj rest) {
    this.first = first;
    this.rest = rest;
  }

  boolean isEmpty(){
    return false;
  }

  boolean sameALoObj(ALoObj alist){
    if (alist.isEmpty())
      return false;
    else 
      return ((ISame)this.first).same(((ConsLoObj)alist).first)
          && this.rest.sameALoObj(((ConsLoObj)alist).rest);
  }

/*
  // ** DRAFT TEMPLATE ** Edit as needed.
  ??? mmm() {
    ... this.first ...
    ... this.rest.mmm() ...
  }
*/
}

/*
;                                                              
;                                                              
;                                                              
;   ;     ;;;;    ;       ;    ;;;;     ;;;;    ;       ;      
;   ;    ;    ;   ;           ;    ;   ;    ;   ;              
;   ;   ;      ;  ;                ;  ;      ;  ;              
;   ;   ;      ;  ; ;;    ;        ;  ;      ;  ; ;;    ;      
;   ;   ;      ;  ;;  ;   ;       ;   ;      ;  ;;  ;   ;      
;   ;   ;      ;  ;    ;  ;      ;    ;      ;  ;    ;  ;      
;   ;   ;      ;  ;    ;  ;     ;     ;      ;  ;    ;  ;      
;   ;   ;      ;  ;    ;  ;    ;      ;      ;  ;    ;  ;      
;   ;    ;    ;   ;;  ;   ;   ;        ;    ;   ;;  ;   ;      
;   ;     ;;;;    ; ;;    ;   ;;;;;;    ;;;;    ; ;;    ;      
;                         ;                             ;      
;                         ;                             ;      
;                       ;;                            ;;       
*/
interface IObj2Obj{
  // produce an object from the given object
  Object makeObject(Object obj);
}

/*
;                                                                
;                                                                
;                                                                
;   ;       ;         ;                ;;;;   ;                  
;   ;;     ;;         ;               ;    ;                     
;   ;;     ;;         ;              ;            ;              
;   ; ;   ; ;  ;;;    ;   ;    ;;;   ;        ;  ;;;; ;     ;    
;   ; ;   ; ; ;   ;   ;  ;    ;   ;  ;        ;   ;   ;     ;    
;   ;  ; ;  ;     ;   ; ;    ;    ;  ;        ;   ;    ;   ;     
;   ;  ; ;  ;  ;;;;   ;;;    ;;;;;;  ;        ;   ;    ;   ;     
;   ;   ;   ; ;   ;   ;  ;   ;       ;        ;   ;     ; ;      
;   ;   ;   ; ;   ;   ;   ;   ;       ;    ;  ;   ;     ; ;      
;   ;       ;  ;;;;;  ;    ;   ;;;;    ;;;;   ;    ;;    ;       
;                                                        ;       
;                                                        ;       
;                                                       ;        
*/
// to produce the from city string (wrapper) from the given segment
class MakeCity implements IObj2Obj{
  Object makeObject(Object obj){
    return new StringWrapper(((Segment)obj).from);
  }
}

/*
;                                                                  
;                                                                  
;                                                                  
;   ;       ;         ;              ;       ;  ;;;;;    ;;;;      
;   ;;     ;;         ;              ;;     ;;  ;    ;  ;    ;     
;   ;;     ;;         ;              ;;     ;;  ;    ; ;           
;   ; ;   ; ;  ;;;    ;   ;    ;;;   ; ;   ; ;  ;    ; ;           
;   ; ;   ; ; ;   ;   ;  ;    ;   ;  ; ;   ; ;  ;    ; ;           
;   ;  ; ;  ;     ;   ; ;    ;    ;  ;  ; ;  ;  ;;;;;  ;           
;   ;  ; ;  ;  ;;;;   ;;;    ;;;;;;  ;  ; ;  ;  ;      ;     ;     
;   ;   ;   ; ;   ;   ;  ;   ;       ;   ;   ;  ;      ;     ;     
;   ;   ;   ; ;   ;   ;   ;   ;      ;   ;   ;  ;       ;    ;     
;   ;       ;  ;;;;;  ;    ;   ;;;;  ;       ;  ;        ;;;;;     
;                                                                  
;                                                                  
;                                                                  
*/
// to produce the MPG record from the given segment
class MakeMPG implements IObj2Obj{
  Object makeObject(Object obj){
    return new MPG(((Segment)obj).from, 
                   ((Segment)obj).to,
                   ((Segment)obj).miles / ((Segment)obj).gallons);
  }
}

/*
;                                                                    
;                                                                    
;                                                                    
;   ;       ;         ;                ;;;;                          
;   ;;     ;;         ;               ;    ;                         
;   ;;     ;;         ;              ;                       ;       
;   ; ;   ; ;  ;;;    ;   ;    ;;;   ;         ;;;     ;;;  ;;;;     
;   ; ;   ; ; ;   ;   ;  ;    ;   ;  ;        ;   ;   ;      ;       
;   ;  ; ;  ;     ;   ; ;    ;    ;  ;       ;     ;  ;;     ;       
;   ;  ; ;  ;  ;;;;   ;;;    ;;;;;;  ;       ;     ;   ;;    ;       
;   ;   ;   ; ;   ;   ;  ;   ;       ;       ;     ;     ;   ;       
;   ;   ;   ; ;   ;   ;   ;   ;       ;    ;  ;   ;      ;   ;       
;   ;       ;  ;;;;;  ;    ;   ;;;;    ;;;;    ;;;    ;;;     ;;     
;                                                                    
;                                                                    
;                                                                    
*/
// to produce the Cost record from the given segment
class MakeCost implements IObj2Obj{
  Object makeObject(Object obj){
    return new Cost(((Segment)obj).from, 
                   ((Segment)obj).to,
                   ((Segment)obj).gallons * ((Segment)obj).price);
  }
}

/*
;                                                                                              
;                                                                                              
;                                                                                              
;    ;;;;            ;                  ;    ;    ;                                            
;   ;    ;                              ;    ;    ;                                            
;   ;      ;                            ;   ; ;   ;                                            
;   ;     ;;;;  ; ;  ;   ; ;;     ;; ;   ;  ; ;  ;  ; ;  ;;;    ; ;;    ; ;;     ;;;   ; ;     
;    ;;    ;    ;;   ;   ;;  ;   ;  ;;   ;  ; ;  ;  ;;  ;   ;   ;;  ;   ;;  ;   ;   ;  ;;      
;      ;   ;    ;    ;   ;   ;  ;    ;   ; ;   ; ;  ;       ;   ;    ;  ;    ; ;    ;  ;       
;       ;  ;    ;    ;   ;   ;  ;    ;   ; ;   ; ;  ;    ;;;;   ;    ;  ;    ; ;;;;;;  ;       
;       ;  ;    ;    ;   ;   ;  ;    ;   ; ;   ; ;  ;   ;   ;   ;    ;  ;    ; ;       ;       
;   ;   ;  ;    ;    ;   ;   ;   ;  ;;    ;     ;   ;   ;   ;   ;;  ;   ;;  ;   ;      ;       
;    ;;;    ;;  ;    ;   ;   ;    ;; ;    ;     ;   ;    ;;;;;  ; ;;    ; ;;     ;;;;  ;       
;                                    ;                          ;       ;                      
;                               ;    ;                          ;       ;                      
;                                ;;;;                           ;       ;                      
*/
// to allow String object comparison with 'same' method
class StringWrapper implements ISame{
  String s;
 
  StringWrapper(String s){
    this.s = s;
  }

  boolean same(Object obj){
    return s.equals(((StringWrapper)obj).s);
  } 
}
/*
;                                                                  
;                                                                  
;                                                                  
;   ;;;;;;                                    ;                    
;   ;                                         ;                    
;   ;                                         ;                    
;   ;     ;     ;  ;;;    ; ;;  ;;    ; ;;    ;    ;;;    ;;;      
;   ;;;;;  ;   ;  ;   ;   ;;  ;;  ;   ;;  ;   ;   ;   ;  ;         
;   ;       ; ;       ;   ;   ;   ;   ;    ;  ;  ;    ;  ;;        
;   ;        ;     ;;;;   ;   ;   ;   ;    ;  ;  ;;;;;;   ;;       
;   ;       ; ;   ;   ;   ;   ;   ;   ;    ;  ;  ;          ;      
;   ;      ;   ;  ;   ;   ;   ;   ;   ;;  ;   ;   ;         ;      
;   ;;;;;;;     ;  ;;;;;  ;   ;   ;   ; ;;    ;    ;;;;  ;;;       
;                                     ;                            
;                                     ;                            
;                                     ;                            
*/
class Examples{
  Examples() {}

  Segment b2nyc  = new Segment("Boston", "NYC", 200, 10, 210);
  Segment nyc2ph = new Segment("NYC", "Philly", 180, 9, 220);
  Segment ph2dc  = new Segment("Philly", "DC", 120, 12, 200);
  Segment dc2nor = new Segment("DC", "Norfolk", 150, 10, 200);

  ALoS mtlist = new MTLoS();

  ALoS mytrip = new ConsLoS(b2nyc, 
                    new ConsLoS(nyc2ph, 
                      new ConsLoS(ph2dc, 
                        new ConsLoS(dc2nor, 
                          mtlist))));


  // testing the method same in the class segment
  boolean testSameSegment1 = b2nyc.same(ph2dc) == false;
  boolean testSameSegment2 = ph2dc.same(
                             new Segment("Philly", "DC", 120, 12, 200)) == true;

  MPG b2nycmpg  = new MPG("Boston", "NYC", 200/10);
  MPG nyc2phmpg = new MPG("NYC", "Philly", 180/9);
  MPG ph2dcmpg  = new MPG("Philly", "DC", 120/12);
  MPG dc2normpg = new MPG("DC", "Norfolk", 150/10);

  Cost b2nycCost  = new Cost("Boston", "NYC", 10 * 210);
  Cost nyc2phCost = new Cost("NYC", "Philly", 9 * 220);
  Cost ph2dcCost  = new Cost("Philly", "DC", 12 * 200);
  Cost dc2norCost = new Cost("DC", "Norfolk", 10 * 200);

  boolean testMakeCity1 = b2nyc.makeCity().equals("Boston");
  boolean testMakeCity2 = nyc2ph.makeCity().equals("NYC");

  boolean testMakeMPG1 = b2nyc.makeMPG().same(b2nycmpg);
  boolean testMakeMPG2 = ph2dc.makeMPG().same(ph2dcmpg);

  boolean testMakeCost1 = b2nyc.makeCost().same(b2nycCost);
  boolean testMakeCost2 = ph2dc.makeCost().same(ph2dcCost);

  ALoObj mtloobj = new MTLoObj();

/* the following tests cannot be easily performed, because
   we cannot compare two String-s using the 'same' method
   that works for all classes we defined. We could instead
   define a class StringWrapper that contains one String field
   and implements ISame and use that as the target class for
   the makeCity method in the class Segment.

  boolean testMakeCities1 = mtlist.makeCities().same(mtloobj);
  boolean testMakeCities2 = mytrip.makeCities().same(
                               new ConsLoObj("Boston", 
                                 new ConsLoObj("NYC", 
                                   new ConsLoObj("Philly", 
                                     new ConsLoObj("DC", 
                                       mtloobj)))));
*/
  boolean testMakeMPGs1 = mtlist.makeMPGs().same(mtloobj);
  boolean testMakeMPGs2 = mytrip.makeMPGs().same(
                               new ConsLoObj(b2nycmpg, 
                                 new ConsLoObj(nyc2phmpg, 
                                   new ConsLoObj(ph2dcmpg, 
                                     new ConsLoObj(dc2normpg, 
                                       mtloobj)))));

  boolean testMakeCosts1 = mtlist.makeCosts().same(mtloobj);
  boolean testMakeCosts2 = mytrip.makeCosts().same(
                               new ConsLoObj(b2nycCost, 
                                 new ConsLoObj(nyc2phCost, 
                                   new ConsLoObj(ph2dcCost, 
                                     new ConsLoObj(dc2norCost, 
                                       mtloobj)))));

  // test the final abstraction through the method makeTripRecord
  boolean testMakeRecordCities1 = mtlist.makeTripRecord(new MakeCity()).same(mtloobj);
  boolean testMakeRecordCities2 = mytrip.makeTripRecord(new MakeCity()).same(
                               new ConsLoObj(new StringWrapper("Boston"), 
                                 new ConsLoObj(new StringWrapper("NYC"), 
                                   new ConsLoObj(new StringWrapper("Philly"), 
                                     new ConsLoObj(new StringWrapper("DC"), 
                                       mtloobj)))));

  boolean testMakeRecordMPGs1 = mtlist.makeTripRecord(new MakeMPG()).same(mtloobj);

  boolean testMakeRecordMPGs2 = mytrip.makeTripRecord(new MakeMPG()).same(
                               new ConsLoObj(b2nycmpg, 
                                 new ConsLoObj(nyc2phmpg, 
                                   new ConsLoObj(ph2dcmpg, 
                                     new ConsLoObj(dc2normpg, 
                                       mtloobj)))));

  boolean testMakeRecordCosts1 = mtlist.makeTripRecord(new MakeCost()).same(mtloobj);
  boolean testMakeRecordCosts2 = mytrip.makeTripRecord(new MakeCost()).same(
                               new ConsLoObj(b2nycCost, 
                                 new ConsLoObj(nyc2phCost, 
                                   new ConsLoObj(ph2dcCost, 
                                     new ConsLoObj(dc2norCost, 
                                       mtloobj)))));

}

