package chess4j.io;

import java.text.ParseException;
import java.util.List;
//import groovy.lang.MissingMethodException

import org.xml.sax.SAXException;

import chess4j.App;
import chess4j.Color;
import chess4j.board.Board;
import chess4j.board.File;
import chess4j.board.Rank;
import chess4j.board.Square;
import chess4j.eval.Evaluator;
import chess4j.exceptions.IllegalMoveException;
import chess4j.moves.Move;
import chess4j.moves.MoveGen;
import chess4j.search.SearchIterator;
import chess4j.utils.GameStatus;
import chess4j.utils.GameStatusChecker;
import chess4j.utils.Perft;



public class InputParser {
	private static final InputParser INSTANCE = new InputParser();
	private boolean _forceMode;
	private Thread _searchThread;

	private InputParser() { }
	
	public static InputParser getInstance() {
		return INSTANCE;
	}
	
	public void parseCommand(String command) throws IllegalMoveException,MissingMethodException,ParseException {
		def input = command.tokenize()
		def method = input.remove(0)
		if ("new".equals(method)) {  // because 'new' is a reserved word
			invokeMethod("newGame",input)
		} else if ("?".equals(method)) { // can't have a method named '?'
			invokeMethod("moveNow",input)
		} else {
			invokeMethod(method,input)
		}
	}
	
	def accepted(def arg) {}
	
	def analyze(def arg) {}

	def black(def arg) {}
	
	def bk(def arg) {}
	
	def computer(def arg) {}

	def db(def arg) {
		DrawBoard.drawBoard(App.getBoard());
	}

	def draw(def arg) {}
	
	def easy(def arg) {}

	def eval(def arg) {
		int eval = App.getEval().eval(App.getBoard());
		println "eval=" + eval
	}

	def force(def arg) {
		_forceMode = true;
	}
		
	def go(def arg) {
		joinSearchThread();
		_forceMode = false;
		thinkAndMakeMove();
	}
	
	def hard(def arg) {}
	
	def hint(def arg) {}
	
	def ics(def arg) {}
	
	def level(def arg) {}

	def moveNow(def arg) {}

	def name(List args) {
		String opponent = args.get(0)
		println "opponent is: " + opponent
	}
	
	def newGame(def arg) {
		joinSearchThread();
		_forceMode = false;
		App.getBoard().resetBoard();
	}

	def otim(def arg) { }

	def perft(List args) {
		joinSearchThread();
		int depth = Integer.valueOf(args.get(0));
		DrawBoard.drawBoard(App.getBoard());
		try {
			long start = System.currentTimeMillis();
			long nodes=Perft.perft(App.getBoard(), depth, null);
			long end = System.currentTimeMillis();
			if (end==start) end=start+1; // HACK to avoid div 0
			println "nodes: " + nodes
			println "elapsed time: " + (end-start) + " ms"
			println "rate: " + nodes*1000/(end-start) + " n/s\n"
		} catch (SAXException e) {
			e.printStackTrace();
		}
	}

	def playother(def arg) { }
	
	def ping(List args) {
		println "pong " + args.get(0)
	}	

	def protover(List args) {
		Integer version = Integer.valueOf(args.get(0))
		if (version < 2) {
			println "Error: invalid protocol version."
			System.exit(1)
		}
		println "feature ping=1 setboard=1 draw=0 analyze=0 colors=0 name=1"
		println "feature usermove=1 sigint=0 sigterm=0 variants=\"normal\""
		println "feature ics=1 done=1"
	}

	def quit(def arg) {
		println "bye..."
		System.exit(0);
	}

	def random(def arg) { }
	
	def rating(def arg) { }
	
	def rejected(def arg) { }
	
	def remove(def arg) { }

	def result(def arg) {
		joinSearchThread()
	}	

	def sd(def arg) { }
			
	def setboard(List args) {
		String fen = args.get(0)
		FenParser.setPos(App.getBoard(),fen);
	}

	def st(def arg) { }

	def time(def arg) { }

	def undo(def arg) { }

	def usermove(List args) throws IllegalMoveException {
		joinSearchThread();
		String strMove = args.get(0)
		Move mv = MoveParser.parseLegalMove(strMove,App.getBoard());
		App.getBoard().applyMove(mv);
		if (!_forceMode) {
			thinkAndMakeMove();
		}
	}

	def variant(List args) {
		String v = args.get(0)
		if (! "normal".equals(v)) {
			println "Error: unsupported variant."
		}
	}
			
	def white(def arg) {}
	
	def xboard(def arg) {}
	
	private void joinSearchThread() {
		if (_searchThread==null) return;
		_searchThread.join();
	}
	
	private void thinkAndMakeMove() {
		GameStatus gs = GameStatusChecker.getGameStatus(App.getBoard());
		if (gs != GameStatus.INPROGRESS) {
			PrintGameResult.printResult(gs);
			return;
		}
		_searchThread = new Thread(SearchIterator.getInstance());
		_searchThread.start();
	}
}
