package net.woodyfolsom.msproj.policy;

import java.util.List;

import net.woodyfolsom.msproj.GameConfig;
import net.woodyfolsom.msproj.GameState;
import net.woodyfolsom.msproj.StateEvaluator;

//import org.apache.log4j.Logger;

public class AlphaBeta implements Policy {
	//private static final Logger LOGGER = Logger.getLogger(AlphaBeta.class
	//		.getName());
	private static final int DEFAULT_RECURSIVE_PLAYS = 3;
	private final ValidMoveGenerator validMoveGenerator = new ValidMoveGenerator();

	private String bestPick = Policy.PASS;

	@Override
	public String getAction(GameConfig gameConfig, GameState gameState,
			String initialColor) {

		int alpha = Integer.MIN_VALUE;
		int beta = Integer.MAX_VALUE;

		if ("b".equals(initialColor)) {
			getMaxValue(gameConfig, gameState, initialColor, false,
					DEFAULT_RECURSIVE_PLAYS * 2, alpha, beta);
			return bestPick;
		} else if ("w".equals(initialColor)) {
			getMinValue(gameConfig, gameState, initialColor, false,
					DEFAULT_RECURSIVE_PLAYS * 2, alpha, beta);
			return bestPick;
		} else {
			return Policy.PASS;
		}
	}

	private int getMaxValue(GameConfig gameConfig, GameState gameState,
			String initialColor, boolean playAsOpponent, int recursionLevel,
			int alpha, int beta) {
		if (terminalTest(recursionLevel)) {
			return getUtility(gameConfig, gameState);
		}

		String colorPlaying = getColorToPlay(initialColor, playAsOpponent);

		List<String> validMoves = validMoveGenerator.getActions(gameConfig,
				gameState, colorPlaying, ActionGenerator.ALL_ACTIONS);

		int value = Integer.MIN_VALUE;

		for (String nextMove : validMoves) {
			GameState nextState = new GameState(gameState);

			if (!nextState.playStone(colorPlaying, nextMove)) {
				throw new RuntimeException(
						"Illegal move attempted during search!");
			}

			int minValue = getMinValue(gameConfig, nextState, initialColor,
					!playAsOpponent, recursionLevel - 1, alpha, beta);

			if (minValue > value) {
				value = minValue;
				if (recursionLevel == DEFAULT_RECURSIVE_PLAYS * 2) {
					bestPick = nextMove;
				}
			}

			if (value >= beta) {
				return value;
			}
			alpha = Math.max(alpha, value);
		}

		return value;
	}

	private int getMinValue(GameConfig gameConfig, GameState gameState,
			String initialColor, boolean playAsOpponent, int recursionLevel,
			int alpha, int beta) {
		if (terminalTest(recursionLevel)) {
			return getUtility(gameConfig, gameState);
		}

		String colorPlaying = getColorToPlay(initialColor, playAsOpponent);

		List<String> validMoves = validMoveGenerator.getActions(gameConfig,
				gameState, colorPlaying, ActionGenerator.ALL_ACTIONS);

		int value = Integer.MAX_VALUE;

		for (String nextMove : validMoves) {
			GameState nextState = new GameState(gameState);

			if (!nextState.playStone(colorPlaying, nextMove)) {
				throw new RuntimeException(
						"Illegal move attempted during search!");
			}

			int maxValue = getMaxValue(gameConfig, nextState, initialColor,
					!playAsOpponent, recursionLevel - 1, alpha, beta);

			if (maxValue < value) {
				value = maxValue;
				if (recursionLevel == 2 * DEFAULT_RECURSIVE_PLAYS) {
					bestPick = nextMove;
				}
			}

			if (value <= alpha) {
				return value;
			}
			beta = Math.min(beta, value);
		}

		return value;
	}

	private boolean terminalTest(int recursionLevel) {
		return recursionLevel < 1;
	}

	private int getUtility(GameConfig gameConfig, GameState gameState) {
		StateEvaluator stateEvaluator = new StateEvaluator(gameConfig);
		return stateEvaluator.scoreGame(gameState).getAggregateScore();
	}

	private String getColorToPlay(String color, boolean playAsOpponent) {
		if (playAsOpponent) {
			if ("w".equals(color)) {
				return "b";
			} else if ("b".equals(color)) {
				return "w";
			} else {
				return "?"; // invalid color will cause randomMoveGenerator to
							// PASS
			}
		} else {
			return color;
		}
	}
}