
package PrintLabyrinth;

import java.util.Random;

//----------------------------------------------------------------------
/**
 * class representing a two dimensional labyrinth
 */

public class CreateLabyrinth
{

  /** the number of diamonds distributed in the field (set from
   * outside of the class with the appropriate method-calls */
  protected int num_diamonds_;

  /** the number of way cells distributed in the field (set from
   * outside of the class with the appropriate method-calls */
  protected int num_way_cells_;

  /** the max number of rows
   *  max_row_=rows-1*/
  protected int max_row_;
  /** the max number of cols
   *  max_col_=cols-1*/
  protected int max_col_;
  /** the row-coordinate of the "startpont"
   * with the range 0 to rows-1*/
  protected int startpoint_row_;
  /** the col-coordinate of the "startpont"
   * with the range 0 to cols-1*/
  protected int startpoint_col_;

  // allow or denay building angles
  protected boolean build_angle_;
  // allow or denay building a tree
  protected boolean build_tree_;
  // allow or denay building a loop
  protected boolean build_loop_;
  // allow or denay building a place
  // it is net able to build a palce wirhout to allow to build a loop
  protected boolean build_places_;

  //protected int diamonds_;
  //protected int max_ways_;
  protected int min_way_lenght_;
  protected int max_way_lenght_;
  protected int max_loops_;
  protected int loops_;

  protected LabyrinthField labyrinth_field_;
  protected Random random_generator_;
  protected RandomWayCoordinates randomwaycoordinates_;

  protected int row_;
  protected int col_;
  protected int way_lenght_;
  protected Direction way_direction_;
  protected Direction start_direction_;
  protected boolean new_point_;

//------------------------------------------------------------------------------
/**
 * Standard constructor
 * @param rows the number of rows of this labyrinth
 * @param cols the number of columns of this labyrinth
 * @exception IllegalArgumentException thrown if either rows or cols
 * is < 0
 */

  public CreateLabyrinth(int rows,int cols, int num_way_cells, int num_diamonds,
    boolean build_angle, boolean build_tree, boolean build_loop, boolean build_places)
    throws IllegalArgumentException, IllegalDirectionException
  {
    if (rows <= 1)
      throw(new IllegalArgumentException(
        "rows must be >= 1"));
    if (cols <= 1)
      throw(new IllegalArgumentException(
        "cols must be >= 1"));

    labyrinth_field_ = new LabyrinthField(rows, cols);
    random_generator_ = new Random();
    randomwaycoordinates_ = new RandomWayCoordinates(rows, cols);

    num_diamonds_=num_diamonds;
    num_way_cells_=num_way_cells;
    max_row_=rows-1;
    max_col_=cols-1;
    startpoint_row_=rows-1;
    startpoint_col_=(cols-1)/2;
    start_direction_= new Direction();
    start_direction_.setDirection(Direction.DIRECTION_UP);

    build_angle_=build_angle;
    build_tree_=build_tree;
    build_loop_=build_loop;
    // it is not able to build a palce wirhout to allow to build a loop
    build_places_=build_places;

    //diamonds_=0;
    //max_ways_=0;
    min_way_lenght_=5;
    max_way_lenght_=10;
    //max_loops_=num_way_cells_/min_way_lenght_;
    max_loops_=1000;
    loops_=0;

    row_=-1;
    col_=-1;
    way_lenght_=-1;
    way_direction_=new Direction();
    new_point_=false;
  }

public Direction getStartDirection()
{
  return start_direction_;
}

//------------------------------------------------------------------------------
/**
 * package-internal method called from the outside to set the number
 * of diamonds distributed in this labyrinthfield. It is not checked, whether
 * this number exceeds the maximum allowed number. This has to be done
 * beforehand.
 * @exception IllegalArgumentException thrown if the number of mines
 * is < 0
 */

  public void setNumDiamonds(int num_diamonds)
    throws IllegalArgumentException
  {
    if (num_diamonds < 0)
      throw(new IllegalArgumentException(
        "num_diamonds must be >= 0"));
    num_diamonds_ = num_diamonds;
  }

//------------------------------------------------------------------------------
/**
 * package-internal method called from the outside to set the number
 * of way cells distributed in this labyrinthfield. It is not checked, whether
 * this number exceeds the maximum allowed number. This has to be done
 * beforehand.
 * @exception IllegalArgumentException thrown if the number of way cells
 * is < 0
 */

  public void setNumWayCells(int num_way_cells)
    throws IllegalArgumentException
  {
    if (num_way_cells < 0)
      throw(new IllegalArgumentException(
        "num_way_cells must be >= 0"));
    num_way_cells_ = num_way_cells;
  }

//------------------------------------------------------------------------------
/**
 *
 *
 */
  protected int getIntRandomValue(int min, int max)
  {
    return min + random_generator_.nextInt(max-min+1);
  }

//------------------------------------------------------------------------------
/**
 *
 *
 */
  public void calculateWays()
    throws IllegalDirectionException
  {
    // definds the Startpoint of the labyrinth
    //Cell
    //cell=(Cell)labyrinth_field_.getElement(startpoint_row_,startpoint_col_);
    //cell.convertToStartpoint();
    //max_ways_++;
    labyrinth_field_.convertToStartpoint(startpoint_row_,startpoint_col_);

    // set startpoint
    row_=startpoint_row_;
    col_=startpoint_col_;
    // set the lenght of the way starting at the startpoint
    way_lenght_=getIntRandomValue(min_way_lenght_, max_way_lenght_);
    // set the way direction from the startpoint
    way_direction_.setDirection(Direction.DIRECTION_UP);
    // calculate way
    buildWay();

    while(labyrinth_field_.getNumWayCells()<num_way_cells_ && loops_<max_loops_)
    {
      // set the lenght of the way
      way_lenght_=getIntRandomValue(min_way_lenght_, max_way_lenght_);

      // if build_angle_==true allow  angles
      if(build_angle_==true)
      {
        // set the forbidden way direction

        way_direction_.randomizeNextDirection();
      }
      // calculate way
      buildWay();
    }
  }

//------------------------------------------------------------------------------
/**
 *
 *
 */
  private void buildWay()
    throws IllegalArgumentException, IllegalDirectionException
  {
    if(way_lenght_==-1)
      throw(new IllegalArgumentException(
        "way_lenght_ net set"));

/*    if(way_direction_==-1)
      throw(new IllegalArgumentException(
        "way_direction_ net set"));
*/
    if(row_==-1)
      throw(new IllegalArgumentException(
        "row_ net set"));
    if(col_==-1)
      throw(new IllegalArgumentException(
        "col_ net set"));
/*    if(new_point_==true)
      throw(new IllegalArgumentException(
        "new_point_ is true"));
*/
    // Array whith all contitions
    //Array conditions_array[][]={row_ = true|col_= false, ++ = true|-- = false}
    boolean conditions_array[][]={{true, false},   //way_direction_=1  to the top
                                  {false, true},   //way_direction_=2  to the right
                                  {true, true},    //way_direction_=3  to the botom
                                  {false, false}}; //way_direction_=4  to the left

    for(int way_lenght_counter=way_lenght_;way_lenght_counter>0;way_lenght_counter--)
    {
      if(new_point_==true && build_tree_==true)
        setNewPoint();

      int way_direction_index;
      switch (way_direction_.getDirection())
      {
        case Direction.DIRECTION_UP:
          way_direction_index = 0; break;
        case Direction.DIRECTION_RIGHT:
          way_direction_index = 1; break;
        case Direction.DIRECTION_DOWN:
          way_direction_index = 2; break;
        case Direction.DIRECTION_LEFT:
          way_direction_index = 3; break;
        default:
          way_direction_index = 0;
      }

      if(conditions_array[way_direction_index][0]==true) //row_
      {
        if(conditions_array[way_direction_index][1]==true) //++
        {
          if(cellToWay(row_+1,col_,row_+2,col_)==false)
            break;
          row_++;
          //max_ways_++;
        }
        else //--
        {
          if(cellToWay(row_-1,col_,row_-2,col_)==false)
            break;
          row_--;
          //max_ways_++;
        }
      }
      else //col_
      {
        if(conditions_array[way_direction_index][1]==true) //++
        {
          if(cellToWay(row_,col_+1,row_,col_+2)==false)
            break;
          col_++;
          //max_ways_++;
        }
        else //--
        {
          if(cellToWay(row_,col_-1,row_,col_-2)==false)
            break;
          col_--;
          //max_ways_++;
        }
      }
    }
    loops_++;
  }

//------------------------------------------------------------------------------
/**
 *
 *
 */
  private boolean cellToWay(int row, int col, int row2, int col2)
  {
    // return false if the cell is not in the field
    if(row<1 ||col<1 || row>max_row_-1 || col>max_col_-1)
      return false;

    //Cell cell;
    // do not allow loops
    if(build_loop_==false)
    {
      if(max_row_<row2|| row2<0 || max_col_<col2 || col2<0)
        return false;
      //cell=(Cell)labyrinth_field_.getElement(row2,col2);
      if(labyrinth_field_.isWay(row2,col2)==true)
      {
        new_point_=true;
        return false;
      }
    }

    // do not allow places
    if(build_places_==false)
    {
      if(row==row2)
      {
        if(row-1<0 || row+1>max_row_)
          return false;
        //cell=(Cell)labyrinth_field_.getElement(row-1,col);
        if(labyrinth_field_.isWay(row-1,col)==true)
        {
          new_point_=true;
          return false;
        }
        //cell=(Cell)labyrinth_field_.getElement(row+1,col);
        if(labyrinth_field_.isWay(row+1,col)==true)
        {
          new_point_=true;
          return false;
        }
      }
      else //col==col2
      {
        if(col-1<0 || col+1>max_col_)
          return false;
        //cell=(Cell)labyrinth_field_.getElement(row,col-1);
        if(labyrinth_field_.isWay(row,col-1)==true)
        {
          new_point_=true;
          return false;
        }
        //cell=(Cell)labyrinth_field_.getElement(row,col+1);
        if(labyrinth_field_.isWay(row,col+1)==true)
        {
          new_point_=true;
          return false;
        }
      }
    }

    // get the next cell
    //cell=(Cell)labyrinth_field_.getElement(row,col);

    // if the cell is a wall then convert it to a way
    if(labyrinth_field_.isWall(row,col)==true)
    {
      //System.out.println("isWall");
      //cell.convertToWay();
      labyrinth_field_.convertToWay(row,col);
    }
    // cell is a way -> buildet loop
    else
    {
      // buildet loop
      //System.out.println("!isWall");
      new_point_=true;
      loops_++;
      return false;
    }
    return true;
  }

//------------------------------------------------------------------------------
/**
 *
 *
 */
  private void setNewPoint()
  {
    int row=-1;
    int col=-1;
    Cell cell;

    if(randomwaycoordinates_.findRandomWayCoordinates(labyrinth_field_, labyrinth_field_.getNumWayCells())==true)
    {
      row=randomwaycoordinates_.getRandomWayRowCoordinate();
      col=randomwaycoordinates_.getRandomWayColCoordinate();
      //cell=(Cell)labyrinth_field_.getElement(row,col);
      if(labyrinth_field_.isWay(row,col)==true)
      {
        row_=row;
        col_=col;
        way_direction_.randomizeDirection();
        new_point_=false;
      }
    }
  }

//------------------------------------------------------------------------------
/**
 *
 *
 */
  public void setDiamonds()
  {
    int row=-1;
    int col=-1;
    //Cell cell;

    while(labyrinth_field_.getNumDiamonds()<num_diamonds_ && labyrinth_field_.getNumDiamonds()<labyrinth_field_.getNumWayCells())
    {
      if(randomwaycoordinates_.findRandomWayCoordinates(labyrinth_field_, labyrinth_field_.getNumWayCells())==true)
      {
        row=randomwaycoordinates_.getRandomWayRowCoordinate();
        col=randomwaycoordinates_.getRandomWayColCoordinate();
        //cell=(Cell)labyrinth_field_.getElement(row,col);
        if(labyrinth_field_.containsDiamond(row,col)==false && labyrinth_field_.isWay(row,col)==true && labyrinth_field_.isStartpoint(row,col)==false)
        {
          //cell.setDiamond();
          //diamonds_++;
          labyrinth_field_.setDiamond(row, col);
        }
      }
    }
  }

//------------------------------------------------------------------------------
/**
 *
 *
 */
  public LabyrinthField getLabyrinthField()
  {
    return labyrinth_field_;
  }

//------------------------------------------------------------------------------
/**
 * standard toString method for debugging
 * @return info about the labyrinth field in string-format
 */

  public String toString()
  {
    return("CreateLabyrinth: num_diamonds_ = " + num_diamonds_ +
           ", num_way_cells_ = " + num_way_cells_ +
           ", startpoint_row_ = " + startpoint_row_ +
           ", startpoint_col_ = " + startpoint_col_ +
           ", build_angle_ = " + build_angle_ +
           ", build_tree_ = " + build_tree_ +
           ", build_loop_ = " + build_loop_ +
           ", build_places_ = " + build_places_ +
           ", min_way_lenght_ = " + min_way_lenght_ +
           ", max_way_lenght_ = " + max_way_lenght_ +
           super.toString());
  }

  public int getStartpointRow()
  {
    return startpoint_row_;
  }
  public int getStartpointCol()
  {
    return startpoint_col_;
  }


}
