package cecj.app.othello;

import games.Board;
import games.BoardGame;
import games.GameMove;
import games.Player;

import java.util.ArrayList;
import java.util.List;

public class OthelloGame implements BoardGame {

	private static final int NUM_PLAYERS = 2;

	private int currentPlayer;
	private OthelloBoard board;

	public OthelloGame(OthelloBoard board) {
		this.board = board;
	}

	public boolean endOfGame() {
		for (int row = 1; row <= OthelloBoard.size(); row++) {
			for (int col = 1; col <= OthelloBoard.size(); col++) {
				if (canPlace(row, col, currentPlayer)
						|| canPlace(row, col, getOpponent(currentPlayer))) {
					return false;
				}
			}
		}
		return true;
	}

	public double evalMove(Player player, GameMove move) {
		List<Integer> directions = findDirections(move.getRow(), move.getCol(), currentPlayer);

		float result = 0;
		for (int dir : directions) {
			int dist = 1;
			while (board.getPiece(move.getRow(), move.getCol(), dir, dist) == getOpponent(currentPlayer)) {
				GameMove shifted = board.getShiftedMove(move.getRow(), move.getCol(), dir, dist);
				result += 2 * player.getValue(shifted.getRow(), shifted.getCol());
				dist++;
			}
		}

		return result + player.getValue(move.getRow(), move.getCol());
	}

	public List<? extends GameMove> findMoves() {
		List<OthelloMove> moves = new ArrayList<OthelloMove>();
		for (int row = 1; row <= OthelloBoard.size(); row++) {
			for (int col = 1; col <= OthelloBoard.size(); col++) {
				if (canPlace(row, col, currentPlayer)) {
					moves.add(new OthelloMove(row, col));
				}
			}
		}
		return moves;
	}

	public void makeMove(GameMove move) {
		List<Integer> directions = findDirections(move.getRow(), move.getCol(), currentPlayer);
		for (int dir : directions) {
			int dist = 1;
			board.setPiece(move.getRow(), move.getCol(), currentPlayer);
			while (board.getPiece(move.getRow(), move.getCol(), dir, dist) == getOpponent(currentPlayer)) {
				board.setPiece(move.getRow(), move.getCol(), dir, dist, currentPlayer);
				dist++;
			}
		}
	}

	List<Integer> findDirections(int row, int col, int player) {
		List<Integer> directions = new ArrayList<Integer>();

		if (board.isEmpty(row, col)) {
			for (int dir = 0; dir < OthelloBoard.NUM_DIRECTIONS; dir++) {
				int dist = 1;
				while (board.getPiece(row, col, dir, dist) == getOpponent(player)) {
					dist++;
				}
				if (dist > 1 && board.getPiece(row, col, dir, dist) == player) {
					directions.add(dir);
				}
			}
		}
		return directions;
	}

	boolean canPlace(int row, int col, int curPlayer) {
		return (!findDirections(row, col, curPlayer).isEmpty());
	}

	int getOpponent(int player) {
		return ((player + 1) % NUM_PLAYERS);
	}

	public void switchPlayer() {
		currentPlayer = getOpponent(currentPlayer);
	}

	public int getCurrentPlayer() {
		return currentPlayer;
	}
	
	public int getOutcome() {
		return (board.countPieces(0) - board.countPieces(1));
	}

	public void reset() {
		board.reset();
		currentPlayer = 0;
	}

	public Board getBoard() {
		return board;
	}
}
