/***********************************************
 *  CS2510 Spring 2011 
 *  Lecture #12.2
 *  Equality, the second way
 ***********************************************/

import tester.*;

// Represents a Location
class Loc{
    int x;
    int y;
    
    Loc(int x, int y){
        this.x = x;
        this.y = y;
    }
    
    // Is this Loc the same as the given one
    boolean sameLoc(Loc that){
        return (that.x == this.x &&
                that.y == this.y);
    }
}

// Represents a Shape
interface IShape{
    // Is that shape the same as this shape
    public boolean sameShape(IShape that);
    
    // Is this you a Circle?
    public boolean isCirc();
    // Turn you into a Circle
    public Circ magicCirc(); 
    // Is this a Rect
    public boolean isRect();
    // Turn you into a Rect
    public Rect magicRect(); 
    // Is this a Combo
    public boolean isCombo();
    // Turn you into a Combo
    public Combo magicCombo(); 
    
}

// Represents a Circle
class Circ implements IShape{
    Loc loc;
    int rad;

    Circ(Loc loc, int rad) {
        this.loc = loc; this.rad = rad;
    }
    
    /** Template:
     *    Fields:
     *      ... this.loc ... -- Loc
     *      ... this.rad ... -- int
     *      
     *    Methods:
     *      ... this.sameShape(IShape) ... -- boolean
     *      ... this.sameCirc(Circ) ...    -- boolean
     *      ... this.isCirc() ...  -- boolean
     *      ... this.isRect() ...  -- boolean
     *      ... this.isCombo() ... -- boolean
     *      ... this.magicCirc() ...  -- Circ
     *      ... this.magicRect() ...  -- Rect
     *      ... this.magicCombo() ... -- Combo
     *      
     *    Methods of Fields:
     *      ... this.loc.sameLoc() ...-- boolean
     */
    // Is that shape the same as this Circ
    public boolean sameShape(IShape that){
        if(that.isCirc()){
            return this.sameCirc(that.magicCirc());
        }else{
            return false;
        }
    }
    // Is that Circle the same as this Circ
    public boolean sameCirc(Circ that){
        return (this.loc.sameLoc(that.loc) &&
                this.rad == that.rad);
    }
    // Is this a Circle
    public boolean isCirc(){
        return true;
    }
    // Is this a Rect
    public boolean isRect(){
        return false;
    }
    // Is this a Combo
    public boolean isCombo(){
        return false;
    }
    // Turn you into a Circle
    public Circ magicCirc(){
        return this;  
    } 
    // Turn you into a Rect
    public Rect magicRect(){
        throw new RuntimeException("What were you thinking!");
    } 
    // Turn you into a Combo
    public Combo magicCombo(){
        throw new RuntimeException("What were you thinking!");
    }
}

// Represents a Rectangle
class Rect implements IShape{
    Loc loc;
    int w;
    int h;
    
    Rect(Loc loc, int w, int h) {
        this.loc = loc; this.w = w; this.h = h;
    }
    
    // Is that shape the same as this Rect
    public boolean sameShape(IShape that){
        return that.isRect() &&
            this.sameRect(that.magicRect());
    }
    // Is that Rect the same as this Rect
    public boolean sameRect(Rect that){
        return (this.loc.sameLoc(that.loc) &&
                this.w == that.w &&
                this.h == that.h);
    }
    // Is this a Circle
    public boolean isCirc(){
        return false;
    }
    // Is this a Rect
    public boolean isRect(){
        return true;
    }
    // Is this a Combo
    public boolean isCombo(){
        return false;
    }
    // Turn you into a Circle
    public Circ magicCirc(){
        throw new RuntimeException("What were you thinking!");  
    } 
    // Turn you into a Rect
    public Rect magicRect(){
        return this;
    } 
    // Turn you into a Combo
    public Combo magicCombo(){
        throw new RuntimeException("What were you thinking!");
    } 

}

// Represents a Combo
class Combo implements IShape{
    IShape top;
    IShape bot;
    
    Combo(IShape top, IShape bot) {
        this.top = top; this.bot = bot;
    }
    // Is that shape the same as this Combo
    public boolean sameShape(IShape that){
        return that.isCombo() &&
            this.sameCombo(that.magicCombo());
    }
    // Is that Combo the same as this Combo
    public boolean sameCombo(Combo that){
        return (that.top.sameShape(this.top) &&
                that.bot.sameShape(this.bot));
    }
    // Is this a Circle
    public boolean isCirc(){
        return false;
    }
    // Is this a Rect
    public boolean isRect(){
        return false;
    }
    // Is this a Combo
    public boolean isCombo(){
        return true;
    }
    // Turn you into a Circle
    public Circ magicCirc(){
        throw new RuntimeException("What were you thinking!");  
    } 
    // Turn you into a Rect
    public Rect magicRect(){
        throw new RuntimeException("What were you thinking!");
    } 
    // Turn you into a Combo
    public Combo magicCombo(){
        return this;
    }
}


// Exaustive Testing...
class LectureExamples{
    IShape c1 = new Circ(new Loc(50, 50), 10);
    IShape c2 = new Circ(new Loc(60, 40), 30);
    IShape c3 = new Circ(new Loc(50, 50), 10);
    IShape r1 = new Rect(new Loc(50, 50), 10, 20);
    IShape r2 = new Rect(new Loc(60, 40), 30, 50);
    IShape r3 = new Rect(new Loc(50, 50), 10, 20);
    IShape comb1 = new Combo(this.c1, this.c2);
    IShape comb2 = new Combo(this.r1, this.c1);
    IShape comb3 = new Combo(this.c1, this.c2);
    IShape comb4 = new Combo(this.comb1, this.comb2);
    IShape comb5 = new Combo(this.comb1, this.comb2);
    IShape comb6 = new Combo(this.comb1, this.comb1);
    
    // Test the same kinds of things (Circ/Circ, Rect/Rect)
    boolean testSameOnes(Tester t){
        return (t.checkExpect(this.c1.sameShape(this.c1), true) &&
                t.checkExpect(this.c1.sameShape(this.c2), false) &&
                t.checkExpect(this.c3.sameShape(this.c1), true) &&
                t.checkExpect(this.r1.sameShape(this.r1), true) &&
                t.checkExpect(this.r1.sameShape(this.r2), false) &&
                t.checkExpect(this.r3.sameShape(this.r1), true) &&
                t.checkExpect(this.comb1.sameShape(this.comb1), true) &&
                t.checkExpect(this.comb1.sameShape(this.comb2), false) &&
                t.checkExpect(this.comb4.sameShape(this.comb5), true) &&
                t.checkExpect(this.comb5.sameShape(this.comb6), false));
    }
    // Test different kinds of things (Circ/Rect, Rect/Combo) all false
    boolean testSameDiffs(Tester t){
        return (t.checkExpect(this.r1.sameShape(this.c1), false) &&
                t.checkExpect(this.comb1.sameShape(this.c2), false) &&
                t.checkExpect(this.c1.sameShape(this.r1), false) &&
                t.checkExpect(this.comb1.sameShape(this.r2), false) &&
                t.checkExpect(this.c1.sameShape(this.comb1), false) &&
                t.checkExpect(this.r2.sameShape(this.comb2), false));
    }
}