package PrintGame;

import java.awt.*;

/**
 * class representing a turing machine.
 */

public class TuringMachine
{
  public final static int FASTFORWARD = 100;
  public final static int NORMAL = 500;
  
  private InstructionList instruct_list_;
  private Robot robot_;
  private LabyrinthField lab_field_;
  private int num_steps_;
  private int num_taken_diamonds_;
  private int max_num_diamonds_;
  private int delay_time_;
  

   
//-----------------------------------------------------------------------------  
/**
 * method returns the conditions of robot's environment
 * @return info about the current condition
 */
  protected Condition getFieldConditions()
  {
    int current_row = robot_.getPosRow();
    int current_col = robot_.getPosCol();
    int cell_mark = lab_field_.getCellMark(current_row, current_col);
    boolean wall_ahead = false;
    boolean wall_left = false;
    boolean wall_right = false;
    boolean new_area = robot_.isNewArea();
    
    try
    {
      switch (robot_.getCurrentDirection().getDirection())
      {
        case Direction.DIRECTION_UP:
          wall_ahead = lab_field_.isWall(current_row-1, current_col);
          wall_left  = lab_field_.isWall(current_row, current_col-1);
          wall_right = lab_field_.isWall(current_row, current_col+1);
          break;
        case Direction.DIRECTION_DOWN:
          wall_ahead = lab_field_.isWall(current_row+1, current_col);
          wall_left  = lab_field_.isWall(current_row, current_col+1);
          wall_right = lab_field_.isWall(current_row, current_col-1);
          break;
        case Direction.DIRECTION_LEFT:
          wall_ahead = lab_field_.isWall(current_row, current_col-1);
          wall_left  = lab_field_.isWall(current_row+1, current_col);
          wall_right = lab_field_.isWall(current_row-1, current_col);
          break;
        case Direction.DIRECTION_RIGHT:
          wall_ahead = lab_field_.isWall(current_row, current_col+1);
          wall_left  = lab_field_.isWall(current_row-1, current_col);
          wall_right = lab_field_.isWall(current_row+1, current_col);
          break;
      }
    }
    catch (IllegalDirectionException ex)
    {
      System.err.println(ex.getMessage());
    }
    
    Condition temp_condition = new Condition(new_area, cell_mark, wall_left, wall_right, wall_ahead );
    
    return temp_condition;
  }

//-----------------------------------------------------------------------------  
/**
 * method performes the given action and checks if the robot crashes
 * @param action specifies what to do
 * @return true if no problems occure during the action, false if the robot is crashed
 */  
  protected boolean performAction(Action action)
  {
    int current_row = robot_.getPosRow();
    int current_col = robot_.getPosCol();
    boolean action_performed = false;
    
    
    try
    {
      switch (action.getMovingDirection())
      {
        case Action.MOVE_AHEAD:
          robot_.moveForward();
          break;
        case Action.MOVE_BACK:
          robot_.goBack();
          break;
        case Action.MOVE_LEFT:
          robot_.goLeft();
          break;
        case Action.MOVE_RIGHT:
          robot_.goRight();
          break;
      }
      
    }
    catch (IllegalDirectionException ex)
    {
      System.err.println(ex.getMessage());
    }     
    
    if(lab_field_.isWall(robot_.getPosRow(), robot_.getPosCol()))
    {
      robot_.setPos(current_row, current_col);
      
    }
    else
    {
      robot_.setNewArea(action.isNewArea());
      lab_field_.setCellMark(current_row, current_col, action.getCellMark());
      action_performed = true;
    }

    return action_performed;
  }

//-----------------------------------------------------------------------------  
/**
 *
 */    
  public void setInstructionList(InstructionList instruct_list)
  {
    instruct_list_ = instruct_list;
  }

//-----------------------------------------------------------------------------  
/**
 *
 */    
  public void setRobot(Robot robot)
  {
    robot_ = robot;
  }

//-----------------------------------------------------------------------------  
/**
 *
 */    
  public void setLabyrinthField(LabyrinthField lab_field)
  {
    lab_field_ = lab_field;
  }

 public void takeAndCalcDiamonds()
 {
   if(lab_field_.containsDiamond(robot_.getPosRow(), robot_.getPosCol()))
   {
     num_taken_diamonds_++;
     lab_field_.removeDiamond(robot_.getPosRow(), robot_.getPosCol());
   }
   
 }
  
//-----------------------------------------------------------------------------  
/**
 * method processes an instruction list
 * @param component window which contains the labyrinth field
 */    
  public void run(Component component)
    throws InterruptedException
  {
    boolean finished= false;
    Instruction current_instruction;
    int num_instructions = instruct_list_.size();
    Condition field_condition;
    max_num_diamonds_ = lab_field_.getNumDiamonds();
    num_taken_diamonds_ = 0;
    num_steps_ = 0;    
        
    
    while(finished == false)
    {
      field_condition = getFieldConditions();
      
/*      System.out.println("field conditions: "+field_condition.isWallLeft()  
                                            +field_condition.isWallRight()
                                            +field_condition.isWallAhead()
                                            +field_condition.getCellMark()  
                                            +field_condition.isNewArea());*/
    

      
      
      boolean condition_found = false;
      for(int index=0; index < num_instructions; index++)
      {
        current_instruction = instruct_list_.getInstructionAtPos(index);

/*   System.out.println("instruct conditions: "+current_instruction.getCondition().isWallLeft()  
                                            +current_instruction.getCondition().isWallRight()
                                            +current_instruction.getCondition().isWallAhead()
                                            +current_instruction.getCondition().getCellMark()  
                                            +current_instruction.getCondition().isNewArea());*/
    
        
        if(field_condition.equals(current_instruction.getCondition()))
        {
          Thread.sleep(delay_time_);
          if (!performAction(current_instruction.getAction()))
          {
            finished = true;
            System.out.println("Roboter ist in die Wand gekracht!");
          } 
          else
          {  
            takeAndCalcDiamonds();
            num_steps_++;

            if (!checkCellIsStartpoint())
            {
              finished = true;
            }
          }
          component.repaint();
          condition_found = true;
          break;
        }
      }
      if(condition_found == false)
      {
        finished = true;
        System.out.println("es wurde keine Condition gefunden, " +
        "das Programm ist nicht vollständig");
      }
    }
 
  }

//-----------------------------------------------------------------------------  
/**
 * method checks if the robot's position is the startpoint. 
 */  
  protected boolean checkCellIsStartpoint()
  {
    boolean cell_ok = true;
    int current_row = robot_.getPosRow();
    int current_col = robot_.getPosCol();
    if (lab_field_.isStartpoint(current_row, current_col) && (num_steps_ > 0))
    {
      cell_ok = false;
    }
    return cell_ok;
    
  }
  
  public void setSpeed(int delay_time)
  {
    delay_time_ = delay_time;
  }
  
  public int getNumSteps()
  {
    return num_steps_;
  }

  public int getNumTakenDiamonds()
  {
    return num_taken_diamonds_;
  }
}

