/*
 * This is the "main" class.  All it does is instantiate
 * a controller and get the game running.
 */

public class mine {

  public static void main(String [] argv){
    
    GameController control = new GameController();
    control.startGame();
    
  }
}

/*********************************************************************/

/*
 * This class is eventually going to control all the flow
 * of Minesweeper.  All input/output of the program will 
 * be through this class.  
 *
 * Remember that a returning -1 is an invalid term (reserved)
 */
public class GameController{

  private int level_;
  private Grid grid_;

  private boolean gameOver_;

  public GameController(){
    gameOver_ = false;
  }

  public void startGame(){

    System.out.println("Hello!  Welcome to Danah's Minesweeper");
    if (this.askLevel()){
      this.createGame();
      this.programFlow();
    }
    else {
      System.out.println("Oh well, thanks for trying!");
    }

  }
    
  /* 
   * The goal of this method is to ask the user what level
   * they want to play.  It is important to make certain that
   * the input is accurate and that we act accordingly.
   *
   * The boolean tells the controller whether or not we want
   * to actually play
   */
  public boolean askLevel(){

    System.out.println("What level would you like to play?");
    System.out.println("1=Beginner, 2=Intermediate, 3=Advanced (0 for no play)");
    level_ = ReadInput.getInt();
    System.out.println("more stuff = " + ReadInput.isMoreStuff());
    ReadInput.flushLine(); // flush the rest of the line!

    System.out.println("You have chosen level " + level_);

    /* Since 0 is no play, we check for no play and return whether
     * or not we got a zero.  I don't know what to do if they type 
     * something that is not correct...
     */
    if (level_ != 0){
      return true;
    }
    else return false;
  }

  /*
   * Given the level of the game, this method creates the
   * actual board.  [Right now, it only prints out the very
   * basics since we don't have a board class]
   */
  public void createGame(){
    /* eventually, this will create a real game but for now
     * I will just print out an array of the appropriate size
     */
    
    int xSize, ySize, numMines;
    

    /* THESE SHOULD BE CONSTANTS */
    if (level_ == 1){
      xSize = 8;
      ySize = 8;
      numMines = 4;
    }
    else if (level_ == 2){
      xSize = 16;
      ySize = 16;
      numMines = 4;
    }
    else if (level_ == 3){
      xSize = 16;
      ySize = 30;
      numMines = 4;
    }
    else {
      System.out.println("What size x,y would you like? [x y]");
      xSize = ReadInput.getInt();
      ySize = ReadInput.getInt();
      ReadInput.flushLine(); // flush the rest of the line!
      System.out.println("How many mines do you want?");
      numMines = ReadInput.getInt();
      ReadInput.flushLine(); // flush the rest of the line! 
      
    }

    grid_ = new Grid(xSize, ySize, numMines);
    grid_.createGrid();
    grid_.printGrid();
    
  }

  /* 
   * This now deals with the FOC of the entire program
   * So long as we are not in quit mode, we ask questions
   */
  public void programFlow(){
   
    while (!(gameOver_)){
      this.individualOptions();
      grid_.printGrid();      
    }

  }

  /* 
   * This asks for and deals with individual commands 
   */
  public void individualOptions(){
    int option, x, y;
    System.out.println("\n");
    System.out.println("What would you like to do next?");
    System.out.println("Options: 0=Quit 1=Uncover, 2=Flag, 3=Clear");
    option = ReadInput.getInt();
    ReadInput.flushLine(); // flush the rest of the line!
    
    if (option == 0){
      /* this is above since we don't want to get positions otherwise */
      System.out.println("You have chosen to quit.");
      this.stopGame();
    }

    else if (option == 1){ // uncovering
      System.out.println("What x and y positions? [x y]");
      x = ReadInput.getInt();
      y = ReadInput.getInt();
      ReadInput.flushLine(); // flush the rest of the line!

      boolean uncover;
      uncover = grid_.uncoverSquare(x, y);
      if (!uncover) stopGame();
      
    }
    else if (option == 2){ // flag
      System.out.println("What x and y positions? [x y]");
      x = ReadInput.getInt();
      y = ReadInput.getInt();
      ReadInput.flushLine(); // flush the rest of the line!
      grid_.flagSquare(x, y);
    }
    
    else if (option == 3){ // clear
      System.out.println("What x and y positions? [x y]");
      x = ReadInput.getInt();
      y = ReadInput.getInt();
      ReadInput.flushLine(); // flush the rest of the line!

      grid_.clearSquare(x, y);

    }
    else {
      System.out.println("You did not choose a valid commmand");
    }
    

  }

  public void stopGame(){
    gameOver_ = true;
  }
  

 }

/*********************************************************************/


/*
 * This class models the grid of the entire board and also
 * has a print method...
 */

public class Grid {

  private int width_, height_, numMines_;

  private Square [][] grid_;

  public Grid(int x, int y, int numMines){
    
    width_ = x;
    height_ = y;
    numMines_ = numMines;
    
    grid_ = new Square[width_][height_];

  }


  public void createGrid(){

    java.util.Random randomizer = new java.util.Random();
    
    int randomX, randomY;

    for (int i=0; i<numMines_; i++){
      
      randomX = (int) (randomizer.nextDouble() * width_);
      randomY = (int) (randomizer.nextDouble() * height_);

      grid_[randomX][randomY] = new MineSquare();

    }

    
    for (int y=0; y<height_; y++){
      for (int x=0; x<width_; x++){
	if (grid_[x][y] == null){
	  grid_[x][y] = new NumberSquare();
	}
      }
    }


  }

  public void printGrid(){
    System.out.println(""); // this gives clearer space
    for (int y=0; y<height_; y++){
      for (int x=0; x<width_; x++){
	System.out.print(" ");
	grid_[x][y].printSquare();
      }
      System.out.println("");
    }
   System.out.println(""); // this ends it so it does not cram into the bottom
  }

  /* returns whether or not it failed.  if it failed, we uncovered
   * a bomb 
   */
  public boolean uncoverSquare(int x, int y){
    System.out.println("uncovering " + x + ", " + y);
    return (grid_[x][y].uncoverSquare());
  }

  public void flagSquare(int x, int y){
    System.out.println("flagging " + x + ", " + y);
    grid_[x][y].flagSquare();
  }

  public void clearSquare(int x, int y){
    System.out.println("clearing " + x + ", " + y);
    grid_[x][y].clearSquare();
  }
  
    
}

/*********************************************************************/


/* 
 *  The goal of this class is to model a generic square.  It
 *  is an abstract class because we never use a square, only
 *  its subclasses.
 */

public abstract class Square {

  protected String printableElement_;
  protected boolean flagged_;

  public Square(){

    printableElement_ = "x";  // this is a good starter type
    flagged_ = false;

  }

  public void printSquare(){
    System.out.print("" + printableElement_);
  }
  
  public void flagSquare(){
    if (flagged_){
      printableElement_ = "x";
    }
    else {
      printableElement_ = "f";
    }
    flagged_ = !flagged_;
  }

  public void clearSquare(){}

  abstract public boolean uncoverSquare();


}

/*********************************************************************/


public class NumberSquare extends Square {


  public NumberSquare(){

    super();

  }

  public void clearSquare(){
  }

  public boolean uncoverSquare(){
    if (!flagged_){
      printableElement_ = " "; // this is temporary
      // i don't know how to tell what number I am and then combine
      // that information to pass on everything to uncover everything
    }
    else {
      System.out.println("Cannot uncover flagged option.");
    }
    return true;
  }


}

/*********************************************************************/


public class MineSquare extends Square {


  public MineSquare(){

    super();

  }

  public boolean uncoverSquare(){
   
    if (!flagged_){
      printableElement_ = "B";
      return false; // when we uncover a bomb!
    }
    else {
      System.out.println("Cannot uncover flagged option.");
    return false;
    }
  }

}
