package beginner;

import static com.sandwich.koan.constant.KoanConstants.__;
import static com.sandwich.util.Assert.assertEquals;
import static com.sandwich.util.Assert.fail;

import com.sandwich.koan.Koan;

@SuppressWarnings("unused")
public class AboutCasting {
    
	@Koan
	public void longPlusInt() {
		int a = 6;
		long b = 10;
		Object c = a + b;
		assertEquals(c, __);
		assertEquals(c instanceof Integer, __);
		assertEquals(c instanceof Long, __);
	}
    
    @Koan
	public void forceIntTypecast() {
		long a = 2147483648L; 
		// What happens if we force a long value into an int?
		int b = (int)a;
		assertEquals(b, __);
	}
   
    @Koan
	public void implicitTypecast() {
    	int a = 1;
    	int b = Integer.MAX_VALUE;
		long c = a + b; // still overflows int... which is the Integer.MIN_VALUE, the operation occurs prior to assignment to long
		assertEquals(c, __);
	}
    
    class Parent extends Child { public String complain() { return "TPS reports don't even have a cover letter!"; } }
    class GrandParent extends Parent { public String complain() { return "Get your feet off the davenport!"; } }
    
    @Koan
    public void downCastWithInerhitance() {
    	GrandParent grandParent = new GrandParent();
    	Parent parentReference = grandParent; // Why isn't there an explicit cast?
    	assertEquals(grandParent instanceof GrandParent, __);
    	assertEquals(parentReference instanceof GrandParent, __);
    	assertEquals(parentReference instanceof Parent, __);
    	assertEquals(parentReference instanceof Child, __);
    }
    
    @Koan
    public void downCastAndPolymophism() {
    	GrandParent grandParent = new GrandParent();
    	Parent parentReference = grandParent;
    	// If the result is unexpected, consider the difference between an instance and its reference
    	assertEquals(parentReference.complain(), __);
    }
    
    @Koan
    public void upCastWithInheritance() {
    	Object grandParent = new GrandParent();
    	Parent parentReference = (Parent)grandParent; // Why do we need an explicit cast here?
    	assertEquals(grandParent instanceof Child,__);
    	assertEquals(parentReference instanceof GrandParent,__);
    	assertEquals(parentReference instanceof Parent,__);
    	assertEquals(parentReference instanceof Child,__);
    }
    
    @Koan
    public void upCastAndPolymophism() {
    	Object grandParent = new GrandParent();
    	Parent parent = (GrandParent)grandParent;
    	// Think about the result. Did you expect that? Why?
    	// How is that different from above?
    	assertEquals(parent.complain(), __);
    }
    
    interface Sleepable {
    	String sleep();
    }
    
    class Child implements Sleepable{
    	public String sleep() { 
    		return "zzzz"; 
    	}
    }
    
    @Koan
    public void classCasting(){
    	try{
    		Object o = new Object(); 	// were downcasting way to far here - would it be possible
    									// to even compile this koan had we done what was safe, and 
    									// held the reference as Sleepable?
    		((Sleepable)o).sleep();
    	}catch(ClassCastException x){
    		fail("Object does not implement Sleepable, maybe one of the people classes do?");
    	}
    }
    
    @Koan
    public void complicatedCast() {
    	Child parent = new Parent();
    	// How can we access the parent's ability to "complain" - if the reference is held as a superclass? 
    	assertEquals(new Parent().complain(), __);
    }
    
    @Koan
    public void complicatedCastWithInterface() {
    	Object parent = new Child();
    	// What do you need to do in order to call "sleep" on the parent? 
    	assertEquals(new Child().sleep(), __);
    }

   
}

@@ -876,24 +876,180 @@
 _);%0A%09%7D%0A    %0A
+    interface Sleepable %7B%0A    %09String sleep();%0A    %7D%0A    class Child implements Sleepable%7B%0A    %09public String sleep() %7B %0A    %09%09return %22zzzz%22; %0A    %09%7D%0A    %7D%0A
     class Pa
@@ -1069,16 +1069,22 @@
 Child %7B 
+%0A    %09
 public S
@@ -1094,32 +1094,39 @@
 ng complain() %7B 
+%0A    %09%09
 return %22TPS repo
@@ -1159,25 +1159,36 @@
 r letter!%22; 
-%7D
+%0A    %09%7D %0A   
  %7D%0A    class
@@ -1217,16 +1217,22 @@
 arent %7B 
+%0A    %09
 public S
@@ -1250,16 +1250,23 @@
 ain() %7B 
+%0A    %09%09
 return %22
@@ -1300,17 +1300,28 @@
 port!%22; 
-%7D
+%0A    %09%7D %0A   
  %7D%0A    %0A
@@ -2108,38 +2108,37 @@
 itance() %7B%0A    %09
-Object
+Child
  grandParent = n
@@ -2256,54 +2256,84 @@
    %09
-assertEquals(grandParent instanceof Child,__);
+GrandParent grandParentReference = (GrandParent)parentReference; // Or here?
 %0A   
@@ -2339,33 +2339,38 @@
   %09assertEquals(
-p
+grandP
 arentReference i
@@ -2406,33 +2406,38 @@
   %09assertEquals(
-p
+grandP
 arentReference i
@@ -2468,33 +2468,38 @@
   %09assertEquals(
-p
+grandP
 arentReference i
@@ -2586,22 +2586,21 @@
  %7B%0A    %09
-Object
+Child
  grandPa
@@ -2829,174 +2829,8 @@
    %0A
-    interface Sleepable %7B%0A    %09String sleep();%0A    %7D%0A    %0A    class Child implements Sleepable%7B%0A    %09public String sleep() %7B %0A    %09%09return %22zzzz%22; %0A    %09%7D%0A    %7D%0A    %0A
     
@@ -3500,235 +3500,14 @@
 _);%0A
+
     %7D%0A
-    %0A    @Koan%0A    public void complicatedCastWithInterface() %7B%0A    %09Object parent = new Child();%0A    %09// What do you need to do in order to call %22sleep%22 on the parent? %0A    %09assertEquals(new Child().sleep(), __);%0A    %7D%0A%0A
    %0A

make AboutCasting a bit clearer