/*--------------------------------------------------------------------------
    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"
#include <math.h>


void print_info(int r,int d)
{
	int i,mate;
	float score;
	char str[32];
	int t;
	uint64 nps = 0;
	int seldepth = 0;
	char pvstring[1024];
	double hprm = 0;

	if(opt->mode == UCI_MODE)
	{
		i = pv_to_string(&pvstring[0],d);
		if(i > d) seldepth = i;
		t = ((get_time() - opt->startup_time));
		if(t) nps = (si->nodes / t) * 1000;
		
		hprm = ((double)si->num_hash_saves/(double)opt->tt_numentries) * 1000.0;

		if(abs(r) >= MATE_VALUE - MAX_PLY)
		{	if(r>0) mate = (MATE_VALUE - r + 1) / 2;
			else mate = -(MATE_VALUE + r) / 2;
			printf("info depth %d seldepth %d score mate %d time %d nodes "llufmt" nps "llufmt" hashfull %.0f pv %s \n",d,seldepth, mate, t,si->nodes,nps,hprm,pvstring);
		}
		else
			printf("info depth %d seldepth %d score cp %d time %d nodes "llufmt" nps "llufmt" hashfull %.0f pv %s \n",d,seldepth, r, t,si->nodes,nps,hprm,pvstring);
	}
	else
	{	//reversing the score if needed:
		//+ WHITE, - BLACK
		if(opt->comp_side == BLACK && r != 0)
			score = -(r / ((float)100));
		else
			score = (r / ((float)100));
		
		printf("%2d "llufmt,d,si->nodes); 
		//converting the nodes count
		sprintf(str,llufmt,si->nodes);

		//formatting the spaces betw. nodes and pv:
		if(score >= 0) i = (int)(11 - strlen(str));
		else i = (int)(10 - strlen(str));
		while(i){
			printf(" ");
			i--;
		}
		printf(" %.2f ",score);
		
		pv_to_string(&pvstring[0],d);
		printf("%s", pvstring);
		
		printf("\n");
	}
}

void update_info()
{
	uint64 nps = 0;
	int t;
	double hprm = 0;
	if(opt->mode == UCI_MODE)
	{	t = get_time() - opt->startup_time;
		if(t) nps = (si->nodes / t) * 1000;
		hprm = ((double)si->num_hash_saves/(double)opt->tt_numentries) * 1000.0;
		printf("info time %d nodes "llufmt" nps "llufmt" hashfull %.0f\n",t,si->nodes,nps,hprm);
	}
}


#ifndef _WIN32
#include <sys/time.h>
int poll()
{
	fd_set readfds;
	struct timeval  timeout;
	
	FD_ZERO(&readfds);
	FD_SET(fileno(stdin), &readfds);
	timeout.tv_sec = 0;
	timeout.tv_usec = 0;
	select(16, &readfds, 0, 0, &timeout);
	return (FD_ISSET(fileno(stdin), &readfds));
}
#else
#include <windows.h>
#include <conio.h>
int poll()
{	
	DWORD dwData,i;
	INPUT_RECORD inRec[8];
	static HANDLE hConsoleHandle;
	static bool poll_initialized = false;
	static bool pipe = true;

	if(!poll_initialized)
	{	poll_initialized = true;
		hConsoleHandle = GetStdHandle(STD_INPUT_HANDLE);
		if(GetConsoleMode(hConsoleHandle, &dwData)) 
			pipe = false;
	}
	if(pipe)
	{	if(PeekNamedPipe(hConsoleHandle, 0, 0, 0, &dwData, 0))
			return dwData;
	}
	else 
	{	PeekConsoleInput(hConsoleHandle, &inRec[0], 8, &dwData);
		for(i = 0; i < dwData; i++)
		  if(inRec[i].EventType & KEY_EVENT)
		    return dwData;
	}
	return (pipe);
}
#endif

void check_for_poll()
{
	char input[256];

	if (poll())
	{	if (!fgets(input,sizeof(input), stdin)) strcpy(input, "quit\n");
		if(opt->mode == UCI_MODE)
		{	if (!strncmp(input, "quit", 4)) uci_exit();
			else if (!strncmp(input, "stop", 4))
				si->stop_search = true;
			else if(!strncmp(input, "isready",7)) printf("readyok\n");
			else if(!strncmp(input, "ponderhit",9))
			{////resets the clock and continue:
				opt->analyze = false;
				if(opt->rtp)
				{	opt->startup_time = get_time(); 
					si->nodes = 0;
				}
			}
		}
	}
}

move_data_t pv_backup[MAX_PLY];
static void collect(int *psize)
{
	move_t m;
	uint32 hm;
	
	if(*psize >= MAX_PLY) return;
	hm = tt_get_hashmove();
	if(hm)
	{	m.p = hm;
		if(make_if_legal(m))
		{	pv_backup[*psize].p = hm;
			*psize += 1;
			collect(psize);
			move_undo();
		}
	}
}

static int pv_collect()
{
	move_t m;
	int pvlen = 1;
	
	m.p = si->rootmove.p;
	if(!make_if_legal(m)) return 1;
	pv_backup[0].p = m.p;
	collect(&pvlen);
	move_undo();
	return pvlen;
}

int pv_to_string(char *s,int depth)
{//takes tha addr of buffer as argument 
//and returns the pv string length in moves count.
	
	int i,file,rank;
	move_data_t m;
	int len,move_count = 0;

	len = pv_collect();
	
	//check for redundancy repetitions:
	if(len > MAX_PLY-1) len = depth;
	
	for(i = 0; i < len; i++)
	{
		m.p = pv_backup[i].p;
		
		file = calc_file(m.from);
		rank = calc_rank(m.from);
		switch(file)
		{
			case FILE_A: *s = 'a'; break;
			case FILE_B: *s = 'b'; break;
			case FILE_C: *s = 'c'; break;
			case FILE_D: *s = 'd'; break;
			case FILE_E: *s = 'e'; break;
			case FILE_F: *s = 'f'; break;
			case FILE_G: *s = 'g'; break;
			case FILE_H: *s = 'h'; break;
			default: break;
		}
		s++;
		switch(rank)
		{
			case RANK_1: *s = '1'; break;
			case RANK_2: *s = '2'; break;
			case RANK_3: *s = '3'; break;
			case RANK_4: *s = '4'; break;
			case RANK_5: *s = '5'; break;
			case RANK_6: *s = '6'; break;
			case RANK_7: *s = '7'; break;
			case RANK_8: *s = '8'; break;
		}
		s++;
		file = calc_file(m.to);
		rank = calc_rank(m.to);
		switch(file)
		{
			case FILE_A: *s = 'a'; break;
			case FILE_B: *s = 'b'; break;
			case FILE_C: *s = 'c'; break;
			case FILE_D: *s = 'd'; break;
			case FILE_E: *s = 'e'; break;
			case FILE_F: *s = 'f'; break;
			case FILE_G: *s = 'g'; break;
			case FILE_H: *s = 'h'; break;
			default: break;
		}
		s++;
		switch(rank)
		{
			case RANK_1: *s = '1'; break;
			case RANK_2: *s = '2'; break;
			case RANK_3: *s = '3'; break;
			case RANK_4: *s = '4'; break;
			case RANK_5: *s = '5'; break;
			case RANK_6: *s = '6'; break;
			case RANK_7: *s = '7'; break;
			case RANK_8: *s = '8'; break;
		}
		s++;
		switch(GetType(m.promoted))
		{
			case QUEEN:  *s = 'Q'; s++; break;
			case ROOK:   *s = 'R'; s++; break;
			case BISHOP: *s = 'B'; s++; break;	
			case KNIGHT: *s = 'N'; s++; break;
			default: break;
		}
		*s = ' ';
		s++;
		move_count++;
	}
	*s = '\0'; //null terminating
	
	return move_count;
}

void suppress_buffering()
{
	#ifndef _WIN32
	setbuf(stdout, NULL);
	setbuf(stdin, NULL);
	setvbuf(stdout, NULL, _IONBF, 0);
	setvbuf(stdin, NULL, _IONBF, 0);
	#else
	HANDLE hConsoleHandle;
	DWORD dwData;
	hConsoleHandle = GetStdHandle(STD_INPUT_HANDLE);
	if(!GetConsoleMode(hConsoleHandle, &dwData)) 
	{	setbuf(stdout, NULL);
		setbuf(stdin, NULL);
		setvbuf(stdout, NULL, _IONBF, 0);
		setvbuf(stdin, NULL, _IONBF, 0);
	}
	#endif
}
