package com.goatsandtigers.tictactoe;

import java.awt.Point;
import java.util.LinkedList;
import javax.swing.JOptionPane;
import com.goatsandtigers.minimax.VanillaMinimax;

public class TicTacToeBoard extends VanillaMinimax implements Cloneable
{
    public static final char EMPTY_SQUARE   = ' ';
    public static final char NOUGHT         = 'O';
    public static final char CROSS          = 'X';
    public static final char INVALID_SQUARE = '?';
    private char[][] square                 = new char[3][3];

    public TicTacToeBoard()
    {
        for(int i = 0; i < 3; i++)
        {
            for(int j = 0; j < 3; j++)
            {
                square[i][j] = TicTacToeBoard.EMPTY_SQUARE;
            }
        }
    }

    /**
     * Returns the contents of the square at a given co-ordinate
     * @param x x co-ordinate of the square to retrieve
     * @param y y co-ordinate of the square to retrieve
     * @return either TicTacToeBoard.EMPTY_SQUARE, TicTacToeBoard.NOUGHT or
     * TicTacToeBoard.CROSS if x and y are both between 0 and 2 inclusive,
     * otherwise TicTacToeBoard.INVALID_SQUARE.
     */
    public char getSquare(int x, int y)
    {
        try
        {
            return square[x][y];
        }
        catch(Exception e)
        {
            return TicTacToeBoard.INVALID_SQUARE;
        }
    }

    /**
     * Checks for three noughts in a straight line.
     * @return true if noughts has won, false otherwise.
     */
    private boolean isVictoryForNoughts()
    {
        if(square[0][0] == TicTacToeBoard.NOUGHT)
        {
            if(square[1][0] == TicTacToeBoard.NOUGHT && square[2][0] == TicTacToeBoard.NOUGHT)
            {
                return true;
            }
            if(square[0][1] == TicTacToeBoard.NOUGHT && square[0][2] == TicTacToeBoard.NOUGHT)
            {
                return true;
            }
            if(square[1][1] == TicTacToeBoard.NOUGHT && square[2][2] == TicTacToeBoard.NOUGHT)
            {
                return true;
            }
        }
        if(square[1][0] == TicTacToeBoard.NOUGHT && 
           square[1][1] == TicTacToeBoard.NOUGHT &&
           square[1][2] == TicTacToeBoard.NOUGHT)
        {
            return true;
        }
        if(square[0][1] == TicTacToeBoard.NOUGHT && 
           square[1][1] == TicTacToeBoard.NOUGHT &&
           square[2][1] == TicTacToeBoard.NOUGHT)
        {
            return true;
        }
        if(square[2][0] == TicTacToeBoard.NOUGHT && 
           square[2][1] == TicTacToeBoard.NOUGHT &&
           square[2][2] == TicTacToeBoard.NOUGHT)
        {
            return true;
        }
        if(square[0][2] == TicTacToeBoard.NOUGHT && 
           square[1][2] == TicTacToeBoard.NOUGHT &&
           square[2][2] == TicTacToeBoard.NOUGHT)
        {
            return true;
        }
        
        if(square[0][2] == TicTacToeBoard.NOUGHT && 
           square[1][1] == TicTacToeBoard.NOUGHT &&
           square[2][0] == TicTacToeBoard.NOUGHT)
        {
            return true;
        }
        
        return false;
    }

    /**
     * Checks for three crosses in a sraight line.
     * @return true if crosses has won, false otherwise.
     */
    private boolean isVictoryForCrosses()
    {
        if(square[0][0] == TicTacToeBoard.CROSS)
        {
            if(square[1][0] == TicTacToeBoard.CROSS && square[2][0] == TicTacToeBoard.CROSS)
            {
                return true;
            }
            if(square[0][1] == TicTacToeBoard.CROSS && square[0][2] == TicTacToeBoard.CROSS)
            {
                return true;
            }
            if(square[1][1] == TicTacToeBoard.CROSS && square[2][2] == TicTacToeBoard.CROSS)
            {
                return true;
            }
        }
        if(square[1][0] == TicTacToeBoard.CROSS && 
           square[1][1] == TicTacToeBoard.CROSS &&
           square[1][2] == TicTacToeBoard.CROSS)
        {
            return true;
        }
        if(square[0][1] == TicTacToeBoard.CROSS && 
           square[1][1] == TicTacToeBoard.CROSS &&
           square[2][1] == TicTacToeBoard.CROSS)
        {
            return true;
        }
        if(square[2][0] == TicTacToeBoard.CROSS && 
           square[2][1] == TicTacToeBoard.CROSS &&
           square[2][2] == TicTacToeBoard.CROSS)
        {
            return true;
        }
        if(square[0][2] == TicTacToeBoard.CROSS && 
           square[1][2] == TicTacToeBoard.CROSS &&
           square[2][2] == TicTacToeBoard.CROSS)
        {
            return true;
        }
        
        if(square[0][2] == TicTacToeBoard.CROSS && 
           square[1][1] == TicTacToeBoard.CROSS &&
           square[2][0] == TicTacToeBoard.CROSS)
        {
            return true;
        }
        
        return false;
    }

    /**
     * Gives the current position a score that can be used by the
     * Minimax algorithm.
     * @return VanillaMinimax.MINI_HAS_WON if noughts has won,
     * VanillaMinimax.MAX_HAS_WIN if crosses has won,
     * zero otherwise.
     * @see com.goatsandtigers.minimax.VanillaMinimax#getCurrentScore()
     */
    public int getCurrentScore()
    {
    	if(this.isVictoryForNoughts())
        {
            return MINI_HAS_WON;
        }
    	else if(this.isVictoryForCrosses())
        {
            return MAX_HAS_WON;
        }
        else
        {
            return 0;
        }
    }
            
    public Object clone()
    {
        try
        {
            TicTacToeBoard clone = (TicTacToeBoard)super.clone();

            clone.square = new char[3][3];
            for(int i = 0; i < 3; i++)
            {
                for(int j = 0; j < 3; j++)
                {
                    clone.square[i][j] = this.square[i][j];
                }
            }
            return clone;
        }
        catch(Exception e)
        {
            return null;
        }
    }

    public LinkedList<Point> listAllLegalMoves()
    {
        LinkedList<Point> list = new LinkedList<Point>();
        for(int i = 0; i < 3; i++)
        {
            for(int j = 0; j < 3; j++)
            {
                if(square[i][j] == TicTacToeBoard.EMPTY_SQUARE)
                {
                    list.add(new Point(i, j));
                }
            }
        }
        return list;
    }

    /**
     * 
     * @see com.goatsandtigers.minimax.VanillaMinimax#moveAction(java.lang.Object)
     */
    public void moveAction(Object move)
    {
        Point m = (Point)move;
        boolean isNoughtsTurn = this.getPlayer() == -1;
        square[m.x][m.y] = isNoughtsTurn ? TicTacToeBoard.NOUGHT : TicTacToeBoard.CROSS;
    }

    /**
     * Display a message informing the user that the game has ended without
     * either side being victorious.
     */
    public void staleMate()
    {
        JOptionPane.showMessageDialog(null, "It's a draw!");
    }
}