package fr.iut_fbleau.GameAPI;

import java.util.NoSuchElementException;
import java.util.Iterator;
import java.util.Deque;

/**
 * An abstract class implementing the interface IBoard.
 *
 * It is used to implement some things to do with the update of the next player
 * which is the same for all turn taking games using a round robin and provides
 * also a minimal implantation of the history mechanism.
 *
 * The current implantation works only for two players.
 *
 * 
 */
public abstract class AbstractBoard implements IBoard{

    // the player, the turn of which it is to play.
    private Player currentPlayer ;

    // used as a stack.
    private  Deque<AbstractPly> history;


    // constructeur à appeler dans le constructeur d'un fils concret avec super.
    public AbstractBoard(Player p, Deque<AbstractPly> h){
	this.currentPlayer = p;
	this.history = h;
    }

    
    /**
     * set current player to the other player.
     * 
     */
    protected void setNextPlayer(){
	if (this.currentPlayer==Player.PLAYER1){
	    this.currentPlayer= Player.PLAYER2;
	}
	else
	    this.currentPlayer= Player.PLAYER1;
    }

    /**
     * add the given ply to history so that it becomes the last one.
     * 
     */
    protected void addPlyToHistory(AbstractPly c){
	this.history.addFirst(c);
    }


    /**
     * removes the last ply from history.
     * 
     *@throws NoSuchElementException if empty history.
     * @return the last ply from history.
     */
    protected AbstractPly removePlyFromHistory(){
	return this.history.removeFirst();
    }

    /**
     * @return the last ply from history or null if none.
     */
    protected AbstractPly getLastPlyFromHistory(){
	return this.history.peekFirst();
    }

	
    /**
     * @return the current player
     */
    public Player getCurrentPlayer(){
	return this.currentPlayer;
    }

    /**
     * Returns the game status
     *
     * @return true iff the game is over
     */
    public abstract boolean isGameOver();

    /**
     *  
     * @return the result (null if not over)
     */
    public abstract Result getResult();

    
    /**
     * checker of the legality of a ply from this position
     *
     * @return true iff the ply is legal
     */
    public abstract boolean isLegal(AbstractPly c);
   
    
    /**
     * constructor of Iterator over legal moves from this position
     *
     * @return the iterator
     */
    public abstract Iterator<AbstractPly> iterator();

    
    
    /**
     * Plays a given move on the plateau.
     *
     * A daughter class should call super of this last if the move has been done.
     *
     * @throws IllegalArgumentException if the move is always illegal (say from the wrong game)
     * @throws IllegalStateException if the move is not legal in this position
     *
     * @param AbstractPly to be played
     *
     */
    public void doPly(AbstractPly c){
	// Should update history 
	this.addPlyToHistory(c);
	// swap players
	this.setNextPlayer();
    }

    /**
     * Resets the plateau to the position before the last move.
     *
     * A daughter class should probably overwrite this class, but use this code as a base, as it will need to know the ply that needs to be undone.
     *
     * @throws IllegalStateException if nothing to undo in history
     *
     */
    public void undoPly(){
	AbstractPly p;
	try{
	    p=this.removePlyFromHistory();
	   }
	catch(NoSuchElementException e) {
	    throw new IllegalStateException("No ply in history, nothing can be undone");
	}
	// swap players (works for two players, fairly dangerous if more players, great for a test exam).
	this.setNextPlayer();
    }

    /**
     * creates a safe copy of the board.
     *
     * @return the copy
     */    
    public abstract IBoard safeCopy();
}
