/* Grid.java */

import java.util.*;

/**
 *  The Grid class represents a rectangular grid.  
 **/

public class Grid {

  // Horizontal and vertical dimensions of the grid.
  protected int horiz;
  protected int vert;
  // Horizontal and vertical interior walls; each is true if the wall exists.
  protected boolean[][] hWalls;
  protected boolean[][] vWalls;

  // Object for generating random numbers.
  private static Random random;

  /**
   *  Grid() creates a rectangular grid having "horizontalSize" cells in the
   *  horizontal direction, and "verticalSize" cells in the vertical direction.
   **/
  public Grid(int horizontalSize, int verticalSize) {
    int i, j;

    horiz = horizontalSize;
    vert = verticalSize;
    // Check if there are any interior walls
    if ((horiz < 1) || (vert < 1) || ((horiz == 1) && (vert == 1))) {
      return;
    }

    // Create all of the horizontal interior walls.  
    if (vert > 1) {
      hWalls = new boolean[horiz][vert - 1];
      for (j = 0; j < vert - 1; j++) {
        for (i = 0; i < horiz; i++) {
          hWalls[i][j] = true;
        }
      }
    }
    // Create all of the vertical interior walls.
    if (horiz > 1) {
      vWalls = new boolean[horiz - 1][vert];
      for (i = 0; i < horiz - 1; i++) {
        for (j = 0; j < vert; j++) {
          vWalls[i][j] = true;
        }
      }
    }
  }


    /**
     * createMaze() turns an ordinary rectangular grid into a maze.  
     * There is exactly one path between any two cells of the maze.  
     * Disjoint sets implemented with the union-find data structure is used 
     * to ensure that there is only one path between any two cells.
     *
     * Fill in the createMaze method.  You should go through all the walls of
     * the maze in random order, and remove any wall whose removal will not
     * create a cycle.  Use the implementation of union-find provided in the
     * union-find package to avoid creating any cycles.
     *
     * Note the method randInt() further below, which generates a random
     * integer.  randInt() generates different numbers every time the program
     * is run, so that you can make lots of different mazes.
     **/
  public void createMaze() {


  }

  /**
   *  toString() returns a string representation of the grid.
   **/
  public String toString() {
    int i, j;
    String s = "";

    // Print the top exterior wall.
    for (i = 0; i < horiz; i++) {
      s = s + "+-";
    }
    s = s + "+\n|";

    // Print the grid interior.
    for (j = 0; j < vert; j++) {
      // Print a row of cells and vertical walls.
      for (i = 0; i < horiz - 1; i++) {
        if (vWalls[i][j]) {
          s = s + " |";
        } else {
          s = s + "  ";
        }
      }
      s = s + " |\n+";
      if (j < vert - 1) {
        // Print a row of horizontal walls and wall corners.
        for (i = 0; i < horiz; i++) {
          if (hWalls[i][j]) {
            s = s + "-+";
          } else {
            s = s + " +";
          }
        }
        s = s + "\n|";
      }
    }

    // Print the bottom exterior wall.  (Note that the first asterisk has
    // already been printed.)
    for (i = 0; i < horiz; i++) {
      s = s + "-+";
    }
    return s + "\n";
  }

  /**
   * horizontalWall() determines whether the horizontal wall on the bottom
   * edge of cell (x, y) exists.  If the coordinates (x, y) do not correspond
   * to an interior wall, true is returned.
   **/
  public boolean horizontalWall(int x, int y) {
    if ((x < 0) || (y < 0) || (x > horiz - 1) || (y > vert - 2)) {
      return true;
    }
    return hWalls[x][y];
  }

  /**
   * verticalWall() determines whether the vertical wall on the right edge of
   * cell (x, y) exists. If the coordinates (x, y) do not correspond to an
   * interior wall, true is returned.
   **/
  public boolean verticalWall(int x, int y) {
    if ((x < 0) || (y < 0) || (x > horiz - 2) || (y > vert - 1)) {
      return true;
    }
    return vWalls[x][y];
  }

  /**
   * randInt() returns a random integer from 0 to choices - 1.
   **/
  private static int randInt(int choices) {
    if (random == null) {       // Only executed first time randInt() is called
      random = new Random();       // Create a "Random" object with random seed
    }
    int r = random.nextInt() % choices;      // From 1 - choices to choices - 1
    if (r < 0) {
      r = -r;                                          // From 0 to choices - 1
    }
    return r;
  }

  /*
   * diagnoseMaze() checks a maze and prints a warning if not every cell
   * can be reached from the upper left corner cell, or if there is a
   * cycle reachable from the upper left cell.
   *
   */
  private void diagnoseMaze() {

    boolean mazeFine = true;

    // Create an array that indicates whether each cell has been visited.
    boolean[][] cellVisited = new boolean[horiz][vert];

    // Do a depth-first or breadth-first traversal.
    // Use a method you create called DFS or BFS.
    // Do NOT put all the code into this method.
    // Fill in some code here...

    // Check to be sure that every cell of the maze was visited.
    // You will need to add more code here, too...

    if (mazeFine) {
      System.out.println("What a fine maze you've created!");
    }
  }

  /*
   * main() creates a grid of dimensions specified on the command
   * line, creates a maze out of it, prints the maze, and runs the 
   * diagnostic method to see if the maze is good.
   */
  public static void main(String[] args) {
    int x = 39;
    int y = 15;

    /*
     *  Read the input parameters.
     */

    if (args.length > 0) {
      try {
        x = Integer.parseInt(args[0]);
      }
      catch (NumberFormatException e) {
        System.out.println("First argument to Simulation is not an integer.");
        System.out.println(" --> using default value instead.");
      }
    }

    if (args.length > 1) {
      try {
        y = Integer.parseInt(args[1]);
      }
      catch (NumberFormatException e) {
        System.out.println("Second argument to Simulation is not an integer.");
        System.out.println(" --> using default value instead.");
      }
    }

    Grid maze = new Grid(x, y);
    maze.createMaze();
    System.out.print(maze);
    maze.diagnoseMaze();
  }

}
