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

Lecture 12: Mirror, mirror on the wall... 
         or Java classes for Java classes 
*/



/*
    +----------+    
    | ALibItem |    
    +----------+    
    +----------+    
        / \         
        ---         
         |          
  +--------------+  
  | Book         |  
  +--------------+  
  | String title |  
  | int year     |  
  +--------------+  
*/

// to represent a library item
abstract class ALibItem {
}

// to represent a book
class Book extends ALibItem {
  String title;
  int year;

  Book(String title, int year) {
    this.title = title;
    this.year = year;
  }

  // determine whether this book was published before the given year
  boolean before(int year){
    return this.year < year;
  }
}

class Examples{
  Examples() {}

  Book b1 = new Book("HtDP", 2001);
  Book b2 = new Book("LPP", 1942);

  boolean testBefore1 = b1.before(1950) == false;
  boolean testBefore2 = b2.before(1950) == true;
 
}


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

// to represent the body of a method
class Body {
  String body;

  Body(String body) {
    this.body = body;
  }
}

/*
;                                                          
;                                                          
;                                                          
;   ;;;;;                                                  
;   ;    ;                                                 
;   ;    ;                                                 
;   ;    ; ; ;   ;;;     ;; ;   ; ;  ;;;    ; ;;  ;;       
;   ;    ; ;;   ;   ;   ;  ;;   ;;  ;   ;   ;;  ;;  ;      
;   ;;;;;  ;   ;     ; ;    ;   ;       ;   ;   ;   ;      
;   ;      ;   ;     ; ;    ;   ;    ;;;;   ;   ;   ;      
;   ;      ;   ;     ; ;    ;   ;   ;   ;   ;   ;   ;      
;   ;      ;    ;   ;   ;  ;;   ;   ;   ;   ;   ;   ;      
;   ;      ;     ;;;     ;; ;   ;    ;;;;;  ;   ;   ;      
;                           ;                              
;                      ;    ;                              
;                       ;;;;                               
*/
// to represent a list of class definitions
abstract class ALoClassDefs {
}

// to represent an empty list of class definitions
class MTLoClassDefs extends ALoClassDefs {

  MTLoClassDefs() {
  }
}

// to represent an nonempty list of class definitions
class ConsLoClassDefs extends ALoClassDefs {
  ClassDef first;
  ALoClassDefs rest;

  ConsLoClassDefs(ClassDef first, ALoClassDefs rest) {
    this.first = first;
    this.rest = rest;
  }
}

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

// to represent any class definition
abstract class AClassDef {
}

// to represent a dummy class definition
class DummyClassDef extends AClassDef {
  String name;

  DummyClassDef(String name) {
    this.name = name;
  }
}

// to represent a concrete class definition
class ClassDef extends AClassDef{
  String name;
  AClassDef superclass;
  ALoFieldDefs fields;
  ALoMethodDefs methods;

  ClassDef(String name, AClassDef superclass, ALoFieldDefs fields, ALoMethodDefs methods) {
    this.name = name;
    this.superclass = superclass;
    this.fields = fields;
    this.methods = methods;
  }
}

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


// to represent a list of field definitions
abstract class ALoFieldDefs {
}

// to represent an empty list of field definitions
class MTLoFieldDefs extends ALoFieldDefs {

  MTLoFieldDefs() { }
}

// to represent an empty list of field definitions
class ConsLoFieldDefs extends ALoFieldDefs {
  FieldDef first;
  ALoFieldDefs rest;

  ConsLoFieldDefs(FieldDef first, ALoFieldDefs rest) {
    this.first = first;
    this.rest = rest;
  }
}


/*
;                                                          
;                                                          
;                                                          
;   ;;;;;  ;          ;       ;   ;;;;;;            ;;;    
;   ;                 ;       ;   ;     ;          ;       
;   ;                 ;       ;   ;      ;         ;       
;   ;      ;    ;;;   ;    ;; ;   ;      ;   ;;;  ;;;;     
;   ;;;;   ;   ;   ;  ;   ;  ;;   ;      ;  ;   ;  ;       
;   ;      ;  ;    ;  ;  ;    ;   ;      ; ;    ;  ;       
;   ;      ;  ;;;;;;  ;  ;    ;   ;      ; ;;;;;;  ;       
;   ;      ;  ;       ;  ;    ;   ;      ; ;       ;       
;   ;      ;   ;      ;   ;  ;;   ;     ;   ;      ;       
;   ;      ;    ;;;;  ;    ;; ;   ;;;;;;     ;;;;  ;       
;                                                          
;                                                          
;                                                          
*/
// to represnt a field in a class or method args
class FieldDef {
  ClassDef type;
  String name;

  FieldDef(ClassDef type, String name) {
    this.type = type;
    this.name = name;
  }
}

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

// to represent a list of method definitions
abstract class ALoMethodDefs {
}

// to represent an empty list of method definitions
class MTLoMethodDefs extends ALoMethodDefs {

  MTLoMethodDefs() {
  }
}

// to represent a nonempty list of method definitions
class ConsLoMethodDefs extends ALoMethodDefs {
  MethodDef first;
  ALoMethodDefs rest;

  ConsLoMethodDefs(MethodDef first, ALoMethodDefs rest) {
    this.first = first;
    this.rest = rest;
  }
}


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



// to represent a method definition
class MethodDef {
  String name;
  ClassDef returnType;
  Body body;
  ALoFieldDefs arguments;

  MethodDef(String name, ClassDef returnType, Body body, ALoFieldDefs arguments) {
    this.name = name;
    this.returnType = returnType;
    this.body = body;
    this.arguments = arguments;
  }
}


/*
We can now turn our porgram into an example of data in this class hieararchy:
*/

class ProgramExamples{
  ProgramExamples(){}

  // base classes

  DummyClassDef objClass = new DummyClassDef("Object");

  DummyClassDef aLibItemClass = new DummyClassDef("ALibItem");

  // built-in types and classes

  ClassDef intClass = new ClassDef(  "int", 
                              objClass,
                              new MTLoFieldDefs(), 
                              new MTLoMethodDefs());

  ClassDef booleanClass = new ClassDef("boolean",
                                       objClass, 
                                       new MTLoFieldDefs(), 
                                       new MTLoMethodDefs());

  ClassDef stringClass = new ClassDef("String",
                                      objClass,
                                      new MTLoFieldDefs(), 
                                      new MTLoMethodDefs());
 

  // data to represent the Book class

  Body body = new Body("return this.year < year;");

  FieldDef titleField = new FieldDef(stringClass, "title");
  FieldDef yearField  = new FieldDef(intClass, "year");
   
  ALoFieldDefs beforeArguments = new ConsLoFieldDefs(yearField,
                                   new MTLoFieldDefs()); 

  MethodDef beforeMethod = new MethodDef("before", booleanClass, body, beforeArguments);   

  ALoFieldDefs bookFields = new ConsLoFieldDefs(titleField, 
                              new ConsLoFieldDefs(yearField, 
                                new MTLoFieldDefs())); 

  ALoMethodDefs bookMethods = new ConsLoMethodDefs(beforeMethod, 
                                new MTLoMethodDefs()); 

  ClassDef bookClass = new ClassDef("Book",
                                    aLibItemClass,
                                    bookFields,     
                                    bookMethods);  

  // data to represent the Examples class

  FieldDef b1FieldDef = new FieldDef(bookClass, "b1");
  FieldDef b2FieldDef = new FieldDef(bookClass, "b2");

  FieldDef testBefore1FieldDef = new FieldDef(booleanClass, "testBefore1");
  FieldDef testBefore2FieldDef = new FieldDef(booleanClass, "testBefore2");

  ALoFieldDefs examplesFields = new ConsLoFieldDefs(b1FieldDef,
                                  new ConsLoFieldDefs(b2FieldDef, 
                                    new ConsLoFieldDefs(testBefore1FieldDef,
                                       new ConsLoFieldDefs(testBefore2FieldDef,
                                         new MTLoFieldDefs())))); 

  ALoMethodDefs examplesMethods = new MTLoMethodDefs(); 

  ClassDef examplesClass = new ClassDef("Examples",
                                        objClass,
                                        examplesFields,
                                        examplesMethods);


  ALoClassDefs program = new ConsLoClassDefs(bookClass,
                           new ConsLoClassDefs(examplesClass,
                             new MTLoClassDefs()));
}

