package interestingExplorationsWithInnerClasses;

public class Driver {

	public static void main(String[] args) {
		System.out.println("\n*** Instantiating Inner Classes directly from client");
		instantiateInnerClasses();
		System.out.println("\n*** Leveraging returned Inner Class instance variables from Outer Class");
		leverageReturnedInnerClasses();
	}
	
	private static void instantiateInnerClasses() {
		// Instantiate some STATIC inner classes
		Outer.StaticInnerPublic myA = new Outer.StaticInnerPublic();
		
		// Cannot instantiate this...
		//     Outer.StaticInnerPrivate myB = new Outer.StaticInnerPrivate();
		
		System.out.println(myA.getInnerName() + " is " + myA.age + " years old.");

		// Instantiate some REGULAR inner classes
		Outer myOuter = new Outer();
		Outer.InnerPublic myC = myOuter.new InnerPublic();
		System.out.println(myC.getInnerName() + " is " + myC.age + " years old.");

		// Cannot instantiate this...
		//     Outer.InnerPrivate myD = myOuter.new InnerPrivate();
		
		// Obviously, we cannot instantiate anonymous inner classes
	}
	
	private static void leverageReturnedInnerClasses() {
		Outer myOuter = new Outer();
		Outer.StaticInnerPublic myA = myOuter.getA();
		System.out.println(myA.getInnerName() + " is " + myA.age + " years old.");
		
		/* How to deal with Static Inner Private class?
		 * 
		 *    1. We cannot create a local variable of type Outer.StaticInnerPrivate
		 *       Outer.StaticInnerPrivate myB = myOuter.getB(); 
		 *       
		 *    2. We cannot cast an Outer.StaticInnerPrivate as an Outer.StaticInnerPublic 
		 *       Outer.StaticInnerPublic myB = (Outer.StaticInnerPublic) myOuter.getB();  
		 *       
		 *    3. We can return an Outer.StaticInnerPrivate instance as an Object, but...
		*/
		Object myB = myOuter.getB();
		System.out.println(myB);  // Cannot get to any Inner Class instance variables		
		/*
		 *    4. We also cannot cast an Outer.StaticInnerPrivate as a DummyClassWithInnerNameAndAge
		 *       DummyClassWithInnerNameAndAge myB2 = (DummyClassWithInnerNameAndAge) myOuter.getB();
		 *
		 *       The reason casting will not work is that we are neither downcasting to a subtype
		 *       nor upcasting to a supertype.		
		 *
		 */
		double d = 83.4;  	// Note that 83 is the ASCII code for capital S 
		char c1 = (char) d;	// This cast is possible 
		System.out.println(c1);
		// Character c2 = (Character) d;  // This cast is not!
		/*
		 *    5.  OK, since casting is letting us down, can we have an Inner Class extend
		 *        from a supertype, such that we COULD cast?
		 */
		 DummyClassWithInnerNameAndAge myB2 = (DummyClassWithInnerNameAndAge) myOuter.getB2();
		 System.out.println(myB2.getInnerName() + " is " + myB2.getAge() + " years old.");
		 // Wow...we are able to get the InnerName attribute now, but how convoluted is this???
			
	
	}

}
