package com.horstmann.ai;

import edu.lhup.ai.*;
import edu.lhup.ai.tictactoe.Board;

import java.util.*;

/**
 * An abstract board that implements as many methods of the IBoard interface as possible.
 *
 * @author Cay Horstmann
 */
public abstract class AbstractBoard implements IBoard
{
    /**
     * Sets this board to an initial state.
     */
    public abstract void init();

    /**
     * Parses a move in string format.
     * @param strMove the move in string format
     * @return the move represented by this string
     * @throws StateException if the move is illegal
     */
    public abstract IMove parseMove(String strMove) throws StateException;
    
    /**
     * Updates the board to the state after this move. 
     * @param move the move
     * @throws StateException if the move is illegal
     */
    public abstract void doMove(IMove move) throws StateException;
    
    /**
     * Undoes the given move, reverting the board to the state before this move. 
     * @param move the move to be undone
     */
    public abstract void undoMove(IMove move);

    /**
     * Gets the index of the player that has the current turn.
     * @return the index of the player that has the current turn
     */
    public int getTurn()
    {
        return m_turn;
    }
        
    public void setPlayers(IPlayer[] players)
	{
	    m_players = Arrays.copyOf(players, players.length);
	}

	public IPlayer[] getPlayers()
	{
		return m_players;
	}

	public Iterator playerIterator() 
	{
		return new Iterator() 
		{
		    public boolean hasNext()
		    {
		        return getWinner() == null;
		    }

		    public Object next()
		    {
		        return m_players[m_turn];
		    }

		    public void remove()
		    {
		        throw new UnsupportedOperationException();
		    }

		};
	}

	public IMove peekMove()
	{
		return (m_moveStack.size() == 0) ? null : (IMove)m_moveStack.getFirst();
	}

	public void pushMove(String strMove) throws StateException 
	{
	    pushMove(parseMove(strMove));
	}
		
	public void pushMove(IMove move) throws StateException
	{
	    m_moveStack.addFirst(move);
		doMove(move);
		m_turn = (m_turn + 1) % m_players.length;
	}

	public IMove popMove()
	{
		IMove move = (IMove) m_moveStack.removeFirst();		
		m_turn = (m_turn + m_players.length - 1) % m_players.length;
        undoMove(move);
		return move;
	}

	public IPiece[][] getBoard() 
	{ 
		return null; 
	}
	
    public int getState()
    {
        return 0;
    }
	
	public void resetState()
	{
		init();
		m_turn = 0;
		m_moveStack.clear();

        //juggle who goes first...
		ArrayList<IPlayer> temp = new ArrayList<IPlayer>(Arrays.asList(m_players));
		Collections.shuffle(temp);
		for (int i = 0; i < m_players.length; i++) 
		{
		    m_players[i] = (IPlayer) temp.get(i);
		}
	}

	@SuppressWarnings("unchecked")
	public void moves(Collection col)
	{
		col.clear();
		Iterator moveIterator = moveIterator();
		while (moveIterator.hasNext())
		{
			col.add(moveIterator.next());
		}
	}

	public String getDescription()
	{
		return getShortDescription();
	}

	private int m_turn;
	private final LinkedList<IMove> m_moveStack = new LinkedList<IMove>();
	private IPlayer[] m_players;
}
