/////////////////////////////////////////////////////////////
// File: assignment6.java

/*
;                                             
;                                             
;                                             
;   ;;;;;  ;   ;                              
;   ;          ;                              
;   ;          ;   ;                          
;   ;      ;   ;  ;;;;   ;;;   ; ;   ;;;      
;   ;;;;   ;   ;   ;    ;   ;  ;;   ;         
;   ;      ;   ;   ;   ;    ;  ;    ;;        
;   ;      ;   ;   ;   ;;;;;;  ;     ;;       
;   ;      ;   ;   ;   ;       ;       ;      
;   ;      ;   ;   ;    ;      ;       ;      
;   ;      ;   ;    ;;   ;;;;  ;    ;;;       
;                                             
;                                             
;                                             
*/
interface IFilter{
  // method that selects objects with some property
  boolean select();
}

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

interface IPredicate{
  // method that selects objects with some property
  boolean select2(Object obj);
}

class Probation implements IPredicate{
  boolean select2(Object obj){
    return ((Student) obj).gpa < 2.0;
  }
}

/*
;                                                
;                                                
;                                                
;   ;;;;;                                        
;   ;    ;                                       
;   ;    ;                                       
;   ;    ;  ;;;   ; ;   ;;;    ;;;    ; ;;       
;   ;    ; ;   ;  ;;   ;      ;   ;   ;;  ;      
;   ;;;;; ;    ;  ;    ;;    ;     ;  ;   ;      
;   ;     ;;;;;;  ;     ;;   ;     ;  ;   ;      
;   ;     ;       ;       ;  ;     ;  ;   ;      
;   ;      ;      ;       ;   ;   ;   ;   ;      
;   ;       ;;;;  ;    ;;;     ;;;    ;   ;      
;                                                
;                                                
;                                                
*/
class Person implements ISame, IFilter{
  int id;
  String name;

  Person(int id, String name) {
    this.id = id;
    this.name = name;
  }

  boolean same(Object obj){
    return    (this.name.equals( ((Person) obj).name))  
           && (this.id == ((Person) obj).id);
  }

  // select persons with names starting with letters up to H'
  boolean select(){
    return this.name.compareTo("H") < 0;
  }
}

/*
;                                                      
;                                                      
;                                                      
;    ;;;;                   ;                          
;   ;    ;                  ;                          
;   ;      ;                ;                  ;       
;   ;     ;;;;  ;   ;    ;; ;    ;;;   ; ;;   ;;;;     
;    ;;    ;    ;   ;   ;  ;;   ;   ;  ;;  ;   ;       
;      ;   ;    ;   ;  ;    ;  ;    ;  ;   ;   ;       
;       ;  ;    ;   ;  ;    ;  ;;;;;;  ;   ;   ;       
;       ;  ;    ;   ;  ;    ;  ;       ;   ;   ;       
;   ;   ;  ;    ;  ;;   ;  ;;   ;      ;   ;   ;       
;    ;;;    ;;   ;; ;    ;; ;    ;;;;  ;   ;    ;;     
;                                                      
;                                                      
;                                                      
*/
class Student extends Person implements ISame, IFilter{
  int credits;
  double gpa;

  Student(int id, String name, int credits, double gpa){
    super(id, name);
    this.credits = credits;
    this.gpa = gpa;
  }

  boolean same(Object obj) {
    return    (this.name.equals(  ((Student) obj).name ))
           && (this.id == (  ((Student) obj).id ));
   }

  // select students with gpa below 2.0
  boolean select(){
    return this.gpa < 2.0;
  }
}

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

  // count the number of items in this list
  abstract int count();

  // determine whether this list contains the given object
  abstract boolean contains(Object obj);

  // determine whether there is a 'selected' object in this list
  abstract boolean orMap();

  // determine whether there is a 'selected' object in this list
  abstract boolean orMap2(IPredicate predicate);

  // is this list same as the given object
  boolean same(Object obj){
    return this.sameList((ALoObj) obj);
  }

  // determine whether this is an empty list
  abstract boolean emptyList();

  // determine whether this list is the same as other list
  abstract boolean sameList(ALoObj other);
}

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

  MTLoObj(){ }

  int count(){ return 0; }

  boolean contains(Object obj){ return false; }

  boolean orMap(){ return false; }

  boolean orMap2(IPredicate predicate){ return false; }

  boolean emptyList(){
    return true;
  }

  boolean sameList(ALoObj other){
    return other.emptyList();
  }

}

/*
;                                                                           
;                                                                           
;                                                                           
;     ;;;;                          ;                ;;;;    ;       ;      
;    ;    ;                         ;               ;    ;   ;              
;   ;                               ;              ;      ;  ;              
;   ;         ;;;    ; ;;     ;;;   ;       ;;;    ;      ;  ; ;;    ;      
;   ;        ;   ;   ;;  ;   ;      ;      ;   ;   ;      ;  ;;  ;   ;      
;   ;       ;     ;  ;   ;   ;;     ;     ;     ;  ;      ;  ;    ;  ;      
;   ;       ;     ;  ;   ;    ;;    ;     ;     ;  ;      ;  ;    ;  ;      
;   ;       ;     ;  ;   ;      ;   ;     ;     ;  ;      ;  ;    ;  ;      
;    ;    ;  ;   ;   ;   ;      ;   ;      ;   ;    ;    ;   ;;  ;   ;      
;     ;;;;    ;;;    ;   ;   ;;;    ;;;;;;  ;;;      ;;;;    ; ;;    ;      
;                                                                    ;      
;                                                                    ;      
;                                                                  ;;       
*/
// 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;
  }

/*
...this.first...
...this.rest...
...this.count()...
...this.contains(Object obj)...
...this.rest.orMap(IPredicate predicate)...
*/

  int count() { 
    return 1 + this.rest.count();
  }

  boolean contains(Object obj){
    return    (this.first.equals(obj))
           || (this.rest.contains(obj));
  }

  boolean orMap(){
    return    ( ((IFilter)(this.first)).select() )
           || (this.rest.orMap());
  }

  boolean orMap2(IPredicate predicate){
    return    predicate.select2(this.first)
           || (this.rest.orMap2(predicate));
  }

  boolean emptyList(){
    return false;
  }

  boolean sameList(ALoObj other){
    if (other.emptyList())
      return false;
    else 
      return ((ISame)this.first).same(((ConsLoObj)other).first)
          && this.rest.sameList(((ConsLoObj)other).rest);
  }

}

/*
;                                                                  
;                                                                  
;                                                                  
;   ;;;;;;                                    ;                    
;   ;                                         ;                    
;   ;                                         ;                    
;   ;     ;     ;  ;;;    ; ;;  ;;    ; ;;    ;    ;;;    ;;;      
;   ;;;;;  ;   ;  ;   ;   ;;  ;;  ;   ;;  ;   ;   ;   ;  ;         
;   ;       ; ;       ;   ;   ;   ;   ;    ;  ;  ;    ;  ;;        
;   ;        ;     ;;;;   ;   ;   ;   ;    ;  ;  ;;;;;;   ;;       
;   ;       ; ;   ;   ;   ;   ;   ;   ;    ;  ;  ;          ;      
;   ;      ;   ;  ;   ;   ;   ;   ;   ;;  ;   ;   ;         ;      
;   ;;;;;;;     ;  ;;;;;  ;   ;   ;   ; ;;    ;    ;;;;  ;;;       
;                                     ;                            
;                                     ;                            
;                                     ;                            
*/
// Examples of data and tests of methods
class Examples{
  Examples() {}


}


