#include "gtbwrapper.h"
#include "bitboard.h"

#ifdef _MSC_VER
#define USE_GTB
#endif

#ifdef USE_GTB
#include "gtbcode/gtb-probe.h"
#endif

GTBWrapper::GTBWrapper() : paths(0), tbMen(0)
{
}

GTBWrapper::~GTBWrapper()
{
#ifdef USE_GTB
	tbcache_done();

	tb_done();

	paths = tbpaths_done(paths); 
#endif
}

bool GTBWrapper::init( const char *path, int cache )
{
	tbMen = 0;
#ifdef USE_GTB
	const char **paths = tbpaths_init();
	if (!paths)
		return 0;
	paths = tbpaths_add (paths, path);
	if (!paths)
		return 0;

	/* 	wdl_fraction:
		fraction, over 128, that will be dedicated to wdl information. 
		In other words, 96 means 3/4 of the cache will be dedicated to 
		win-draw-loss info, and 1/4 dedicated to distance to mate 
		information. 
	*/
	int wdl_fraction = 96;

	/* init probing code, indexes, paths, etc. */
	char *initinfo = tb_init( 1/*verbosity*/, tb_CP4/*scheme*/, paths);
//	if ( initinfo )
//		printf(initinfo);

	/* init cache */
	tbcache_init( cache, wdl_fraction );

	tbstats_reset();

	int avail = tb_availability();
	tbMen = 0;
	if ( avail & 2 )
	{
		tbMen = 3;
	}
	if ( avail & 8 )
	{
		tbMen = 4;
	}
	if ( avail & 32 )
	{
		tbMen = 5;
	}
#endif
	return 1;
}

int GTBWrapper::probe( const BitBoard &bb, int ply )
{
#ifdef USE_GTB
	unsigned int  stm;		/* side to move */
	unsigned int  epsquare;	/* target square for an en passant capture */
	unsigned int  castling;	/* castling availability, 0 => no castles */
	unsigned int  ws[17];	/* list of squares for white */
	unsigned int  bs[17];	/* list of squares for black */
	unsigned char wp[17];	/* what white pieces are on those squares */
	unsigned char bp[17];	/* what black pieces are on those squares */ 

	int tb_available;			/* 0 => FALSE, 1 => TRUE */
	unsigned info = tb_UNKNOWN;	/* default, no tbvalue */
	unsigned pliestomate;	
 
	const BitFlags &f = bb.flags();
	epsquare = f.ep;
	if (f.ep)
	{
		epsquare += (f.ep >= 4*8 ? 8 : -8);
		epsquare ^= 0x38;
	} else epsquare = tb_NOSQUARE;
	stm = f.turn;
	castling = tb_NOCASTLE;
	if ( f.castRights[0] || f.castRights[1] )
	{
		// FIXME: better!
		return -1;
	}
	int w = 0;
	int b = 0;
	u64 tmp = bb.bits[ wall ];
	while ( tmp )
	{
		int bi = popLSB( tmp );
		ws[w] = bi ^ 0x38;
		wp[w] = bb.pieces[ bi ] & 127;
		w++;
	}
	ws[w] = tb_NOSQUARE;
	wp[w] = tb_NOPIECE;

	tmp = bb.bits[ ball ];
	while ( tmp )
	{
		int bi = popLSB( tmp );
		bs[b] = bi ^ 0x38;
		bp[b] = bb.pieces[ bi ] & 127;
		b++;
	}
	bs[b] = tb_NOSQUARE;
	bp[b] = tb_NOPIECE;

	tb_available = tb_probe_hard( stm, epsquare, castling, ws, bs, wp, bp, &info, &pliestomate );

	if ( !tb_available )
		return -1;

	if ( info == tb_DRAW )
		return 0;

	if ( info == tb_WMATE )
	{
		return f.turn == white ? bmate - (int)pliestomate - ply : -bmate + (int)pliestomate + ply;
	}

	if ( info != tb_BMATE )
		return -1;

	return f.turn == black ? bmate - (int)pliestomate - ply : -bmate + (int)pliestomate + ply;
#else
	return -1;
#endif
}

int GTBWrapper::numMen() const
{
	return tbMen;
}
