
package PrintGame;

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_;

  // 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 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(LabyrinthField labyrinth_field)
  {
    labyrinth_field_ = labyrinth_field;
    int rows=labyrinth_field_.getNumRows();
    int cols=labyrinth_field_.getNumCols();
    random_generator_ = new Random();
    randomwaycoordinates_ = new RandomWayCoordinates(rows, cols);

    num_diamonds_=0;
    num_way_cells_=0;
    max_row_=rows-1;
    max_col_=cols-1;

    build_angle_=false;
    build_tree_=false;
    build_loop_=false;
    // it is not able to build a palce wirhout to allow to build a loop
    build_places_=false;

    //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;

    way_lenght_=-1;

    if(labyrinth_field_.isStartpoint()==false)
    {
    //System.out.println("startpoint==talse");
      labyrinth_field_.convertToStartpoint((rows-1), (cols-1)/2);
      try
      {
        if(labyrinth_field_.isStartDirection()==false)
        {
          Direction direction = new Direction();
          direction.setDirection(Direction.DIRECTION_UP);
          labyrinth_field_.setStartDirection(direction);
        }
          way_direction_ = new Direction();
          way_direction_.setDirection(labyrinth_field_.getStartDirection().getDirection());
          //way_direction_=labyrinth_field_.getStartDirection();
      }
      catch(IllegalDirectionException exc)
      {

      }
      row_=labyrinth_field_.getStartpointRow();
      col_=labyrinth_field_.getStartpointCol();
      new_point_=false;
    }
    else if(labyrinth_field_.getNumWayCells()==1 && labyrinth_field_.isStartpoint()==true)
    {
    //System.out.println("startpoint==true + waycell" + way_direction_);
      //way_direction_=labyrinth_field_.getStartDirection();
      try
      {
      way_direction_ = new Direction();
      way_direction_.setDirection(labyrinth_field_.getStartDirection().getDirection());
      }
      catch(IllegalDirectionException exc)
      {

      }
      row_=labyrinth_field_.getStartpointRow();
      col_=labyrinth_field_.getStartpointCol();
      new_point_=false;
    }
    else
    {
    //System.out.println("many waycell" + way_direction_);
      row_=-1;
      col_=-1;
      try
      {
        way_direction_=new Direction();
        //way_direction_.setDirection(Direction.DIRECTION_UP);
        way_direction_.randomizeNextDirection();
      }
      catch(IllegalDirectionException exc)
      {

      }
      new_point_=true;
    }
    //System.out.println("way_direction_: " + way_direction_);
  }


//------------------------------------------------------------------------------
/**
 * 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;
  }

//------------------------------------------------------------------------------
/**
 * 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;
  }

  public void setMinWayLenght(int min_way_lenght)
    throws IllegalArgumentException
  {
    if (min_way_lenght < 0)
      throw(new IllegalArgumentException(
        "min_way_lenght must be >= 0"));
    min_way_lenght_ = min_way_lenght;
  }

  public void setMaxWayLenght(int max_way_lenght)
    throws IllegalArgumentException
  {
    if (max_way_lenght < 0)
      throw(new IllegalArgumentException(
        "max_way_lenght must be >= 0"));
    max_way_lenght_ = max_way_lenght;
  }

  public void setBuildAngles(int build_angle)
    throws IllegalArgumentException
  {
    if (build_angle < 0)
      throw(new IllegalArgumentException(
        "build_angle must be >= 0"));
    if(build_angle>0)
      build_angle_=true;
    else
      build_angle_=false;
  }

  public void setBuildTrees(int build_tree)
    throws IllegalArgumentException
  {
    if (build_tree < 0)
      throw(new IllegalArgumentException(
        "build_tree must be >= 0"));
    if(build_tree>0)
      build_tree_=true;
    else
      build_tree_=false;
  }

  public void setBuildPlaces(int build_place)
    throws IllegalArgumentException
  {
    if (build_place < 0)
      throw(new IllegalArgumentException(
        "build_place must be >= 0"));
    if(build_place>0)
      build_places_=true;
    else
      build_places_=false;
  }

  public void setBuildLoops(int build_loop)
    throws IllegalArgumentException
  {
    if (build_loop < 0)
      throw(new IllegalArgumentException(
        "build_loop must be >= 0"));
    if(build_loop>0)
      build_loop_=true;
    else
      build_loop_=false;
  }

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

//------------------------------------------------------------------------------
/**
 *
 *
 */
  public void calculateWays()
  {
    // 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
    if(new_point_==true)
      setNewPoint();
    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
        try
        {
          way_direction_.randomizeNextDirection();
        }
        catch(IllegalDirectionException exc)
        {

        }
      }
      // calculate way
      buildWay();
    }
  }

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

/*    if(way_direction_==-1)
      throw(new IllegalArgumentException(
        "way_direction_ net set"));
*/
    if(row_==-1)
      throw(new IllegalArgumentException(
        "row_ not set"));
    if(col_==-1)
      throw(new IllegalArgumentException(
        "col_ not 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

    try
    {
      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_++;
          }
        }
      }
    }
    catch(IllegalDirectionException exc)
    {

    }
    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_)==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_)==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_ +
           ", 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());
  }



}
