package jrummikub.control.turn;

import jrummikub.control.RoundControl.InvalidTurnInfo;
import jrummikub.model.GameSettings;
import jrummikub.model.IHand;
import jrummikub.model.IRoundState;
import jrummikub.model.ITable;
import jrummikub.util.IEvent;
import jrummikub.util.IEvent1;
import jrummikub.util.IEvent2;
import jrummikub.view.IView;

/**
 * Interface containing shared methods of human and computer turn control
 * 
 */
public interface ITurnControl {
	/**
	 * Start the turn
	 * 
	 * @param info
	 *            the current turn state
	 * 
	 * @param settings
	 *            the game settings
	 * @param view
	 *            view for user interaction.
	 */
	public void setup(TurnInfo info, GameSettings settings, IView view);

	/**
	 * Get the event that is emitted when the turn is over
	 * 
	 * @return end of turn event
	 */
	public IEvent2<IRoundState, InvalidTurnInfo> getEndOfTurnEvent();

	/**
	 * Emitted when the round is aborted and needs to be restarted
	 * 
	 * @return the event
	 */
	public IEvent getRedealEvent();

	/**
	 * Start the turn
	 */
	public void startTurn();

	/**
	 * Abort the turn
	 */
	public void abortTurn();

	/**
	 * Emitted in network when the table changes during player turn
	 * 
	 * @return the event
	 */
	public IEvent1<ITable> getTableUpdateEvent();

	/**
	 * The TurnInfo class encapsulates all information concerning the current
	 * turn
	 */
	public class TurnInfo {
		private IRoundState roundState;

		private ITable oldTable;
		private IHand oldHand;

		private ITable table;
		private IHand hand;

		private TurnMode turnMode;

		private boolean mayPause;

		/**
		 * Creates a new TurnInfo instance
		 * 
		 * @param roundState
		 *            current round state
		 * @param turnMode
		 *            the turn mode
		 * @param mayPause
		 *            player is allowed to paues
		 */
		public TurnInfo(IRoundState roundState, TurnMode turnMode,
				boolean mayPause) {
			this.roundState = roundState;

			oldTable = roundState.getTable();
			oldHand = roundState.getActivePlayer().getHand();

			this.table = (ITable) oldTable.clone();
			this.hand = (IHand) oldHand.clone();

			this.turnMode = turnMode;

			this.mayPause = mayPause;
		}

		/**
		 * Get the current round state
		 * 
		 * @return the current round state
		 */
		public IRoundState getRoundState() {
			return roundState;
		}

		/**
		 * Gets the table at the beginning of the turn
		 * 
		 * @return the table
		 */
		public ITable getOldTable() {
			return oldTable;
		}

		/**
		 * Gets the current player's hand at the beginning of the turn
		 * 
		 * @return the hand
		 */
		public IHand getOldHand() {
			return oldHand;
		}

		/**
		 * Gets the current table
		 * 
		 * @return the table
		 */
		public ITable getTable() {
			return table;
		}

		/**
		 * Gets the current player's hand
		 * 
		 * @return the hand
		 */
		public IHand getHand() {
			return hand;
		}

		/**
		 * Returns if the current player has laid out yet
		 * 
		 * @return if the player has laid out
		 */
		public boolean getLaidOut() {
			return roundState.getActivePlayer().getLaidOut();
		}

		/**
		 * Gets the current turn's mode
		 * 
		 * @return the turn mode
		 */
		public TurnMode getTurnMode() {
			return turnMode;
		}

		/**
		 * Return whether pausing is allowed during this turn
		 * 
		 * @return true if pause is allowed
		 */
		public boolean isMayPause() {
			return mayPause;
		}
	}
}