/***************************************************************************
                          proto_xboard.cpp  -  description
                             -------------------
    begin                : Sat Oct 26 2002
    copyright            : (C) 2003 by Troy Corbin Jr.
    email                : tcorbin@users.sf.net
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include <tdelocale.h>
#include <tqtimer.h>
#include <tqstringlist.h>
#include <tqregexp.h>

#include "proto_xboard.moc"
#include "definitions.h"

proto_xboard::proto_xboard( const int ID ) : proto_base( ID )
{
	FEATURE_Analyze			= true;
	FEATURE_Colors			= true;
	FEATURE_Draw				= true;
	FEATURE_ICS					= false;
	FEATURE_Name				= true;
	FEATURE_Pause				= false;
	FEATURE_Ping				= false;
	FEATURE_PlayOther		= false;
	FEATURE_Reuse				= true;
	FEATURE_SetBoard		= false;
	FEATURE_SAN					= false;
	FEATURE_SIGINT			= true;
	FEATURE_SIGTERM			= true;
	FEATURE_Time				= true;
	FEATURE_UserMove		= false;
	FEATURE_Variants		= 0;
	FEATURE_Level				= 1;
	FEATURE_BookEngine	= 0;

	CMDList = new CommandList;
	InitTimer = new TQTimer( this );
	connect( InitTimer, TQ_SIGNAL( timeout() ), this, TQ_SLOT( releaseBuffer() ) );

	Check								= true;
	Team								= false;
	JustMoved						= false;
	AcceptIllegal				= false;
	DelayedGo						= false;
	Forced							= true;
	Turn								= WHITE;
}
proto_xboard::~proto_xboard()
{
	delete InitTimer;
	delete CMDList;
}
///////////////////////////////////////
//
//	proto_xboard::parse( const Command &command )
//
///////////////////////////////////////
void proto_xboard::parse( const Command &command )
{
	TQString temp;
	Command cmd = command;

	if( InitTimer->isActive() )
	{
		/*
				Store Command for later use..
				we're still waiting for the engine to finish
		*/
		CMDList->append( command );
		return;
	}

	switch( cmd.getCommand() )
	{
		/* Command: Init */
		case CMD_Init:
			emit output( "xboard\nprotover 3" );
			InitTimer->start( 2000, true );
			break;

		/* Command: New Game */
		case CMD_NewGame:
			emit output( "new\nrandom" );
			break;

		/* Command: Exit */
		case CMD_Exit:
			emit output( "quit" );
			if( FEATURE_SIGTERM )
				emit output( Command( myID, CMD_Send_SIGTERM ) );
			break;

		/* Command: Move Now */
		case CMD_MoveNow:
			emit output( "?" );
			break;

		/* Command: Move */
		case CMD_Move:
			if( JustMoved )
			{
				JustMoved = false;
				break;
			}
			AcceptIllegal = true;
			myMove = cmd.getMove();
			/* Send Time */
			if( FEATURE_Time )
			{
				if( Army == WHITE )
				{
					emit output( TQString( "time %1" ).arg( cmd.getWhiteTime() ) );
					emit output( TQString( "otim %1" ).arg( cmd.getBlackTime() ) );
				}
				else
				{
					emit output( TQString( "time %1" ).arg( cmd.getBlackTime() ) );
					emit output( TQString( "otim %1" ).arg( cmd.getWhiteTime() ) );
				}
			}
			if( FEATURE_UserMove )
				temp = "usermove ";
			if( FEATURE_SAN )
				temp += myMove.SAN;
			else
				temp += myMove.CAN;
			if( DelayedGo )
			{
				DelayedGo = false;
				temp += "\ngo";
				Forced = false;
			}
			emit output( temp );
			break;

		/* Command: Pause */
		case CMD_Pause:
			if( FEATURE_Pause )
				emit output( "pause" );
			else
			{
				emit output( "force" );
				Forced = true;
			}
			break;

		/* Command: Resume */
		case CMD_Resume:
			if( FEATURE_Pause )
				emit output( "resume" );
			else
			{
				if( Turn == Army )
				{
					emit output( "go" );
					Forced = false;
				}
				else
					DelayedGo = true;
			}
			break;

		/* Command: Play White */
		case CMD_Play_White:
			Army = WHITE;
			if( Turn == BLACK )
			{
				if( FEATURE_PlayOther )
				{
					emit output( "playother" );
				}
				else if( FEATURE_Colors )
				{
					emit output( "black" );
				}
				else
				{
					emit output( "force" );
					Forced = true;
					DelayedGo = true;
				}
				break;
			}
			else
			{
				temp = "force";
				if( FEATURE_Colors )
					temp += "\nwhite";
				temp += "\ngo";
				emit output( temp );
				break;
			}
			break;

		/* Command: Play Black */
		case CMD_Play_Black:
			Army = BLACK;
			if( Turn == WHITE )
			{
				if( FEATURE_PlayOther )
				{
					emit output( "playother" );
				}
				else if( FEATURE_Colors )
				{
					emit output( "white" );
				}
				else
				{
					emit output( "force" );
					Forced = true;
					DelayedGo = true;
				}
				break;
			}
			else
			{
				temp = "force";
				if( FEATURE_Colors )
					temp += "\nblack";
				temp += "\ngo";
				emit output( temp );
				break;
			}
			break;

		/* Command: Result White */
		case CMD_Result_White:
			emit output( "result 1-0 {White Mates}" );
			AcceptIllegal = false;
//			if( Army == WHITE )
//				(*IT).Wins++;
//			else
//				(*IT).Losses++;
			break;

		/* Command: Result Black */
		case CMD_Result_Black:
			emit output( "result 0-1 {Black Mates}" );
			AcceptIllegal = false;
//			if( Army == BLACK )
//				(*IT).Wins++;
//			else
//				(*IT).Losses++;
			break;

		/* Command: Result Draw */
		case CMD_Result_Draw:
			emit output( "result 1/2-1/2 {Draw Game}" );
			AcceptIllegal = false;
//			(*IT).Draws++;
			break;

		/* Command: Your Time */
		case CMD_Your_Time:
			if( FEATURE_Time )
			{
				if( Army == WHITE )
					emit output( TQString( "time %1" ).arg( cmd.getWhiteTime() ) );
				else
					emit output( TQString( "time %1" ).arg( cmd.getBlackTime() ) );
			}
			break;

		/* Command: Enemy Time */
		case CMD_Enemy_Time:
			if( FEATURE_Time )
			{
				if( Army == WHITE )
					emit output( TQString( "otim %1" ).arg( cmd.getBlackTime() ) );
				else
					emit output( TQString( "otim %1" ).arg( cmd.getWhiteTime() ) );
			}
			break;

		/* Command: Offer Draw */
		case CMD_Offer_Draw:
			if( FEATURE_Draw )
				emit output( "draw" );
			break;

		/* Command: Book Mode */
		case CMD_Book_Mode:
			if( FEATURE_BookEngine != 0 )
				emit output( "bookengine" );
			break;

		/* Command: Check Book */
		case CMD_Check_Book:
			emit output( "go" );
			Forced = false;
			break;

		/* Command: Ponder */
		case CMD_Ponder:
			emit output( "hard" );
			break;

		/* Command: No Pondering */
		case CMD_No_Pondering:
			emit output( "hard\neasy" );
			break;

		/* Command: Retract Move */
		case CMD_Retract_Move:
			emit output( "remove" );
			break;

		/* Command: Hint */
		case CMD_Hint:
			emit output( "hint" );
			break;

		/* Command: Listen */
		case CMD_Listen:
			emit output( "force" );
			Forced = true;
			DelayedGo = false;
			break;

		/* Command: Play */
		case CMD_Play:
			if( Army == Turn )
			{
				emit output( "go" );
				Forced = false;
			}
			else
				DelayedGo = true;
			break;

		/* Command: White Resign */
		case CMD_White_Resign:
			parse( Command( 0, CMD_Result_White ) );
			break;

		/* Command: Black Resign */
		case CMD_Black_Resign:
			parse( Command( 0, CMD_Result_Black ) );
			break;

		/* Command: Set Board */
		case CMD_Set_Board:
			if( FEATURE_SetBoard == true )
			{
				emit output( TQString( "setboard %1" ).arg( cmd.getData() ) );
			}
			else
			{
				// Convert FEN to edit commands here and feed them to engine
			}
			break;

		/* Command: Set Difficulty */
		case CMD_Set_Difficulty:
			emit output( "sd " + cmd.getData() );
			// emit output( "st " + TQString::number( cmd.getData().toInt() >> 1 ) );
			break;

		/* Command: Set Name */
		case CMD_Set_Name:
			FEATURE_MyName = cmd.getData();
			break;
		default:
			break;
	}
}
///////////////////////////////////////
//
//	proto_xboard::parse( const TQString &string )
//
///////////////////////////////////////
void proto_xboard::parse( const TQString &string )
{
	TQString strIn = string;
	TQStringList strList( TQStringList::split( ' ', strIn ) );

	if( ( FEATURE_SIGINT ) && ( !Forced ) )
		emit output( Command( myID, CMD_Send_SIGINT ) );

	/* Illegal */
	if( strList[0].contains( "illegal", false ) )
	{
		if( AcceptIllegal )
		{
			if( strIn.contains("(no matching move)board") )
				return;
			if( strIn.contains("(no matching move)protover") )
				return;
			if( strIn.contains("(no matching move)sd") )
				return;
			AcceptIllegal = false;
			emit output( Command( myID, CMD_Illegal ) );
		}
		return;
	}

	/* A Move */
	if( strList[0] == "move" )
	{
		if( strList.count() < 2 )
		{
			kdWarning() << "proto_xboard::parse: Incomplete Move command" << endl;
			return;
		}
		Command::clearMove( &myMove );
		strcpy( myMove.SAN, strList[1].latin1() );
		strcpy( myMove.CAN, strList[1].latin1() );
		if( Team )
		{
			emit output( "force" );
			Forced = true;
		}
		JustMoved = true;
		emit output( Command( myID, CMD_Move, 0, 0, myMove ) );
		return;
	}

	/* A Move ( Old Variation ) */
	if( ( strList[0].contains( TQRegExp("\\d+\\.") ) ) && ( strList[1] == "..." ) )
	{
		Command::clearMove( &myMove );
		strcpy( myMove.SAN, strList[2].latin1() );
		strcpy( myMove.CAN, strList[2].latin1() );
		if( Team )
		{
			emit output( "force" );
			Forced = true;
		}
		JustMoved = true;
		emit output( Command( myID, CMD_Move, 0, 0, myMove ) );
		return;
	}

	/* Hint */
	if( strList[0] == "Hint:" )
	{
		emit output( Command( myID, CMD_Hint, i18n( "%1 suggests this move:\n%2" ).arg( FEATURE_MyName ).arg( strList[1] ) ) );
		return;
	}

	/* Offer Draw */
	if( ( strList[0] == "offer" ) && ( strList[1] == "draw" ) )
	{
		emit output( Command( myID, CMD_Offer_Draw ) );
	}

	/* Out of Book */
	if( strList[0] == "outofbook" )
	{
		emit output( "force" );
		Forced = true;
		emit output( Command( myID, CMD_Out_Of_Book ) );
		return;
	}

	/* Tell User */
	if( strList[0] == "telluser" )
	{
		emit output( Command( myID, CMD_Tell_User, i18n( "%1 tells you:\n%2" ).arg( FEATURE_MyName ).arg( strIn.right( strIn.length() - 9 ) ) ) );
		return;
	}

	/* Tell User Error */
	if( strList[0] == "tellusererror" )
	{
		emit output( Command( myID, CMD_Tell_User_Error, i18n( "%1 tells you:\n%2" ).arg( FEATURE_MyName ).arg( strIn.right( strIn.length() - 14 ) ) ) );
		return;
	}

	/* Error */
	if( strList[0] == "Error" )
	{
		emit output( Command( myID, CMD_Tell_User_Error, i18n( "%1 tells you:\n%2" ).arg( FEATURE_MyName ).arg( strIn.right( strIn.length() ) ) ) );
		return;
	}

	/* Tell Opponent */
	if( strList[0] == "tellopponent" )
	{
		emit output( Command( myID, CMD_Tell_Opponent, TQString( "%1" ).arg( strIn.right( strIn.length() - 13 ) ) ) );
		return;
	}

	/* Tell Others */
	if( strList[0] == "tellothers" )
	{
		emit output( Command( myID, CMD_Tell_Others, TQString( "%1" ).arg( strIn.right( strIn.length() - 11 ) ) ) );
		return;
	}

	/* Tell All */
	if( strList[0] == "tellall" )
	{
		emit output( Command( myID, CMD_Tell_All, TQString( "%1" ).arg( strIn.right( strIn.length() - 8 ) ) ) );
		return;
	}

	/* Tell ICS */
	if( strList[0] == "tellics" )
	{
		emit output( Command( myID, CMD_Tell_ICS, TQString( "%1" ).arg( strIn.right( strIn.length() - 8 ) ) ) );
		return;
	}

	/* Tell ICS No Alias */
	if( strList[0] == "tellicsnoalias" )
	{
		emit output( Command( myID, CMD_Tell_ICS, TQString( "%1" ).arg( strIn.right( strIn.length() - 15 ) ) ) );
		return;
	}

	/* Resign */
	if( strIn.contains( "resign", false ) )
	{
		if( Army == WHITE )
			emit output( Command( myID, CMD_White_Resign ) );
		else
			emit output( Command( myID, CMD_Black_Resign ) );
		return;
	}

	/*
			Parse Features
	*/
	if( !InitTimer->isActive() )
		return;
	for( unsigned int loop = 0; loop < strList.count(); loop++ )
	{
		if( strList[loop] == "done=1" )
		{
			InitTimer->stop();
			releaseBuffer();
			continue;
		}
		/* This buys you 10 minutes */
		if( strList[loop] == "done=0" )
		{
			InitTimer->changeInterval( 600000 );
			continue;
		}
		if( strList[loop] == "feature" )
		{
			continue;
		}
		if( strList[loop].left(3) == "ics" )
		{
			FEATURE_ICS = TQString( strList[loop].right(1) ).toInt();
			emit output( "accepted ics" );
			continue;
		}
		if( strList[loop].left(3) == "san" )
		{
			FEATURE_SAN = TQString( strList[loop].right(1) ).toInt();
			emit output( "accepted san" );
			continue;
		}
		if( strList[loop].left(4) == "draw" )
		{
			FEATURE_Draw = TQString( strList[loop].right(1) ).toInt();
			emit output( "accepted draw" );
			continue;
		}
		if( strList[loop].left(4) == "name" )
		{
			FEATURE_Name = TQString( strList[loop].right(1) ).toInt();
			emit output( "accepted name" );
			continue;
		}
		if( strList[loop].left(4) == "ping" )
		{
			FEATURE_Ping = TQString( strList[loop].right(1) ).toInt();
			emit output( "accepted ping" );
			continue;
		}
		if( strList[loop].left(4) == "time" )
		{
			FEATURE_Time = TQString( strList[loop].right(1) ).toInt();
			emit output( "accepted time" );
			continue;
		}
		if( strList[loop].left(5) == "level" )
		{
			FEATURE_Level = TQString( strList[loop].right( strList[loop].length() - 6 ) ).toInt();
			emit output( "accepted level" );
			continue;
		}
		if( strList[loop].left(5) == "pause" )
		{
			FEATURE_Pause = TQString( strList[loop].right(1) ).toInt();
			emit output( "accepted pause" );
			continue;
		}
		if( strList[loop].left(5) == "reuse" )
		{
			FEATURE_Reuse = TQString( strList[loop].right(1) ).toInt();
			emit output( "accepted reuse" );
			continue;
		}
		if( strList[loop].left(6) == "colors" )
		{
			FEATURE_Colors = TQString( strList[loop].right(1) ).toInt();
			emit output( "accepted colors" );
			continue;
		}
		if( strList[loop].left(6) == "myname" )
		{
			FEATURE_MyName = TQString( strList[loop].right( strList[loop].length() - 8 ) );
			emit output( "accepted myname" );
			continue;
		}
		if( strList[loop].left(6) == "sigint" )
		{
			FEATURE_SIGINT = TQString( strList[loop].right(1) ).toInt();
			emit output( "accepted sigint" );
			continue;
		}
		if( strList[loop].left(7) == "analyze" )
		{
			FEATURE_Analyze = TQString( strList[loop].right(1) ).toInt();
			emit output( "accepted analyze" );
			continue;
		}
		if( strList[loop].left(7) == "sigterm" )
		{
			FEATURE_SIGTERM = TQString( strList[loop].right(1) ).toInt();
			emit output( "accepted sigterm" );
			continue;
		}
		if( strList[loop].left(8) == "setboard" )
		{
			FEATURE_SetBoard = TQString( strList[loop].right(1) ).toInt();
			emit output( "accepted setboard" );
			continue;
		}
		if( strList[loop].left(8) == "usermove" )
		{
			FEATURE_UserMove = TQString( strList[loop].right(1) ).toInt();
			emit output( "accepted usermove" );
			continue;
		}
		if( strList[loop].left(8) == "variants" )
		{
//			FIFO_Tmp = strList[loop].right( strList[loop].length() - 10 );
			// This must be finished
			emit output( "accepted variants" );
			continue;
		}
		if( strList[loop].left(9) == "playother" )
		{
			FEATURE_PlayOther = TQString( strList[loop].right(1) ).toInt();
			emit output( "accepted playother" );
			continue;
		}
		if( strList[loop].left(10) == "bookengine" )
		{
			FEATURE_BookEngine = TQString( strList[loop].right( strList[loop].length() - 11 ) ).toInt();
			emit output( "accepted bookengine" );
			continue;
		}
	}
}
///////////////////////////////////////
//
//	proto_xboard::releaseBuffer
//
///////////////////////////////////////
void proto_xboard::releaseBuffer( void )
{
	CommandList::Iterator it;
	for( it = CMDList->begin(); it != CMDList->end(); it++ )
	{
		parse( *it );
	}
	CMDList->clear();
}
