/**
 * This is a demo of factory method design pattern. This pattern allows you
 * to abstract away the common logic for some framework.
 * In this case the framework is MazeGame. The common logic is in the constructor
 * of MazeGame. By using factory method pattern, we are able to create MazeGame
 * with different rooms without reimplementing the connection logic.
 * The 'connection logic' is really simple here (just one connect) but one can
 * imagine a much more complex case with many more connections.
 * 
 * The concept of MazeGame is take from Wikipedia:
 * 		https://en.wikipedia.org/wiki/Factory_method_pattern
 * The code is original.
 * 
 * @author Jason Qiu
 */
public abstract class MazeGame {
	
	/*
	 * @effects Build two different MazeGame
	 */
	public static void main(String[] args) {
		MazeGame g1 = new OrdinaryMazeGame();
		MazeGame g2 = new MagicMazeGame();
	}
	
	/*
	 * Implements the common logic for a MazeGame
	 * 
	 * @effects Build a MazeGame with two rooms which connect to each other
	 */
    public MazeGame() {
        Room room1 = makeRoom();
        Room room2 = makeRoom();
        room1.connect(room2);
    }

    /*
     * Factory method
     */
    abstract protected Room makeRoom();
}

class MagicMazeGame extends MazeGame {
    @Override
    protected Room makeRoom() {
        return new MagicRoom(); 
    }
}

class OrdinaryMazeGame extends MazeGame {
    @Override
    protected Room makeRoom() {
        return new OrdinaryRoom(); 
    }
}

abstract class Room {
	protected static int numOfRooms = 0;
	protected int id;
	
	/*
	 * @effects Create a room and assign an ID to it.
	 * 			Also increase the total room counts.
	 */
	public Room() {
		numOfRooms++;
		id = numOfRooms;
		System.out.println(this + " is created ");
	}

	/*
	 * @effects Connects this with that
	 */
	public void connect(Room that) {
		System.out.println(this + " is connected to " + that);
	}
}

class OrdinaryRoom extends Room {
	@Override
	public String toString() {
		return "OrdinaryRoom#"+id;
	}
}

class MagicRoom extends Room {
	@Override
	public String toString() {
		return "MagicRoom#"+id;
	}
}