class Board
{
	private Brick board[];
	private AI ai;
	private int currentColor;
	private boolean foundOpposite;
	
	public Board(int startColor)
	{
		board = new Brick[64];
		ai = new AI();
		currentColor = startColor;

		for(int i = 0; i < 64; i++)
		{
			board[i] = new Brick(0, i);
		}
		
		board[27].setColor(1);
		board[28].setColor(-1);
		board[35].setColor(-1);
		board[36].setColor(1);
		
		//Test
		//board[4].setColor(-1); //Vit
		//board[20].setColor(1); //Vit
	}

	/***************************************************************************
	Metodnamn:	resetGame
	Argument:	startColor
	Returnerar:	Inget.
	Syfte:		En funktion för att starta om spelet.
	***************************************************************************/	
	public void resetGame(int startColor)
	{
		currentColor = startColor;

		for(int i = 0; i < 64; i++)
		{
			board[i].setColor(0);
		}
		
		board[27].setColor(1);
		board[28].setColor(-1);
		board[35].setColor(-1);
		board[36].setColor(1);
	}
	
	
	/***************************************************************************
	Metodnamn:	testEverything
	Argument:	Inga.
	Returnerar:	Inget.
	Syfte:		En gammal mysko-test-funktion
	***************************************************************************/		
	public void testEverything()
	{
		int num = 63;
		
		System.out.println("Hejhej, är det manchester eller jeans?!??");
		
		System.out.println(board[num].getNeighbour(0) + "\t" + board[num].getNeighbour(1) + "\t" + board[num].getNeighbour(2));
		System.out.println(board[num].getNeighbour(3) + "\t" + num + "\t" + board[num].getNeighbour(4));
		System.out.println(board[num].getNeighbour(5) + "\t" + board[num].getNeighbour(6) + "\t" + board[num].getNeighbour(7));		

		/*for(int i = 0; i < 8; i++)
		{
			System.out.println(i + ":  " + board[7].getNeighbour(i));
		}*/
	}

	/***************************************************************************
	Metodnamn:	getBrickColor
	Argument:	brickIndex:		Positionen på brickan som färgen ska kollas på.
	Returnerar:	Färgen på brickan.
	Syfte:		Att kolla upp färgen på en bricka.
	***************************************************************************/		
	public int getBrickColor(int brickIndex)
	{
		return (board[brickIndex]).getColor();
	}

	/***************************************************************************
	Metodnamn:	setCurrentColor
	Argument:	newColor:		Den nya färgen
	Returnerar:	Inget
	Syfte:		Att ändra färgen som spelas med just nu.
	***************************************************************************/			
	public void setCurrentColor(int newColor)
	{
		currentColor = newColor;
	}

	/***************************************************************************
	Metodnamn:	getCurrentColor
	Argument:	Inga.
	Returnerar:	Färgen som spelas med just nu.
	Syfte:		Att ta reda på vilken färg som spelas med för tillfället.
	***************************************************************************/			
	public int getCurrentColor()
	{
		return currentColor;
	}
	
	/***************************************************************************
	Metodnamn:	setBrick
	Argument:	brickIndex:		Position på spelplanen där man vill sätta ut en
								bricka.
	Returnerar:	true om brickan gick sätta ut, annars false
	Syfte:		Att sätta ut en bricka på spelplanen.
	***************************************************************************/		
	public boolean setBrick(int brickIndex)
	{
		boolean validMove;
		int currentNeighbour;

		validMove = false;
		//Kollar att brickan inte är upptagen
		if((board[brickIndex]).getColor() == 0)
		{
			//Kollar igenom alla riktningar
			for(int i = 0; i < 8; i++)
			{
				foundOpposite = false;
				if(setBrick(brickIndex, i))
					validMove = true;
			}
		}
		
		if(validMove)
			currentColor = currentColor * -1;

		return validMove;
	}
	
	/***************************************************************************
	Metodnamn:	setBrick
	Argument:	brickIndex:
				direction:
	Returnerar:	
	Syfte:		Rekursiv metod som endast används av ovanstående metod
	***************************************************************************/		
	private boolean setBrick(int brickIndex, int direction)
	{
		int currentNeighbour;
		
		currentNeighbour = (board[brickIndex]).getNeighbour(direction);
		//Kollar att grannen är inom brädet
		if((currentNeighbour >= 0) && (currentNeighbour <= 63))
		{
			//Kollar att grannen är av motsatt färg
			if((board[currentNeighbour]).getColor() == (currentColor * -1))
			{
				//Den är verkligen av motsatt färg :)
				foundOpposite = true; 
				//Låter den rekursera vidare
				if(setBrick(currentNeighbour, direction))
				{
					//Ändrar färgen om draget är godkänt
					board[brickIndex].setColor(currentColor);
					return true;
				}
				else
					return false;
			}
			//Kollar om grannen är av samma färg
			else if((board[currentNeighbour]).getColor() == currentColor)
			{
				//Kollar om den hittat en ruta av samma färg efter x antal rutor
				//av motsatt färg eller ej
				if(foundOpposite)
				{	
					(board[brickIndex]).setColor(currentColor);
					return true;
				}
				else
					return false;
			}
			//Kollar om grannen är tom efter x antal rutor
			else
				return false;
		}

		//Om den går utanför spelplanen
		return false;
	}

	/***************************************************************************
	Metodnamn:	isValidMove
	Argument:	brickIndex:		Position på spelplanen som ska kollas om en 
								bricka av viss färg kan placeras på.
				color:			Färgen på brickan.
	Returnerar:	true om brickan går att placera ut där, annars false
	Syfte:		Att testa om en bricka med en viss färg går att placera ut på en
				viss position på spelplanen.
	***************************************************************************/
	public boolean isValidMove(int brickIndex, int color)
	{
		int currentNeighbour;
		
		//Kollar att brickan inte är upptagen
		if((board[brickIndex]).getColor() == 0)
		{
			//Kollar igenom alla riktningar
			for(int i = 0; i < 8; i++)
			{
				foundOpposite = false;
				if(isValidMove(brickIndex, color, i))
					return true;				
			}
		}
		
		//Om rutan inte är godkänd
		return false;
	}
	
	/***************************************************************************
	Metodnamn:	isValidMove
	Argument:	brickIndex:
				color:
				direction:
	Returnerar:	
	Syfte:		Rekursiv metod som endast används av ovanstående metod.
	***************************************************************************/		
	private boolean isValidMove(int brickIndex, int color, int direction)
	{
		int currentNeighbour;
		
		currentNeighbour = (board[brickIndex]).getNeighbour(direction);
		//Kollar att grannen är inom brädet		
		if((currentNeighbour >= 0) && (currentNeighbour <= 63))
		{
			//Kollar om grannen är av motsatt färg
			if((board[currentNeighbour]).getColor() == (color * -1))
			{
				//Den är verkligen av motsatt färg :)
				foundOpposite = true;
				//Låter den rekursera vidare
				if(isValidMove(currentNeighbour, color, direction))
					return true;
				else
					return false;
			}
			//Kollar om grannen är av samma färg
			else if((board[currentNeighbour]).getColor() == color)
			{
				//Kollar om den hittat en ruta av samma färg efter x antal rutor
				//av motsatt färg eller ej
				if(foundOpposite)
					return true;
				else
					return false;
			}
			//Kollar om grannen är tom efter x antal rutor
			else
				return false;

		}

		//Om den går utanför spelplanen
		return false;
	}

	/***************************************************************************
	Metodnamn:	isGameOver
	Argument:	Inga.
	Returnerar:	1 om vit vunnit, -1 om svart vunnit, 0 om ej game over, 2
				om det är oavgjort
	Syfte:		Att ta reda på om det är game over eller ej.
	***************************************************************************/		
	public int isGameOver()
	{
		int whitePoints;
		int blackPoints;
		
		whitePoints = getPoints(1);
		blackPoints = getPoints(-1);
		
		//Om vit har 0 brickor har svart vunnit
		if(whitePoints == 0)
			return -1;
		
		//Om svart har 0 brickor har vit vunnit
		if(blackPoints == 0)
			return 1;

		for(int i = 0; i < 64; i++)
		{
			//Testar bara alla tomma rutor
			if(board[i].getColor() == 0)
			{
				if(isValidMove(i, 1) || isValidMove(i, -1))
					return 0;
			}
		}
		
		if(whitePoints > blackPoints)
			return 1;
		else if(whitePoints < blackPoints)
			return -1;
		else
			return 2;
	}

	/***************************************************************************
	Metodnamn:	getPoints
	Argument:	color:		Färgen som poängen ska räknas ut för.
	Returnerar:	Antal poäng som färgen har.
	Syfte:		Att räkna ut hur många poäng en färg har.
	***************************************************************************/		
	public int getPoints(int color)
	{
		int points = 0;
		
		for(int i = 0; i < 64; i++)
		{
			if((board[i]).getColor() == color)
				points++;
		}

		return points;
	}

	/***************************************************************************
	Metodnamn:	aiSetBrick
	Argument:	diffuculty:		Vilken svårighetsgrad av AI som ska användas.
	Returnerar:	Positionen på brickan som satts ut, annars -1 om AI:n inte kunde
				sätta ut en bricka.
	Syfte:		Att låta AI:n sätta ut en bricka på ett väldigt smart sätt :).
	***************************************************************************/			
	public int aiSetBrick(int difficulty)
	{
		return ai.setBrick(this, difficulty);
	}

	/***************************************************************************
	Metodnamn:	canMakeMove
	Argument:	Inga.
	Returnerar:	True om den färgen som spelas med just nu kan göra ett drag,
				annars false.
	Syfte:		Att kolla om en färg kan göra några drag överhuvudtaget, om inte
				så byter den spelare automatiskt eftersom denne måste stå
				över ett drag.
	***************************************************************************/			
	public boolean canMakeMove()
	{
		for(int i = 0; i < 64; i++)
		{
			//Kollar bara brickor som är tomma
			if(board[i].getColor() == 0)
			{
				if(isValidMove(i, currentColor))
					return true;
			}
		}
		//Om den inte kan göra ett drag och måste stå över
		currentColor = currentColor * -1;
		return false;
	}
}
