package chess4j.search;

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

import chess4j.App;
import chess4j.Constants;
import chess4j.board.Board;
import chess4j.moves.Move;

public class SearchImpl implements Search {

	public int search(List<Move> parent_pv,int alpha,int beta,Board board,int depth,SearchStats stats) {
		
		stats.incNodes();
		if (depth <= 0) {
			return App.getEval().eval(board);
		}
		
		// try the hash
		/*int hashCode=board.hashCode();
		int key=TTable.getInstance().getKey(hashCode);
		TTEntry hashEntry = TTable.getInstance().get(key);
		stats.incHashProbes();
		if (hashEntry!=null && hashCode==hashEntry.getFullKey()) {
			if (hashEntry.getDepth()>=depth) {
				stats.incHashHits();
				if (hashEntry.getEntryType().equals(TTEntryType.LOWER_BOUND)) {
					return beta;
				}
			}
		}*/
		
		Move bestMove = null;
		int alphaInit = alpha;
		List<Move> pv = new ArrayList<Move>();
		
		List<Move> moves = App.getMoveGen().genPseudoLegalMoves(board);
		int numMovesSearched=0;
		for (Move move : moves) {
			board.applyMove(move);
			if (board.isOpponentInCheck()) {
				board.undoLastMove();
				continue;
			}
			int score = -search(pv,-beta,-alpha,board,depth-1,stats);
			numMovesSearched++;
			board.undoLastMove();
			if (score > alpha) {
				/*if (score >= beta) {
					TTable.getInstance().storeLowerBound(board,depth,score);
					return beta;
				}*/
				alpha = score;
				bestMove = move;
			}
		}
		
		// is this a mate?
		if (numMovesSearched==0) {
			if (board.isPlayerInCheck()) {
				return -Constants.CHECKMATE; // TODO: adjust for distance from root
			} else {
				return 0; // draw score
			}
		}
		
		// did we improve on alpha?
		if (alpha > alphaInit) {
			parent_pv.clear();
			parent_pv.add(bestMove);
			parent_pv.addAll(pv);
		}
		
		return alpha;
	}
	
}
