package com.goatsandtigers.ripvanwinkle;

import java.awt.Point;
import java.awt.Rectangle;
import java.util.LinkedList;

import javax.swing.JOptionPane;

import com.goatsandtigers.minimax.MinimaxAlphaBeta;

public abstract class RipVanWinkleBoard extends MinimaxAlphaBeta
{
	private   long        isSkittleStillStanding;
	protected Rectangle[] skittleRect         = null;
	protected int         numSkittles;
	private   long        skittlesHoveredOver = 0;
	private   long        lastMove            = 0;

	public long getSkittlesHoveredOver()
	{
		return this.skittlesHoveredOver;
	}

	public boolean isSkittleHoveredOver(int index)
	{
		return (this.skittlesHoveredOver & (1L << index)) != 0;
	}

	public boolean isGameOver()
	{
		return this.isSkittleStillStanding == 0;
	}

	public void knockOverHoveredOverSkittles()
	{
		long move = 0;
		for(int i = 0; i < this.numSkittles; i++)
		{
			if(this.isSkittleHoveredOver(i))
			{
				move |= (1L << i);
			}
		}
		this.doMove(new Long(move));
		this.skittlesHoveredOver = 0;
	}

	public void updateSkittlesHoveredOver(Point mousePos)
	{
		this.skittlesHoveredOver = 0;
		for(int i = 0; i < this.numSkittles; i++)
		{
			if(this.isSkittleStillStanding(i) && this.skittleRect[i].contains(mousePos))
			{
				this.skittlesHoveredOver |= (1L << i);
			}
		}
	}

	public int getNumSkittles()
	{
		return this.numSkittles;
	}

	public int getNumSkittlesStillStanding()
	{
		int numSkittlesStillStanding = 0;
		for(int i = 0; i < this.numSkittles; i++)
		{
			if(this.isSkittleStillStanding(i))
			{
				numSkittlesStillStanding++;
			}
		}
		return numSkittlesStillStanding;
	}

	public void standSkittleUp(int index)
	{
		this.isSkittleStillStanding |= (1L << index);
	}

	public void knockSkittleDown(int index)
	{
		this.isSkittleStillStanding &= ~(1L << index);
	}

	public boolean isSkittleStillStanding(int index)
	{
		return (this.isSkittleStillStanding & (1L << index)) != 0;
	}

	public void mirrorLastMove()
	{
		long newMove = 0;
		for(int i = 0; i < this.getNumSkittles(); i++)
		{
			int oppositeSkittle = this.getNumSkittles() - i - 1;
			if((this.lastMove & (1L << i)) != 0)
			{
				newMove |= (1L << oppositeSkittle);
			}
		}
		this.doMove(new Long(newMove));
	}

	public boolean canMirrorLastMove()
	{
		boolean canKnockDownAtLeastOneSkittle = false;
		/*
		 * Iterate through all skittles (standing or otherwise).
		 */
		for(int i = 0; i < this.getNumSkittles(); i++)
		{
			int oppositeSkittle = this.getNumSkittles() - i - 1;
			if((this.lastMove & (1L << i)) != 0)
			{
				/*
				 * If a skittle was knocked down in the last move and the
				 * skittle opposite it is not standing then it is not possible
				 * to mirror the last move.
				 */
				if(!this.isSkittleStillStanding(oppositeSkittle))
				{
					return false;
				}
				/*
				 * If only the middle skittle was knocked down then the move
				 * cannot be mirrored.
				 */
				if(i != (int)(this.getNumSkittles() / 2))
				{
					canKnockDownAtLeastOneSkittle = true;
				}
			}
		}
		return canKnockDownAtLeastOneSkittle;
	}

	public void makeRandomMove()
	{
		LinkedList<Long> possibleMoves = this.listAllLegalMoves();
		int  random     = (int)(Math.random() * possibleMoves.size());
		Long randomMove = possibleMoves.get(random);
		this.doMove(randomMove);
	}

	public Rectangle getSkittleRectangle(int index)
	{
		try
		{
			return this.skittleRect[index];
		}
		catch(ArrayIndexOutOfBoundsException e)
		{
			return null;
		}
	}

	public int getCurrentScore()
	{
		if(this.isGameOver())
		{
			return this.getPlayer() == MinimaxAlphaBeta.MIN_TURN ?
					MinimaxAlphaBeta.MINI_HAS_WON : MinimaxAlphaBeta.MAX_HAS_WON;
		}
		else
		{
			return 0;			
		}
	}

	public LinkedList<Long> listAllLegalMoves()
	{
		LinkedList<Long> list = new LinkedList<Long>();
		/*
		 * Iterate through all skittles
		 */
		for(int i = 0; i < this.numSkittles; i++)
		{
			if(!this.isSkittleStillStanding(i))
			{
				continue;
			}

			/*
			 * Add a move knocking over this one skittle
			 */
			list.add(new Long(1L << i));

			/*
			 * See if this skittle's bounding rectangle intersects any other
			 * skittles' bounding rectangles
			 */
			Rectangle r1 = this.skittleRect[i];
			for(int j = i + 1; j < this.numSkittles; j++)
			{
				if(!this.isSkittleStillStanding(j))
				{
					continue;
				}
				Rectangle r2 = this.skittleRect[j];
				if(r1.intersects(r2))
				{
					/*
					 * If another skittles' bounding rectangle does in fact
					 * intersect this one's then add a move knocking over both
					 * of these skittles
					 */
					list.add(new Long((1L << i) | (1L << j)));
					//break;
				}
				
			}
		}
		/*
		 * Randomise list. This ensures that if all moves are equal then the
		 * first move generated will not be picked every time.
		 */
		for(int i = 0; i < list.size(); i++)
		{
			int random = (int)(Math.random() * list.size());
			Long tempMove = list.get(random);
			list.remove(random);
			list.add(tempMove);
		}

		/*
		 * Return the list.
		 */
		return list;
	}

	/**
	 * @param move a Long integer object. The bits of the long value
	 * represent the skittles to be knocked down
	 * @see com.goatsandtigers.minimax.MinimaxAlphaBeta#moveAction(java.lang.Object)
	 */
	public void moveAction(Object move)
	{
		this.lastMove = (Long)move;
		long skittlesToKnockDown     = this.lastMove; 
		this.isSkittleStillStanding &= ~skittlesToKnockDown;
	}

	@Override
	public void staleMate() {
		// TODO Auto-generated method stub
		
	}
}
