import java.util.Vector;

/**
 * <b>Don't panic! You don't have to understand the implementation of
 * this class.</b><p>Class <code>Maze</code> describes a maze of
 * <em>height * width</em> rooms.  The implementation of the class is
 * rather complicated.  Class <code>Maze</code> is only used in the
 * main programs <code>Main1-Main4</code> and you don't have to create
 * any new mazes, nor use any methods of the class.  */
public class Maze {
    Room[][] rooms;
    int width;
    int height;

    /**
     * Constructs a <em>height</em>*<em>width</em> maze. Initially, the rooms
     * of the maze have no doors to other rooms.
     * @param width	the width of the maze
     * @param height	the height of the maze
     * @return a new maze of <em>height * width</em> rooms.  */
    public Maze(int width, int height) {
	this.width = width;
	this.height = height;
	rooms = new Room[height][width];
	for (int y = 0; y < height; y++) {
	    for (int x = 0; x < width; x++) {
		rooms[y][x] = new Room("Room("+ x + ", " + y + ")");
	    }
	}
    }

    /**
     * Retrieves a room of the maze at coordinates (x, y).
     * @param x	the x coordinate of the room; <em>0 &lt;= x &lt; width</em>.
     * @param y	the y coordinate of the room; <em>0 &lt;= y &lt; height</em>.
     * @return		the room at position (x, y).
     */
    public Room getRoom(int x, int y) {
	if (x < 0 || x >= width
	    || y < 0 || y >= height) {
	    return null;
	} else {
	    return rooms[y][x];
	}
    }

    /**
     * Makes a door to the given <a
     * href="Robot.html#direction">direction</a> in room (x, y).  Note
     * that all doors are not possible in the border of the maze.
     * @param x	the x coordinate of the room; <em>0 &lt;= x &lt; width</em>.
     * @param y	the y coordinate of the room; <em>0 &lt;= y &lt; height</em>.
     * @param direction the <a
     * href="Robot.html#direction">direction</a> of the new door.
     * @return          <code>true</code> if the door could be made and
     *                  <code>false </code> if the door was not possible.  */
    public boolean makeDoor(int x, int y, int direction) {
	direction = direction % 4;
	int x2 = x + (direction%2)*(2-direction);
	int y2 = y + ((direction + 1)%2)*(1-direction);
	if (x < 0 || x >= width
	    || y < 0 || y >= height
	    || x2 < 0 || x2 >= width
	    || y2 < 0 || y2 >= height) {
	    return false;
	} else {
	    Room room1 = rooms[y][x];
	    Room room2 = rooms[y2][x2];
	    room1.connect(room2, direction);
	    return true;
	}
    }

    /**
     * This is a rather complicated method that connects several rooms
     * simultaneously by making several doors.  The coordinates
     * <em>(x1, y1)</em> and <em>(x2, y2)</em> define a rectangle.
     * All rooms inside the rectangle are connected to their neighbors
     * inside the rectangle by doors.
     * @param x1 the x1 coordinate of the room; <em>0 &lt;= x1 &lt;
     * width</em>.
     * @param y1 the y1 coordinate of the room; <em>0 &lt;= y1 &lt;
     * height</em>.
     * @param x2 the x2 coordinate of the room; <em>0 &lt;= x2 &lt;
     * width</em>.
     * @param y2 the y2 coordinate of the room; <em>0 &lt;= y2 &lt;
     * height</em>.
     * @return          <code>true</code> if all doors could be made and
     *                  <code>false </code> if some doors were not possible.  */
    public boolean connectRooms(int x1, int y1, int x2, int y2) {
	int dx, dy;

	if (x1 < 0 || x1 >= width || y1 < 0 || y1 >= height
	    || x2 < 0 || x2 >= width || y2 < 0 || y2 >= height) {
	    return false;
	}
	if (x2 < x1) {
	    dx = -1;
	} else {
	    dx = 1;
	}
	if (y2 < y1) {
	    dy = -1;
	} else {
	    dy = 1;
	}
	if (y1 != y2) {
	    for (int x = x1; dx*(x2 - x) >= 0 ; x += dx) {
		for (int y = y1; y != y2; y += dy) {
		    makeDoor(x, y, 1 - dy);
		}
	    }
	}
	if (x1 != x2) {
	    for (int y = y1; dy*(y2 - y) >= 0; y += dy) {
		for (int x = x1; x != x2; x += dx) {
		    makeDoor(x, y, 2 - dx);
		}
	    }
	}
	return true;
    }

    /**
     * A simple method that draws a dashed line.
     * @param length	the number of dashes ('-') that should be drawn.
     */
    private void printLine(int length) {
	for (int k = 0; k < length; k++) {
	    System.out.print("-");
	}
    }

    /**
     * Prints the maze on the terminal.  We use simple ASCII graphics.
     * The walls of the rooms are drawn by using letters '-', '|', and
     * '+'.  The objects that the rooms contain are drawn by using the
     * labels of the objects.  */
    public void print() {
	for (int y = height - 1; y >= 0; y--) {
	    System.out.print("+");
	    for (int x = 0; x < width; x++) {
		if (rooms[y][x].possibleDirection(0)) {
		    System.out.print("    +");
		} else {
		    System.out.print("----+");
		}
	    }
	    System.out.println();
	    for (int k = 0; k < 3; k++) {
		System.out.print("|");
		for (int x = 0; x < width; x++) {
		    for (int l = 0; l < 4; l++) {
			int index = k*4 + l;
			Room room = getRoom(x, y);
			Object thing = room.getObjectAt(index);
			if (thing != null) {
			    if (thing instanceof Labeled) {
				System.out.print(((Labeled)thing).label());
			    } else {
				System.out.print("*");
			    }
			} else {
			    System.out.print(" ");
			}
		    }
		    if (rooms[y][x].possibleDirection(1)) {
			System.out.print(" ");
		    } else {
			System.out.print("|");
		    }
		}
		System.out.println();
	    }
	    if (y == 0) {
		System.out.print("+");
		for (int x = 0; x < width; x++) {
		    System.out.print("----+");
		}
		System.out.println();
	    }
	}
    }
}
