/**
 * @file Player.java
 *
 * @author
 *    Christos Choutouridis
 *    <cchoutou@ece.auth.gr>
 *    AEM:8997
 */

package host.labyrinth;

/**
 * @brief
 *    This class represents the game's player
 */
class Player {
   /** @name Constructors */
   /** @{ */

   /**
    * Create a new player and put him at the row-column coordinates 
    * @param id         The id of the player
    * @param name       The name of the player
    * @param champion   Flag to indicate if a player is a `champion`
    * @param board      Reference to the board of the game
    * @param row        The row coordinate of initial player position
    * @param column     The column coordinate of initial player's position
    */
   Player(int id, String name, boolean champion, Board board, int row, int column) {
      this.playerId  = id;
      this.name      = name;
      this.board     = board;
      this.score     = 0;
      this.x         = column;
      this.y         = row;
      this.champion  = champion;
   }

   /**
    * Create a new player and put him at the row-column coordinates 
    * @param id         The id of the player
    * @param name       The name of the player
    * @param champion   Flag to indicate if a player is a `champion`
    * @param board      Reference to the board of the game
    * @param tileId     The tileId coordinate of player's initial position
    */
   Player(int id, String name, boolean champion, Board board, int tileId) {
      this.playerId  = id;
      this.name      = name;
      this.board     = board;
      this.score     = 0;
      this.x         = Position.toCol(tileId);
      this.y         = Position.toRow(tileId);
      this.champion  = champion;
   }
   /** @} */

   /** @name Player main application interface */
   /** @{ */

   /**
    * Player's move.
    *
    * A player first throws a dice to get a random direction. Then checks if the direction
    * is walkable. If it is, then goes to that tile and update player's data.
    * If the player is a champion then he also picks up a possible supply from the tile.
    *
    * @param id   The id of the starting tile.
    * @return     An array containing player's final position and possible supply of that position.
    *             The array format is:
    * <ul>
    * <li> int[0]: The tileId of the final player's position.
    * <li> int[1]: The row of the final player's position.
    * <li> int[2]: The column of the final player's position.
    * <li> int[1]: The supplyId in case player picked one (Const.noSupply otherwise).   
    * </ul>
    */
   int[] move(int id) {
      // Initialize return array with the current data
      int[] ret = {id, Position.toRow(id), Position.toCol(id), Const.noSupply};

      int diceDirection = board.dice();            // throw the dice
      if (board.isWalkable(id, diceDirection)) {   // The result is walkable
         // Get next tile
         Position next = new Position(Position.toRow(id), Position.toCol(id), diceDirection);
         ret[0] = next.getId();                    // Update player's and return data
         ret[1] = y = next.getRow();
         ret[2] = x = next.getCol();
         // In case of a champion player, try also to pick a supply
         if (champion && (ret[3] = board.tryPickSupply(next.getId())) != Const.noSupply) {
            ++score;                               // keep score
            System.out.println(name + ":\t*Found a supply. [score: " + score + "]");
         }
      }
      else
         System.out.println(name + ":\t*Can not move.");
      return ret;
   }

   /** Utility to access player's tileID */
   int playerTileId()   { return Position.toID(y, x); }
   /** Utility to access player's row position (row coordinate) */
   int playerRow()      { return y; }
   /** Utility to access player's column position (column coordinate) */
   int playerCol()      { return x; }
   /** @} */

   /**
    * @name Accessor/Mutator interface
    * @note
    *    Please consider not to use mutator interface. Its the abstraction killer :(
    *    We have added a bit of logic however, in order to make it a bit more safe.
    */
   /** @{ */
   int getPlayerId ()   { return playerId; }
   String getName()     { return name; }
   Board getBoard ()    { return board; }
   int getScore ()      { return score; }
   int getX()           { return x; }
   int getY()           { return y; }
   boolean getChampion(){ return champion; }

   void setPlayerId(int id)   { playerId = id; }
   void setName(String name)  { this.name = name; }
   void setBoard (Board board){ this.board = board; }
   void setScore(int score)   { this.score = score; }
   void setX(int x) {
      assert (x >= 0 && x< Session.boardSize) : "X(column) coordinate must be in the range [0, Session.boardSize)";
      this.x = x;
   }
   void setY(int y) {
      assert (y >= 0 && y< Session.boardSize) : "Y(row) coordinate must be in the range [0, Session.boardSize)";
      this.y = y;
   }
   void setChampion (boolean champion) {
      this.champion = champion;
   }

   /** @} */
   
   /** @name Class data */
   /** @{ */
   private int    playerId;   /**< The unique identifier of the player */
   private String name;       /**< The name of the player */ 
   private Board  board;      /**< Reference to the session's boards */
   private int    score;      /**< The current score of the player */
   private int    x;          /**< The column coordinate of the player on the board */
   private int    y;          /**< The row coordinate of the player on the board */
   private boolean champion;  /**< Champion indicate a player who plays against the Minotaur */
   /** @} */
}
