/*--------------------------------------------------------------------------
    Pawny 0.3, chess engine (source code).
    Copyright (C) 2009 - 2011 by Mincho Georgiev.
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
    contact: pawnychess@gmail.com 
    web: http://www.pawny.netii.net/
----------------------------------------------------------------------------*/

#include "data.h"

void uci_exit(){ book_close(); tt_free(); exit(0);}
void uci_start()
{
	printf("id name %s %s\n",ENGINE_NAME, VERSION);
	printf("id author Mincho Georgiev\n");
	printf("option name Hash type spin default 32 min 8 max 1024\n");
	printf("option name PawnHash type spin default 16 min 8 max 128\n");
	printf("option name Reset Timer On Ponderhit type check default false\n");
	printf("option name OwnBook type check default true\n");
	printf("option name Ponder type check default false\n");
	printf("uciok\n");
}

void uci_cmd_handle(char *command)
{
	char *p = 0;
	if(!strncmp(command, "isready",7)) printf("readyok\n");
	else if(!strncmp(command, "quit", 4)) uci_exit();
	else if(!strncmp(command, "position", 8)) uci_set_position(command + 9);
	else if(!strncmp(command, "ucinewgame", 10)) uci_new_game();
	else if(!strncmp(command, "setoption name Hash value", 25)) tt_init(atoi(command + 26));
	else if(!strncmp(command, "setoption name PawnHash value", 29)) pnt_init(atoi(command + 30));
	else if(!strncmp(command, "go", 2)) uci_go(command + 3);
	else if(!strncmp(command, "stop", 4)) si->stop_search = true;
	p = strstr(command, "Reset Timer On Ponderhit");
	if(p)
	{	if(!strncmp(p + 25, "value true", 10))  opt->rtp = true;
		if(!strncmp(p + 25, "value false", 11)) opt->rtp = false;
	}
	p = strstr(command, "OwnBook");
	if(p)
	{	if(!strncmp(p + 8, "value true", 10))  book_open();
		if(!strncmp(p + 8, "value false", 11)) book_close();
	}
}
 
void uci()
{
	char line[4096];
	uci_start();
	
	opt->mode = UCI_MODE;
	while(true)
	{	if(!fgets(&line[0], sizeof(line), stdin)) 
			uci_exit();
		uci_cmd_handle(line);
	}
}

void uci_new_game(){board_init();}

void uci_go(char *commands)
{
	char *startchar = 0;
	int time[2];
	int t, inc;
	int time_inc[2];
	int movestogo = 0;
	int movetime = 0;
	char *ponder   = strstr(commands, "ponder");
	char *infinite = strstr(commands, "infinite");

	opt->max_depth = MAX_DEPTH;
	startchar = strstr(commands, "depth");
	if(startchar)
	{	sscanf(startchar + 6, "%d", &opt->max_depth);
		opt->analyze = true;
		goto l1;
	}
	
	opt->time_fixed = false;
	time[0] = 0; time[1] = 0; time_inc[0] = 0; time_inc[1] = 0;
	
	startchar = strstr(commands, "wtime");
	if(startchar) sscanf(startchar + 6, "%d", &time[WHITE]);
	startchar = strstr(commands, "btime");
	if(startchar) sscanf(startchar + 6, "%d", &time[BLACK]);
	startchar = strstr(commands, "winc");
	if(startchar) sscanf(startchar + 5, "%d", &time_inc[WHITE]);
	startchar = strstr(commands, "binc");
	if(startchar) sscanf(startchar + 5, "%d",  &time_inc[BLACK]);
	startchar = strstr(commands, "movestogo");
	if(startchar) sscanf(startchar + 10, "%d", &movestogo);
	startchar = strstr(commands, "movetime");
	if(startchar) sscanf(startchar + 9, "%d", &movetime);
	
	t = time[board->side]; inc = time_inc[board->side];
	opt->analyze = (uint8)(ponder || infinite);
	
	if(movetime)
	{	opt->time_fixed = true;
		opt->time_high  = movetime - min(movetime/40, 100);
	}
	else if(movestogo)
	{	if(movestogo == 1)
		{	//shorter time for the last move
			//to avoid GUI delays or exceeded time limit:
			opt->time_low  = t / 2;
			opt->time_high = min(t / 2, t - 500);
		}
		else
		{	if(inc)
			{	opt->time_low  = t / min(movestogo, 30) + inc;
				opt->time_high = min((t * 4) / movestogo, t / 3) + inc;
			}
			else
			{	opt->time_low  = t / min(movestogo, 20);
				opt->time_high = min((t * 4) / movestogo, t / 3);
			}
		}
	}
	else
	{	if(inc)
		{	opt->time_low  = t / 30 + inc;
			opt->time_high = max(t / 4, inc - 100);
		}
		else
		{	opt->time_low  = t / 40;
			opt->time_high = t / 8;
		}
	}
	l1:
	think();
}

void uci_set_position(char *pstr)
{
	char *startpos;
	char *fen;
	char *moves;
	char  movestr[8];
	move_t move;
	int i;
	
	startpos = strstr(pstr, "startpos");
	fen = strstr(pstr, "fen");
	moves = strstr(pstr,"moves");

	if(startpos)
	{	board_from_fen(INITIAL_POSITION);		
		if(!moves) return;
		///else - moves from startup position maded:
		moves += 6;
		while(*moves)
		{	//getting the next move string
			memset(&movestr, 0, sizeof(movestr));
			for(i = 0;!isspace(*moves);i++)
			{	movestr[i] = *moves;
				moves++;
			}
			//string to move_t conversion:
			parse_move(&movestr[0], &move);
			//generate, find it and make it:
			if(!make_if_legal(move)) return;
			//get rid of the next space:
			if(isspace(*moves)) moves++;
		}
	}
	if(fen)
	{	//setting the position first
		fen += 4;
		board_from_fen(fen);
		if(!moves) return;
		//else - getting to the present pos.
		moves += 6;
		while(*moves)
		{	//getting the next move string
			memset(&movestr, 0, sizeof(movestr));
			for(i = 0;!isspace(*moves);i++)
			{	movestr[i] = *moves;
				moves++;
			}
			//string to move_t conversion:
			parse_move(&movestr[0], &move);
			//generate, find it and make it:
			if(!make_if_legal(move)) return;
			//get rid of the next space:
			if(isspace(*moves)) moves++;
		}
	}
}
