/**
 *  class Evaluation
 *
 *  This is class conataining static evaluation methods
 *  We have this in an own class to easily switch evaluation if needed
 */
public class Evaluation implements Definitions
{

	public static int white_king_index;
	public static int black_king_index;

	public static int evaluate(Board board)
	{
		white_king_index = -1; // Initialize the white king's poisition
		black_king_index = -1; // Initialize the black king's position

		int finalEval = 0;

		// Check for draw by fifty moves rule
		if(board.movesFifty >= 50) return -DRAW_VALUE; // Negate if we ever choose another value than for draw

		finalEval += material(board); // Start with the evaluations
		//finalEval += kingSafety(board); // In material() we should have found the kings, so now we can evaluate their position

		return finalEval;
		
	}
	public static int material(Board board)
	{
		// Go through all the pieces on the board
		//
		// Add up the values, and see if there is enough material left to force a mate
		boolean whiteHasBishop = false; // Used by draw by material detection
		boolean whiteHasKnight = false; // we need to keep track of the number of
		boolean blackHasBishop = false; // knights and bishops on the board since 1
		boolean blackHasKnight = false; // is draw but 2 is not

		int evaluation = 0; // Initialize the evaluation
		boolean drawn_by_material = true; // Initialize the draw check

		// Since looping through the board costs time, we try to get all the information
		// we can from this one loop. Even things that don't count material.
		// Like finding the kings and checking for draw by material
		for(int i = 0; i < 120; i++)
		{
			if((i & 0x88) == 0)
			{
				// Add the value of the piece to the evaluation
				evaluation += PIECE_VALUE_ARRAY[board.boardArray[i] + 7];

				// Special calculations for particular pieces
				switch(board.boardArray[i])
				{
					case W_KING: white_king_index = i; break;
					case B_KING: black_king_index = i; break;
					case W_KNIGHT: evaluation += W_KNIGHT_POS[i]; break;
					case B_KNIGHT: evaluation -= B_KNIGHT_POS[i]; break;
					case W_BISHOP: evaluation += W_BISHOP_POS[i]; break;
					case B_BISHOP: evaluation -= B_BISHOP_POS[i]; break;
					case W_PAWN: evaluation += W_PAWN_POS[i]; break;
					case B_PAWN: evaluation -= B_PAWN_POS[i]; break;
				}
				// Do the checks for drawn by material
				if(drawn_by_material && board.boardArray[i] != EMPTY_SQUARE)
				{
					// If either side has queen, rook or pawn it is not drawn
					if(board.boardArray[i] == W_QUEEN || board.boardArray[i] == W_ROOK  ||
							board.boardArray[i] == W_PAWN  || board.boardArray[i] == B_QUEEN ||
							board.boardArray[i] == B_ROOK  || board.boardArray[i] == B_PAWN    )
						drawn_by_material = false;

					else if((whiteHasBishop || whiteHasKnight) && board.boardArray[i] == W_BISHOP)
						drawn_by_material = false;

					else if(whiteHasBishop && board.boardArray[i] == W_KNIGHT)
						drawn_by_material = false;

					else if(board.boardArray[i] == W_BISHOP)
						whiteHasBishop = true;

					else if(board.boardArray[i] == W_KNIGHT)
						whiteHasKnight = true;

					else if((blackHasBishop || blackHasKnight) && board.boardArray[i] == B_BISHOP)
						drawn_by_material = false;

					else if(blackHasBishop && board.boardArray[i] == B_KNIGHT)
						drawn_by_material = false;

					else if(board.boardArray[i] == B_BISHOP)
						blackHasBishop = true;

					else if(board.boardArray[i] == B_KNIGHT)
						blackHasKnight = true;

				}

			}
			else i += 7;
		}

		if(drawn_by_material) return DRAW_VALUE * board.toMove;
		else return evaluation * board.toMove; 
	}
	// END evaluatePosition()
	
	/**
	 *  Awards pieces near the enemy's king, since this goes both ways
	 *  (ie if the opponent has many pieces near your king you might be in trouble)
	 *  we call this kingSafety, while it's actually both kingSafety and kingAttack
	 *
	 *  If white has many pieces near the black king and black has no pieces near the
	 *  white king, we might return a score like +50, this way the engine will
	 *  always try avoid having pieces near his own king and put pieces near the enemy's king
	 *
	 * @param board The board
	 * @return int The evaluation
	 */
	private static int kingSafety(Board board)
	{
		int kingSafetyEval = 0; // Holds the final evaluation of the kingSafety on the board

		// Get the kings' row and rank
		int white_king_row = white_king_index%16;
		int white_king_rank = (white_king_index-(white_king_index%16))/16;
		int black_king_row = black_king_index%16;
		int black_king_rank = (black_king_index-(black_king_index%16))/16;

		for(int i = 0; i < 120; i++) // Check for pieces
		{
			if((i & 0x88) == 0)
			{
				// The distance in rows + the distance in ranks = value added to the other
				// player's score
				switch(board.boardArray[i])
				{
					case B_QUEEN:
					{
						kingSafetyEval += Math.abs(white_king_row - (i%16)) + Math.abs(white_king_row - ((i-(i%16))/16));
						System.out.println(kingSafetyEval + " after B_QUEEN");
						break;
					}
					case W_QUEEN:
					{
						kingSafetyEval -= Math.abs(black_king_row - (i%16)) + Math.abs(black_king_row - ((i-(i%16))/16));
						System.out.println(kingSafetyEval + " after W_QUEEN");						
						break;						
					}
					case B_ROOK:
					{
						kingSafetyEval += Math.abs(white_king_row - (i%16)) + Math.abs(white_king_row - ((i-(i%16))/16));
						break;						
					}
					case W_ROOK:
					{
						kingSafetyEval -= Math.abs(black_king_row - (i%16)) + Math.abs(black_king_row - ((i-(i%16))/16));
						break;						
					}
					case B_KNIGHT:
					{
						kingSafetyEval += Math.abs(white_king_row - (i%16)) + Math.abs(white_king_row - ((i-(i%16))/16));
						break;						
					}
					case W_KNIGHT:
					{
						kingSafetyEval -= Math.abs(black_king_row - (i%16)) + Math.abs(black_king_row - ((i-(i%16))/16));
						break;						
					}
				}
			}
			else i += 7;
		}


		// Add check for protection from pawns here


		return kingSafetyEval;

	}
	// END kingSafety()

}
