// Lab 6: Object polymorphism, Interfaces, and Function Objects

/*
In this lab you will learn to build a list of Objects - abstracting from
the lists of various kinds of data we have seen in the past.
You will also learn to abstract over the behavior of classes through 
interfaces, and to construct 'function objects' - as instances of classes
that represent only functional behavior.

The goal of our program today is to keep a record of a cross country 
trip in a car. At each point when we refuel, we record the starting point
of this segment, the destination where we refueled, the miles traveled,
the amount of gasoline purchased (in gallons) and the price of the fuel 
per gallon, given in whole cents. We also want to keep track of the 
souvenirs we buy on the trip. We record the name of the souvenir, how
many souvenirs we bought, and the price per item.

The following class represents one segment of the trip:

/*
+--------------------+
| Segment            |
+--------------------+
| String origin      |
| String destination |
| int miles          |
| int gallons        |
| int price          |
+--------------------+


;                                                            
;                                                            
;                                                            
;    ;;;;                                                    
;   ;    ;                                                   
;   ;                                                ;       
;   ;       ;;;    ;; ;   ; ;;  ;;     ;;;   ; ;;   ;;;;     
;    ;;    ;   ;  ;  ;;   ;;  ;;  ;   ;   ;  ;;  ;   ;       
;      ;  ;    ; ;    ;   ;   ;   ;  ;    ;  ;   ;   ;       
;       ; ;;;;;; ;    ;   ;   ;   ;  ;;;;;;  ;   ;   ;       
;       ; ;      ;    ;   ;   ;   ;  ;       ;   ;   ;       
;   ;   ;  ;      ;  ;;   ;   ;   ;   ;      ;   ;   ;       
;    ;;;    ;;;;   ;; ;   ;   ;   ;    ;;;;  ;   ;    ;;     
;                     ;                                      
;                ;    ;                                      
;                 ;;;;                                       
*/

// to represent one segment of a road trip
class Segment {
  String origin;
  String destination;
  int miles;
  int gallons;
  int price;

  Segment(String origin, String destination, int miles, int gallons, int price) {
    this.origin = origin;
    this.destination = destination;
    this.miles = miles;
    this.gallons = gallons;
    this.price = price;
  }

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

////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
/*
Make examples of trip segments in the class Examples.

Next, design the classes to represent a list of Objects, 
and make examples of some parts of the cross country trip, 
as data in these classes.

*/
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
/*
;                                                    
;                                                    
;                                                    
;      ;     ;                ;;;;    ;       ;      
;      ;     ;               ;    ;   ;              
;     ; ;    ;              ;      ;  ;              
;     ; ;    ;       ;;;    ;      ;  ; ;;    ;      
;    ;   ;   ;      ;   ;   ;      ;  ;;  ;   ;      
;    ;   ;   ;     ;     ;  ;      ;  ;    ;  ;      
;   ;;;;;;;  ;     ;     ;  ;      ;  ;    ;  ;      
;   ;     ;  ;     ;     ;  ;      ;  ;    ;  ;      
;   ;     ;  ;      ;   ;    ;    ;   ;;  ;   ;      
;  ;       ; ;;;;;;  ;;;      ;;;;    ; ;;    ;      
;                                             ;      
;                                             ;      
;                                           ;;       
*/



////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
/*
To make it possible to compare the results, we need to include 
the method 'same' in all of these classes. We make the function header 
'universal' so that one header works for each of these classes and 
define an interface that represents this behavior:

*/

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

/* 
Add the method 'same' to the class Segment and indicate that 
it implements the ISame interface. To extract the fields from the given 
Object obj, you will need to cast obj to the type Segment. 
For example, you may write:

   this.price == ((Segment)obj).price

as a part of your condition. Make sure you follow the design recipe. 
You may assume  that the given object will be of the type Segment.


////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
Now design the class to represent the souvenir purchases, and make sure 
it too implements the ISame interface. Record the price per item in whole 
cents as well as the number of items you have purchased.
Make examples of lists of souvenirs.


////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////

Now design the method 'same' for the classes that represent 
a list of objects. We already know how to do this, if the 
method argument is of the type ALoObj. But we can make this 
happen as follows. In the class ALoObj we definethe method:

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

and add to our wish list the method 

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

We can now design this method in the classes the represent 
a list of objects. Do it now.



////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////

Next design the method totalMiles that computes the total number of miles
traveled on a trip.

Then design the method totalCost that compute how much money we spent 
on souvenirs during this trip.


////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////

Observe the similarites between these two sets of methods. Define
an interface IValue to represent a method that produces an integer
that represents the value of this object. 


////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////

Now modify both classes to implement this interface, combine the 
two methods into one method totalValue using the fact that both
implement the IValue interface. Test your original examples, to 
make sure they still work.


////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////

Now compute the total number of gallons of gas consumed during
the trip. Notice, that even though we are repeating the same 
computation, we cannot re-use the IValue interface.

Instead, we define a new interface:
*/

/*
;                                                         
;                                                         
;                                                         
;   ;     ;;;;    ;       ;    ;;;;   ;                   
;   ;    ;    ;   ;           ;    ;  ;                   
;   ;   ;      ;  ;                ;  ;           ;       
;   ;   ;      ;  ; ;;    ;        ;  ;   ; ;;   ;;;;     
;   ;   ;      ;  ;;  ;   ;       ;   ;   ;;  ;   ;       
;   ;   ;      ;  ;    ;  ;      ;    ;   ;   ;   ;       
;   ;   ;      ;  ;    ;  ;     ;     ;   ;   ;   ;       
;   ;   ;      ;  ;    ;  ;    ;      ;   ;   ;   ;       
;   ;    ;    ;   ;;  ;   ;   ;       ;   ;   ;   ;       
;   ;     ;;;;    ; ;;    ;   ;;;;;;  ;   ;   ;    ;;     
;                         ;                               
;                         ;                               
;                       ;;                                
*/
interface IObj2Int{
  // produce an integer that represents the value of the given object  
  int objValue(Object obj);
}

/*
Any class that implements this interface will have the method that
computes the value of a given object. This can be any object, not
just an instance of the class wehre this method is defined. Indeed, we 
can define:
*/

/*
;                                                                      
;                                                                      
;                                                                      
;     ;;;;                      ;     ;          ;                     
;    ;    ;                     ;     ;          ;                     
;   ;                       ;    ;   ;           ;                     
;   ;         ;;;     ;;;  ;;;;  ;   ;    ;;;    ;   ;   ;    ;;;      
;   ;        ;   ;   ;      ;    ;   ;   ;   ;   ;   ;   ;   ;   ;     
;   ;       ;     ;  ;;     ;     ; ;        ;   ;   ;   ;  ;    ;     
;   ;       ;     ;   ;;    ;     ; ;     ;;;;   ;   ;   ;  ;;;;;;     
;   ;       ;     ;     ;   ;     ; ;    ;   ;   ;   ;   ;  ;          
;    ;    ;  ;   ;      ;   ;      ;     ;   ;   ;   ;  ;;   ;         
;     ;;;;    ;;;    ;;;     ;;    ;      ;;;;;  ;    ;; ;    ;;;;     
;                                                                      
;                                                                      
;                                                                      
*/
// class to represent a method that produces the cost of a trip segment
class CostValue implements IObj2Int{
  int objValue(Object obj){
    return ((Segment)obj).gallons * ((Segment)obj).price;
  }
}

/*
The class costValue has no fields and contains just one method needed 
to implement the desired interface. So, we can compute the cost of the
following trip segment:

Segment b2nyc = new Segment("Boston", "NYC", 200, 10, 210);

as follows:

CostValue cv = new CostValue();
int cost = cv.objValue(b2nyc);
boolean testCost cost == 2100;

Try this in the Examples class. Make additional examples of trip segments
and the cost computation that uses the instance of the CostValue class.

Do the same for the MilesValue class defined below::
*/
/*
;                                                                          
;                                                                          
;                                                                          
;   ;       ;  ;   ;                ;     ;          ;                     
;   ;;     ;;      ;                ;     ;          ;                     
;   ;;     ;;      ;                 ;   ;           ;                     
;   ; ;   ; ;  ;   ;    ;;;    ;;;   ;   ;    ;;;    ;   ;   ;    ;;;      
;   ; ;   ; ;  ;   ;   ;   ;  ;      ;   ;   ;   ;   ;   ;   ;   ;   ;     
;   ;  ; ;  ;  ;   ;  ;    ;  ;;      ; ;        ;   ;   ;   ;  ;    ;     
;   ;  ; ;  ;  ;   ;  ;;;;;;   ;;     ; ;     ;;;;   ;   ;   ;  ;;;;;;     
;   ;   ;   ;  ;   ;  ;          ;    ; ;    ;   ;   ;   ;   ;  ;          
;   ;   ;   ;  ;   ;   ;         ;     ;     ;   ;   ;   ;  ;;   ;         
;   ;       ;  ;   ;    ;;;;  ;;;      ;      ;;;;;  ;    ;; ;    ;;;;     
;                                                                          
;                                                                          
;                                                                          
*/
class MilesValue implements IObj2Int{
  int objValue(Object obj){
    return ((Segment)obj).miles;
  }
}

/*
Finally, abstract over the two methods in the classes that represent the list
of objects, so that the new method 'totalValue2' consumes an argument which
is an instance of a class that implements the IObj2Int interface and uses
it's objValue method to compute the value of the .first item.

------ the code you need ------------------------------------------

in the class ALoObj:

  // compute the total value of objects in this list
  abstract int totalValue2(IObj2Int value);


in the class MTLoObj:

  int totalValue2(IObj2Int value){
    return 0;
  }

  
in the class ConsLoObj:

  int totalValue2(IObj2Int value){
    return value.objValue(this.first)
         + this.rest.totalValue2(value);
  }

------------------------------------------------------

Next, make examples of computing the total cost of trip, using your earlier
sample trips, and using the CostValue instance defined above.

Now copy your class that represents souvenirs from Part one, and compute 
the total cost of souvenirs. You will first have to define a class that 
contains the objValue method that computes the cost of one souvenir 
purchase.

Can you use this technique to count the number of different souvenir purchases,
or the total number of souvenir items?
*/


/*



*/
/*
;                                                                  
;                                                                  
;                                                                  
;   ;;;;;;                                    ;                    
;   ;                                         ;                    
;   ;                                         ;                    
;   ;     ;     ;  ;;;    ; ;;  ;;    ; ;;    ;    ;;;    ;;;      
;   ;;;;;  ;   ;  ;   ;   ;;  ;;  ;   ;;  ;   ;   ;   ;  ;         
;   ;       ; ;       ;   ;   ;   ;   ;    ;  ;  ;    ;  ;;        
;   ;        ;     ;;;;   ;   ;   ;   ;    ;  ;  ;;;;;;   ;;       
;   ;       ; ;   ;   ;   ;   ;   ;   ;    ;  ;  ;          ;      
;   ;      ;   ;  ;   ;   ;   ;   ;   ;;  ;   ;   ;         ;      
;   ;;;;;;;     ;  ;;;;;  ;   ;   ;   ; ;;    ;    ;;;;  ;;;       
;                                     ;                            
;                                     ;                            
;                                     ;                            
*/
class Examples{
  Examples() {}




}

