/***************************************************************************
                          pgn.cpp  -  description
                             -------------------
    begin                : Mon Jul 30 2001
    copyright            : (C) 2003 by Troy Corbin Jr.
    email                : tcorbin@users.sourceforge.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 <sys/utsname.h>
#include <sys/types.h>
#include <tqdatetime.h>
#include <tqregexp.h>
#include <kprinter.h>
#include <tqfontmetrics.h>
#include <tqpaintdevicemetrics.h>
#include "pgn.moc"
#include "tabmanager.h"
#include "tab_pgnview.h"

pgn::pgn( resource *Rsrc, match_param *param )
{
	Resource = Rsrc;
	Param = param;
	pgnView = NULL;

	if( Param != NULL )
	{
		connect( Param, TQ_SIGNAL( valuesChanged() ), this, TQ_SLOT( parseMatchParam() ) );
	}
}
pgn::~pgn()
{
	if( Param )
		delete Param;
	if( pgnView )
	{
		if( Resource->tabManager->isTab( pgnView ) )
		{
			Resource->tabManager->removeTab( pgnView );
		}
	}
}
///////////////////////////////////////
//
//	pgn::parseMatchParam
//
///////////////////////////////////////
void pgn::parseMatchParam( void )
{
	if( Param == NULL )
		return;
	TAG_White = Param->name( WHITE );
	TAG_Black = Param->name( BLACK );
	switch( Param->type( BLACK ) )
	{
		case PLAYERLOCAL:
			TAG_BlackType = "human";
			break;
		case PLAYERPC:
			TAG_BlackType = "program";
			break;
		case PLAYERTCP:
			TAG_BlackType = "unknown";
			TAG_Mode = "ICS";
			break;
		case PLAYEREMAIL:
			TAG_BlackType = "unknown";
			TAG_Mode = "EM";
			break;
		default:
			TAG_BlackType = "unknown";
			break;
	}
	switch( Param->type( WHITE ) )
	{
		case PLAYERLOCAL:
			TAG_WhiteType = "human";
			break;
		case PLAYERPC:
			TAG_WhiteType = "program";
			break;
		case PLAYERTCP:
			TAG_WhiteType = "unknown";
			TAG_Mode = "ICS";
			break;
		case PLAYEREMAIL:
			TAG_WhiteType = "unknown";
			TAG_Mode = "EM";
			break;
		default:
			TAG_WhiteType = "unknown";
			break;
	}
}
///////////////////////////////////////
//
//	pgn::notation
//
///////////////////////////////////////
TQStringList* pgn::notation( const int format )
{
	TQStringList *list;
	TQString notation;
	MoveList::Iterator IT;
	Annotation *annon;
	int tmp(0), Line(0);
	bool showLineNumber( false );

	list = new TQStringList;

	switch( format )
	{
		case 0:
			/* CAN Raw move data ( ie. for UCI engines ) */
			for( IT = Moves.begin(); IT != Moves.end(); ++IT )
			{
				list->append( TQString( (*IT).CAN ) );
			}
			break;

		case 1:
			/* SAN For display to the user */
			for( IT = Moves.begin(); IT != Moves.end(); ++IT )
			{
				Line = ( tmp + 2 ) >> 1;
				if( ( tmp % 2 ) == 0 )
				{
					notation = TQString( "%1. %2" ).arg( Line ).arg( (*IT).SAN );
				}
				else
				{
					notation = TQString( "%1... %2" ).arg( Line ).arg( (*IT).SAN );
				}
				list->append( notation );
				tmp++;
			}
			break;

		case 2:
			/* SAN For PGN */
			for( IT = Moves.begin(); IT != Moves.end(); ++IT )
			{
				Line = ( tmp + 2 ) >> 1;
				if( ( tmp % 2 ) == 0 )
				{
					notation = TQString( "%1. %2" ).arg( Line ).arg( (*IT).SAN );
				}
				else
				{
					if( showLineNumber )
					{
						notation = TQString( "%1... %2" ).arg( Line ).arg( (*IT).SAN );
					}
					else
					{
						notation = TQString( (*IT).SAN );
					}
				}
				showLineNumber = false;
				/* Insert NAGs */
				if( (*IT).NAG != 0 )
				{
					notation += TQString( " $%1" ).arg( TQString::number( (*IT).NAG ) );
				}
				/* Insert RAVs */
				annon = RAV.find( tmp );
				if( annon != NULL )
				{
					notation += TQString( " (%1)" ).arg( annon->text );
					showLineNumber = true;
				}
				/* Insert Annotations */
				annon = annotations.find( tmp );
				if( annon != NULL )
				{
					notation += TQString( " {%1}" ).arg( annon->text );
					showLineNumber = true;
				}
				list->append( notation );
				tmp++;
			}
			break;

		default:
			break;
	}
	return list;
}
///////////////////////////////////////
//
//	pgn::caption
//
///////////////////////////////////////
TQString pgn::caption( void )
{
	TQString caption;

	caption = i18n( "%1 vs. %2").arg( TAG_White ).arg( TAG_Black );
	return caption;
}
///////////////////////////////////////
//
//	pgn::clear
//
///////////////////////////////////////
void pgn::clear( void )
{
	Moves.clear();
	RAV.clear();
	annotations.clear();
	Positions.clear();
	currentIndex = 0;
	whiteTCP.clear();
	blackTCP.clear();
	whiteTime = 300;
	blackTime = 300;
	CurrentURL = "";
	Move_Data.clear();
	clearTags();
}
///////////////////////////////////////
//
//	pgn::clearTags
//
///////////////////////////////////////
void pgn::clearTags( void )
{
	TAG_Site = "";
	TAG_Date = "";
	TAG_Round = "";
	TAG_Result = "";
	TAG_White = "";
	TAG_WhiteTitle = "";
	TAG_WhiteElo = "";
	TAG_WhiteUSCF = "";
	TAG_WhiteNA = "";
	TAG_WhiteType = "";
	TAG_Black = "";
	TAG_BlackTitle = "";
	TAG_BlackElo = "";
	TAG_BlackUSCF = "";
	TAG_BlackNA = "";
	TAG_BlackType = "";
	TAG_Time = "";
	TAG_UTCTime = "";
	TAG_UTCDate = "";
	TAG_Event = "";
	TAG_EventDate = "";
	TAG_EventSponsor = "";
	TAG_Section = "";
	TAG_Stage = "";
	TAG_Board = "";
	TAG_Opening = "";
	TAG_Variation = "";
	TAG_SubVariation = "";
	TAG_ECO = "";
	TAG_NIC = "";
	TAG_TimeControl = "";
	TAG_Termination = "";
	TAG_SetUp = "";
	TAG_FEN = "";
	TAG_Annotator = "";
	TAG_Mode = "";
	TAG_PlyCount = "";
}
///////////////////////////////////////
//
//	pgn::init
//
///////////////////////////////////////
void pgn::init( void )
{
	TQString temp;
	struct utsname unamePtr;
	TQDateTime qdt;

	clear();
	parseMatchParam();
	uname( &unamePtr );

	/* Build Date */
	qdt = TQDateTime::currentDateTime();
	TAG_Date = TQString("%1.%2.%3").arg(qdt.date().year(),4).arg(qdt.date().month(),2).arg(qdt.date().day(),2);
	TAG_Date = TAG_Date.replace( TQRegExp("\\s"), TQString("0") );
	TAG_Time = qdt.time().toString();

	TAG_Site = unamePtr.nodename;
	TAG_Event = "Knights Computer Chess Game";
	TAG_Round = "-";
	TAG_Result = "*";
}
///////////////////////////////////////
//
//	pgn::scan
//
///////////////////////////////////////
int pgn::scan( void )
{
	int Section(0);
	TQChar c;

	clearTags();
	File_Position = File.at();

	/* Toplevel parsing loop */
	while( 1 )
	{
		/* Is this the end of the .pgn file? */
		if( Input.atEnd() )
		{
			close();
			return 100; // 100% Complete
		}
		currentLine = Input.readLine();
 		if( currentLine.isEmpty() )
 		{
 			if( Section == 1 )
				return (int)( ( (float)File.at() / (float)File.size() ) * 100.0 );
 		}
		c = getch();
		while( c != TQChar::null )
		{
  		switch( c )
  		{
  			/* Tag Pair */
  			case '[':
  				parseTag();
					break;
  			case '%': /* Fall through */
  			case ';':
					c = TQChar::null;
					continue;
  				break;
				default:
					Section = 1;
  				c = TQChar::null;
					continue;
					break;
  		}
			c = getch();
		}
	}
	/* We should NEVER reach this point */
	close();
	return -1;
}
///////////////////////////////////////
//
//	pgn::load
//
///////////////////////////////////////
bool pgn::load( const int pos )
{
	TQString Token,
					Value;
	TQChar 	c;

	File.at(pos);
	clear();

	/* Toplevel parsing loop */
	while( 1 )
	{
		if( Input.atEnd() )
			break;
		currentLine = Input.readLine();
		if( currentLine.isEmpty() )
		{
			/* Finished with TAGs... now grab the move data for display */
			File_Position = File.at();
			while( 1 )
			{
				currentLine = Input.readLine();
				if( ( currentLine.at(0) == '[' ) || Input.atEnd() )
					break;
				Move_Data << currentLine;
			}
			/* Allocate the Tab_PGNView */
			pgnView = new tab_pgnView( this, Resource );
			connect( pgnView, TQ_SIGNAL( destroyed() ), this, TQ_SLOT( childViewDestroyed() ) );
			Resource->tabManager->addTab( pgnView, i18n( "%1 vs. %2" ).arg( TAG_White ).arg( TAG_Black ) );
			pgnView->init();
			File.at( File_Position );
			currentLine = "";
			return true;
		}
		c = getch();
		while( c != TQChar::null )
		{
			Token = "";
			Value = "";
			switch( c )
			{
				/* Special break... look for the Knights tag */
				case '%':
					Value = getword();
					if( Value == "KNIGHTS_CMD" ) parseKnightsData();
					/* Fall through */
				case ';':
					c = TQChar::null;
					continue;
					break;
				/* Tag Pair */
				case '[':
					parseTag();
					break;
				default:
					c = TQChar::null;
					break;
			}
			c = getch();
		}
	}
	close();
	return true;
}
///////////////////////////////////////
//
//	pgn::loadNext
//
///////////////////////////////////////
bool pgn::loadNext( void )
{
	TQChar c;
	TQString Value;
	ChessMove Move;
	bool postMove( false );

	/* Toplevel parsing loop */
	while( 1 )
	{
		if( currentLine.isEmpty() )
		{
			if( Input.atEnd() ) break;
			currentLine = Input.readLine();
		}
		c = getch();
		while( c != TQChar::null )
		{
			Value = "";
			switch( c )
			{
				/* Special break... look for the Knights tag */
				case '%':
					Value = getword();
					if( Value == "KNIGHTS_CMD" ) parseKnightsData();
					/* Fall through */
				case ';':
					c = TQChar::null;
					continue;
				/* Tag Pair...next game, so we're done. */
				case '[':
					return false;
				/* Numeric Annotation Glyph */
				case '$':
					c = getch();
					while( ( c.unicode() >= '0' ) && ( c.unicode() <= '9' ) )
					{
						Value += c;
						c = getch();
					}
					Moves[ Moves.count() - 1 ].NAG = Value.toInt();
					break;
				/* Recursive Annotation Variations */
				case '(':
					parseRAV();
					break;
				/* Textual Annotation */
				case '{':
					parseAnnotation();
					break;
				/* Reserved for future expansion by the PGN */
				case '<':
					while( c != '>' ) c = getch();
					break;
				/* Everything from '0' to '*' is null to us and falls through */
				case '0':
				case '1':
				case '2':
				case '3':
				case '4':
				case '5':
				case '6':
				case '7':
				case '8':
				case '9':
				case ' ':
				case '/':
				case '-':
				case '.':
				case '*':
					break;
				default:
					if( postMove )
					{
						currentLine.prepend( c );
						return true;
					}
					/* Catch Standard Algebraic Notation */
					while(	( c != TQChar::null	) &&
									( c != ' '					) &&
									( c != ';'					) &&
									( c != '%'					) )
									{
										Value += c;
										c = getch();
									}
					strcpy( Move.SAN, Value.latin1() );
					emit processMove( Move );
					postMove = true;
			}
			c = getch();
		}
	}
	return false;
}
///////////////////////////////////////
//
//	pgn::save
//
///////////////////////////////////////
bool pgn::save( TQString URL )
{
	TQFile								Save( URL );
	TQTextStream 				*Output;
	TQString							Token,
											Value;

	close();
	CurrentURL = URL;
	if( Resource->OPTION_Reuse_PGN && ( URL == Resource->PGN_Filename ) )
	{
		Save.open( IO_WriteOnly | IO_Append );
	}
	else
	{
		Save.open( IO_WriteOnly );
	}
	Output = new TQTextStream( &Save );
	(*Output) << "[Event \"" << TAG_Event << "\"]\n";
	(*Output) << "[Site \"" << TAG_Site << "\"]\n";
	(*Output) << "[Date \"" << TAG_Date << "\"]\n";
	(*Output) << "[Round \"" << TAG_Round << "\"]\n";
	(*Output) << "[White \"" << TAG_White << "\"]\n";
	(*Output) << "[Black \"" << TAG_Black << "\"]\n";
	(*Output) << "[Result \"" << TAG_Result << "\"]\n";
	if( !TAG_TimeControl.isEmpty() )
			(*Output) << "[TimeControl \"" << TAG_TimeControl << "\"]\n";
	if( !TAG_WhiteTitle.isEmpty() )
			(*Output) << "[WhiteTitle \"" << TAG_WhiteTitle << "\"]\n";
	if( !TAG_WhiteElo.isEmpty() )
			(*Output) << "[WhiteElo \"" << TAG_WhiteElo << "\"]\n";
	if( !TAG_WhiteUSCF.isEmpty() )
			(*Output) << "[WhiteUSCF \"" << TAG_WhiteUSCF << "\"]\n";
	if( !TAG_WhiteNA.isEmpty() )
			(*Output) << "[WhiteNA \"" << TAG_WhiteNA << "\"]\n";
	if( !TAG_WhiteType.isEmpty() )
			(*Output) << "[WhiteType \"" << TAG_WhiteType << "\"]\n";
	if( !TAG_BlackTitle.isEmpty() )
			(*Output) << "[BlackTitle \"" << TAG_BlackTitle << "\"]\n";
	if( !TAG_BlackElo.isEmpty() )
			(*Output) << "[BlackElo \"" << TAG_BlackElo << "\"]\n";
	if( !TAG_BlackUSCF.isEmpty() )
			(*Output) << "[BlackUSCF \"" << TAG_BlackUSCF << "\"]\n";
	if( !TAG_BlackNA.isEmpty() )
			(*Output) << "[BlackNA \"" << TAG_BlackNA << "\"]\n";
	if( !TAG_BlackType.isEmpty() )
			(*Output) << "[BlackType \"" << TAG_BlackType << "\"]\n";
	if( !TAG_Time.isEmpty() )
			(*Output) << "[Time \"" << TAG_Time << "\"]\n";
	if( !TAG_UTCTime.isEmpty() )
			(*Output) << "[UTCTime \"" << TAG_UTCTime << "\"]\n";
	if( !TAG_UTCDate.isEmpty() )
			(*Output) << "[UTCDate \"" << TAG_UTCDate << "\"]\n";
	if( !TAG_EventDate.isEmpty() )
			(*Output) << "[EventDate \"" << TAG_EventDate << "\"]\n";
	if( !TAG_EventSponsor.isEmpty() )
			(*Output) << "[EventSponsor \"" << TAG_EventSponsor << "\"]\n";
	if( !TAG_Section.isEmpty() )
			(*Output) << "[Section \"" << TAG_Section << "\"]\n";
	if( !TAG_Stage.isEmpty() )
			(*Output) << "[Stage \"" << TAG_Stage << "\"]\n";
	if( !TAG_Board.isEmpty() )
			(*Output) << "[Board \"" << TAG_Board << "\"]\n";
	if( !TAG_Opening.isEmpty() )
			(*Output) << "[Opening \"" << TAG_Opening << "\"]\n";
	if( !TAG_Variation.isEmpty() )
			(*Output) << "[Variation \"" << TAG_Variation << "\"]\n";
	if( !TAG_SubVariation.isEmpty() )
			(*Output) << "[SubVariation \"" << TAG_SubVariation << "\"]\n";
	if( !TAG_ECO.isEmpty() )
			(*Output) << "[ECO \"" << TAG_ECO << "\"]\n";
	if( !TAG_NIC.isEmpty() )
			(*Output) << "[NIC \"" << TAG_NIC << "\"]\n";
	if( !TAG_Termination.isEmpty() )
			(*Output) << "[Termination \"" << TAG_Termination << "\"]\n";
	if( !TAG_SetUp.isEmpty() )
			(*Output) << "[SetUp \"" << TAG_SetUp << "\"]\n";
	if( !TAG_FEN.isEmpty() )
			(*Output) << "[FEN \"" << TAG_FEN << "\"]\n";
	if( !TAG_Annotator.isEmpty() )
			(*Output) << "[Annotator \"" << TAG_Annotator << "\"]\n";
	if( !TAG_Mode.isEmpty() )
			(*Output) << "[Mode \"" << TAG_Mode << "\"]\n";
	TAG_PlyCount = TQString().setNum( Moves.count() );
	(*Output) << "[PlyCount \"" << TAG_PlyCount << "\"]\n";

	/* Save internal data if this game is unfinished */
	if( TAG_Result == "*" )
	{
		(*Output) << "% KNIGHTS_CMD WhiteType ";
		switch( Param->type(WHITE) )
		{
			case PLAYERPC:
				(*Output) << "PC\n";
				break;
			case PLAYERTCP:
				(*Output) << "TCP\n";
				break;
			case PLAYEREMAIL:
				(*Output) << "Email\n";
				break;
			case PLAYERLOCAL:
			default:
				(*Output) << "Local\n";
				break;
		}
		(*Output) << "% KNIGHTS_CMD BlackType ";
		switch( Param->type(BLACK) )
		{
			case PLAYERPC:
				(*Output) << "PC\n";
				break;
			case PLAYERTCP:
				(*Output) << "TCP\n";
				break;
			case PLAYEREMAIL:
				(*Output) << "Email\n";
				break;
			case PLAYERLOCAL:
			default:
				(*Output) << "Local\n";
				break;
		}
		(*Output) << "% KNIGHTS_CMD WhiteTime " << whiteTime << "\n";
		(*Output) << "% KNIGHTS_CMD BlackTime " << blackTime << "\n";
		(*Output) << "% KNIGHTS_CMD DONE\n";
	}
	/* End of internal data save */

	(*Output) << "\n";
	TQStringList *list = notation(2);
	TQString SAN = list->join( " " );
	delete list;

	kdWarning() << SAN.right( 20 ) << endl;

	unsigned int pos = 80;
	unsigned int lastPos = 0;
	while( pos < SAN.length() )
	{
		while( SAN.at( pos ) != ' ' )
			pos--;
		SAN = SAN.replace( pos, 1, TQString("\n") );
		lastPos = pos;
		pos = lastPos + 80;
	}
	kdWarning() << SAN.right( 20 ) << endl;

	(*Output) << SAN << " " << TAG_Result << "\n\n";
	Save.close();
	return true;
}
///////////////////////////////////////
//
//	pgn::getch
//
///////////////////////////////////////
TQChar pgn::getch( void )
{
	TQChar c;

	c = currentLine.at(0);
	currentLine.remove( 0, 1 );
	return c;
}
///////////////////////////////////////
//
//	pgn::getword
//
///////////////////////////////////////
TQString pgn::getword( void )
{
	TQChar c;
	TQString word;
	
	do
	{
		c = getch();
	} while( c == ' ' );

	while( ( c != ' ' ) && ( c != TQChar::null ) )
	{
		word += c;
		c = getch();
	}
	return word;
}
///////////////////////////////////////
//
//	pgn::open
//
///////////////////////////////////////
bool pgn::open( const TQString &URL )
{
	close();
	if( !TDEIO::NetAccess::download( URL, tempFile ) )
		return false;

	File.setName( tempFile );
	if( !File.open( IO_ReadOnly ) )
	{
		close();
		return false;
	}
	Input.setDevice( &File );
	CurrentURL = URL;
	File.at(0);
	return true;
}
///////////////////////////////////////
//
//	pgn::close
//
///////////////////////////////////////
void pgn::close( void )
{
	if( !File.isOpen() )
	{
		File.close();
	}
	if( !tempFile.isEmpty() )
	{
		TDEIO::NetAccess::removeTempFile( tempFile );
		tempFile = "";
	}
}
///////////////////////////////////////
//
//	pgn::parseTag
//
///////////////////////////////////////
void pgn::parseTag( void )
{
	TQChar c;
	TQString Token;
	TQString Value;
	
	c = getch();
	while( c == ' ' ) c = getch();
	while( c != '\"' )
	{
		if( c == ' ' )
		{
			c = getch();
			continue;
		}
		Token += c;
		c = getch();
	}
	c = getch();
	while( c != '\"' )
	{
		Value += c;
		c = getch();
	}
	c = getch();
	while( c != ']' ) c = getch();
	/* Now Apply the Token/Value that we got */
	if( Token == "Site" )								TAG_Site = Value;
	else if( Token == "Date" )					TAG_Date = Value;
	else if( Token == "Round" )					TAG_Round = Value;
	else if( Token == "Result" )				TAG_Result = Value;

	else if( Token == "White" )					TAG_White = Value;
	else if( Token == "WhiteTitle" )		TAG_WhiteTitle = Value;
	else if( Token == "WhiteElo" )			TAG_WhiteElo = Value;
	else if( Token == "WhiteUSCF" )			TAG_WhiteUSCF = Value;
	else if( Token == "WhiteNA" )				TAG_WhiteNA = Value;
	else if( Token == "WhiteType" )			TAG_WhiteType = Value;

	else if( Token == "Black" )					TAG_Black = Value;
	else if( Token == "BlackTitle" )		TAG_BlackTitle = Value;
	else if( Token == "BlackElo" )			TAG_BlackElo = Value;
	else if( Token == "BlackUSCF" )			TAG_BlackUSCF = Value;
	else if( Token == "BlackNA" )				TAG_BlackNA = Value;
	else if( Token == "BlackType" )			TAG_BlackType = Value;

	else if( Token == "Time" )					TAG_Time = Value;
	else if( Token == "UTCTime" )				TAG_UTCTime = Value;
	else if( Token == "UTCDate" )				TAG_UTCDate = Value;

	else if( Token == "Event" )					TAG_Event = Value;
	else if( Token == "EventDate" )			TAG_EventDate = Value;
	else if( Token == "EventSponsor")		TAG_EventSponsor = Value;
	else if( Token == "Section" )				TAG_Section = Value;
	else if( Token == "Stage" )					TAG_Stage = Value;
	else if( Token == "Board" )					TAG_Board = Value;

	else if( Token == "Opening" )				TAG_Opening = Value;
	else if( Token == "Variation" )			TAG_Variation = Value;
	else if( Token == "SubVariation" )	TAG_SubVariation = Value;
	else if( Token == "ECO" )						TAG_ECO = Value;
	else if( Token == "NIC" )						TAG_NIC = Value;

	else if( Token == "TimeControl" )		TAG_TimeControl = Value;
	else if( Token == "Termination" )		TAG_Termination = Value;
	else if( Token == "SetUp" )					TAG_SetUp = Value;
	else if( Token == "FEN" )						TAG_FEN = Value;
	else if( Token == "Annotator" )			TAG_Annotator = Value;
	else if( Token == "Mode" )					TAG_Mode = Value;
	else if( Token == "PlyCount" )			TAG_PlyCount = Value;
}
///////////////////////////////////////
//
//	pgn::Parse_Annotation
//
///////////////////////////////////////
void pgn::parseAnnotation( const int fromRAVnum )
{
	Annotation *annon = new Annotation;
	TQChar c;
	
	c = getch();
	while( c != '}' )
	{
		if( c == TQChar::null )
		{
			if( Input.eof() ) break;
			currentLine = Input.readLine();
			c = ' ';
		}
		annon->text += c;
		c = getch();
	}
	annon->RAV = fromRAVnum;
	annotations.add( Moves.count() - 1, annon );
//	kdWarning() << "# " << annon.pos << " : " << annon.text << endl;
}
///////////////////////////////////////
//
//	pgn::Parse_RAV
//
///////////////////////////////////////
void pgn::parseRAV( void )
{
	int RAVLevel(1);
	Annotation *annon = new Annotation;
	TQChar c;
	
	while( RAVLevel )
	{
		c = getch();
		if( c == TQChar::null )
		{
			if( Input.eof() )
				break;
			currentLine = Input.readLine();
			c = ' ';
		}
		if( c == ')' )
		{
			RAVLevel--;
			if( !RAVLevel )
				break;
		}
		if( c == '(' )
		{
			RAVLevel++;
		}
		annon->text += c;
	}
	RAV.add( Moves.count() - 1, annon );
//	kdWarning() << "# " << annon.pos << " : " << annon.text << endl;
}
///////////////////////////////////////
//
//	pgn::parseKnightsData
//
///////////////////////////////////////
void pgn::parseKnightsData( void )
{
	TQString Key;
	TQString Value;
	
  Key = getword();
  if( Key == "DONE" )
  {
  	emit processSpecial();
  	return;
  }
  if( Key == "WhiteType" )
  {
  	Value = getword();
  	if( Value == "Local" ) Param->setType(WHITE, PLAYERLOCAL);
  	if( Value == "PC" ) Param->setType(WHITE, PLAYERPC);
  	if( Value == "TCP" ) Param->setType(WHITE, PLAYERTCP);
  	if( Value == "Email" ) Param->setType(WHITE, PLAYEREMAIL);
  	return;
  }
  if( Key == "BlackType" )
  {
  	Value = getword();
  	if( Value == "Local" ) Param->setType(BLACK, PLAYERLOCAL);
  	if( Value == "PC" ) Param->setType(BLACK, PLAYERPC);
  	if( Value == "TCP" ) Param->setType(BLACK, PLAYERTCP);
  	if( Value == "Email" ) Param->setType(BLACK, PLAYEREMAIL);
  	return;
  }
  if( Key == "WhiteTime" )
  {
  	Value = getword();
		whiteTime = Value.toInt();
  	return;
	}
  if( Key == "BlackTime" )
  {
  	Value = getword();
		blackTime = Value.toInt();
  	return;
	}
}
///////////////////////////////////////
//
//	pgn::print
//
///////////////////////////////////////
void pgn::print( void )
{
	if( !pgnView )
	{
		/* Allocate the Tab_PGNView */
		pgnView = new tab_pgnView( this, Resource );
		Resource->tabManager->addTab( pgnView, i18n( "%1 vs. %2" ).arg( TAG_White ).arg( TAG_Black ) );
		connect( pgnView, TQ_SIGNAL( destroyed() ), this, TQ_SLOT( childViewDestroyed() ) );
		pgnView->init();
	}
	pgnView->print();
}
///////////////////////////////////////
//
//	pgn::childViewDestroyed
//
///////////////////////////////////////
void pgn::childViewDestroyed( void )
{
	pgnView = NULL;
}
///////////////////////////////////////
//
//	pgn::getNAG
//
///////////////////////////////////////
TQString pgn::getNAG( int num )
{
	TQString Line;

	switch( num )
	{
		case 1:
			Line = i18n( "Good move" );
			break;
		case 2:
			Line = i18n( "Poor move" );
			break;
		case 3:
			Line = i18n( "Very good move" );
			break;
		case 4:
			Line = i18n( "Very poor move" );
			break;
		case 5:
			Line = i18n( "Speculative move" );
			break;
		case 6:
			Line = i18n( "Questionable move" );
			break;
		case 7:
			Line = i18n( "Forced move" );
			break;
		case 8:
			Line = i18n( "Singular move" );
			break;
		case 9:
			Line = i18n( "Worst move" );
			break;
		case 10:
			Line = i18n( "Drawish position" );
			break;
		case 11:
			Line = i18n( "Equal chances, quiet position" );
			break;
		case 12:
			Line = i18n( "Equal chances, active position" );
			break;
		case 13:
			Line = i18n( "Unclear position" );
			break;
		case 14:
			Line = i18n( "White has a slight advantage" );
			break;
		case 15:
			Line = i18n( "Black has a slight advantage" );
			break;
		case 16:
			Line = i18n( "White has a moderate advantage" );
			break;
		case 17:
			Line = i18n( "Black has a moderate advantage" );
			break;
		case 18:
			Line = i18n( "White has a decisive advantage" );
			break;
		case 19:
			Line = i18n( "Black has a decisive advantage" );
			break;
		case 20:
			Line = i18n( "White has a crushing advantage ( Black should resign )" );
			break;
		case 21:
			Line = i18n( "Black has a crushing advantage ( White should resign )" );
			break;
		case 22:
			Line = i18n( "White is in zugzwang" );
			break;
		case 23:
			Line = i18n( "Black is in zugzwang" );
			break;
		case 24:
			Line = i18n( "White has a slight space advantage" );
			break;
		case 25:
			Line = i18n( "Black has a slight space advantage" );
			break;
		case 26:
			Line = i18n( "White has a moderate space advantage" );
			break;
		case 27:
			Line = i18n( "Black has a moderate space advantage" );
			break;
		case 28:
			Line = i18n( "White has a decisive space advantage" );
			break;
		case 29:
			Line = i18n( "Black has a decisive space advantage" );
			break;
		case 30:
			Line = i18n( "White has a slight time ( development ) advantage" );
			break;
		case 31:
			Line = i18n( "Black has a slight time ( development ) advantage" );
			break;
		case 32:
			Line = i18n( "White has a moderate time ( development ) advantage" );
			break;
		case 33:
			Line = i18n( "Black has a moderate time ( development ) advantage" );
			break;
		case 34:
			Line = i18n( "White has a decisive time ( development ) advantage" );
			break;
		case 35:
			Line = i18n( "Black has a decisive time ( development ) advantage" );
			break;
		case 36:
			Line = i18n( "White has the initiative" );
			break;
		case 37:
			Line = i18n( "Black has the initiative" );
			break;
		case 38:
			Line = i18n( "White has a lasting initiative" );
			break;
		case 39:
			Line = i18n( "Black has a lasting initiative" );
			break;
		case 40:
			Line = i18n( "White has the attack" );
			break;
		case 41:
			Line = i18n( "Black has the attack" );
			break;
		case 42:
			Line = i18n( "White has insufficient compensation for material deficit" );
			break;
		case 43:
			Line = i18n( "Black has insufficient compensation for material deficit" );
			break;
		case 44:
			Line = i18n( "White has sufficient compensation for material deficit" );
			break;
		case 45:
			Line = i18n( "Black has sufficient compensation for material deficit" );
			break;
		case 46:
			Line = i18n( "White has more than adequate compensation for material deficit" );
			break;
		case 47:
			Line = i18n( "Black has more than adequate compensation for material deficit" );
			break;
		case 48:
			Line = i18n( "White has a slight center control advantage" );
			break;
		case 49:
			Line = i18n( "Black has a slight center control advantage" );
			break;
		case 50:
			Line = i18n( "White has a moderate center control advantage" );
			break;
		case 51:
			Line = i18n( "Black has a moderate center control advantage" );
			break;
		case 52:
			Line = i18n( "White has a decisive center control advantage" );
			break;
		case 53:
			Line = i18n( "Black has a decisive center control advantage" );
			break;
		case 54:
			Line = i18n( "White has a slight kingside control advantage" );
			break;
		case 55:
			Line = i18n( "Black has a slight kingside control advantage" );
			break;
		case 56:
			Line = i18n( "White has a moderate kingside control advantage" );
			break;
		case 57:
			Line = i18n( "Black has a moderate kingside control advantage" );
			break;
		case 58:
			Line = i18n( "White has a decisive kingside control advantage" );
			break;
		case 59:
			Line = i18n( "Black has a decisive kingside control advantage" );
			break;
		case 60:
			Line = i18n( "White has a slight queenside control advantage" );
			break;
		case 61:
			Line = i18n( "Black has a slight queenside control advantage" );
			break;
		case 62:
			Line = i18n( "White has a moderate queenside control advantage" );
			break;
		case 63:
			Line = i18n( "Black has a moderate queenside control advantage" );
			break;
		case 64:
			Line = i18n( "White has a decisive queenside control advantage" );
			break;
		case 65:
			Line = i18n( "Black has a decisive queenside control advantage" );
			break;
		case 66:
			Line = i18n( "White has a vulnerable first rank" );
			break;
		case 67:
			Line = i18n( "Black has a vulnerable first rank" );
			break;
		case 68:
			Line = i18n( "White has a well protected first rank" );
			break;
		case 69:
			Line = i18n( "Black has a well protected first rank" );
			break;
		case 70:
			Line = i18n( "White has a poorly protected king" );
			break;
		case 71:
			Line = i18n( "Black has a poorly protected king" );
			break;
		case 72:
			Line = i18n( "White has a well protected king" );
			break;
		case 73:
			Line = i18n( "Black has a well protected king" );
			break;
		case 74:
			Line = i18n( "White has a poorly placed king" );
			break;
		case 75:
			Line = i18n( "Black has a poorly placed king" );
			break;
		case 76:
			Line = i18n( "White has a well placed king" );
			break;
		case 77:
			Line = i18n( "Black has a well placed king" );
			break;
		case 78:
			Line = i18n( "White has a very weak pawn structure" );
			break;
		case 79:
			Line = i18n( "Black has a very weak pawn structure" );
			break;
		case 80:
			Line = i18n( "White has a moderately weak pawn structure" );
			break;
		case 81:
			Line = i18n( "Black has a moderately weak pawn structure" );
			break;
		case 82:
			Line = i18n( "White has a moderately strong pawn structure" );
			break;
		case 83:
			Line = i18n( "Black has a moderately strong pawn structure" );
			break;
		case 84:
			Line = i18n( "White has a very strong pawn structure" );
			break;
		case 85:
			Line = i18n( "Black has a very strong pawn structure" );
			break;
		case 86:
			Line = i18n( "White has poor knight placement" );
			break;
		case 87:
			Line = i18n( "Black has poor knight placement" );
			break;
		case 88:
			Line = i18n( "White has good knight placement" );
			break;
		case 89:
			Line = i18n( "Black has good knight placement" );
			break;
		case 90:
			Line = i18n( "White has poor bishop placement" );
			break;
		case 91:
			Line = i18n( "Black has poor bishop placement" );
			break;
		case 92:
			Line = i18n( "White has good bishop placement" );
			break;
		case 93:
			Line = i18n( "Black has good bishop placement" );
			break;
		case 94:
			Line = i18n( "White has poor rook placement" );
			break;
		case 95:
			Line = i18n( "Black has poor rook placement" );
			break;
		case 96:
			Line = i18n( "White has good rook placement" );
			break;
		case 97:
			Line = i18n( "Black has good rook placement" );
			break;
		case 98:
			Line = i18n( "White has poor queen placement" );
			break;
		case 99:
			Line = i18n( "Black has poor queen placement" );
			break;
		case 100:
			Line = i18n( "White has good queen placement" );
			break;
		case 101:
			Line = i18n( "Black has good queen placement" );
			break;
		case 102:
			Line = i18n( "White has poor piece coordination" );
			break;
		case 103:
			Line = i18n( "Black has poor piece coordination" );
			break;
		case 104:
			Line = i18n( "White has good piece coordination" );
			break;
		case 105:
			Line = i18n( "Black has good piece coordination" );
			break;
		case 106:
			Line = i18n( "White has played the opening very poorly" );
			break;
		case 107:
			Line = i18n( "Black has played the opening very poorly" );
			break;
		case 108:
			Line = i18n( "White has played the opening poorly" );
			break;
		case 109:
			Line = i18n( "Black has played the opening poorly" );
			break;
		case 110:
			Line = i18n( "White has played the opening well" );
			break;
		case 111:
			Line = i18n( "Black has played the opening well" );
			break;
		case 112:
			Line = i18n( "White has played the opening very well" );
			break;
		case 113:
			Line = i18n( "Black has played the opening very well" );
			break;
		case 114:
			Line = i18n( "White has played the middlegame very poorly" );
			break;
		case 115:
			Line = i18n( "Black has played the middlegame very poorly" );
			break;
		case 116:
			Line = i18n( "White has played the middlegame poorly" );
			break;
		case 117:
			Line = i18n( "Black has played the middlegame poorly" );
			break;
		case 118:
			Line = i18n( "White has played the middlegame well" );
			break;
		case 119:
			Line = i18n( "Black has played the middlegame well" );
			break;
		case 120:
			Line = i18n( "White has played the middlegame very well" );
			break;
		case 121:
			Line = i18n( "Black has played the middlegame very well" );
			break;
		case 122:
			Line = i18n( "White has played the ending very poorly" );
			break;
		case 123:
			Line = i18n( "Black has played the ending very poorly" );
			break;
		case 124:
			Line = i18n( "White has played the ending poorly" );
			break;
		case 125:
			Line = i18n( "Black has played the ending poorly" );
			break;
		case 126:
			Line = i18n( "White has played the ending well" );
			break;
		case 127:
			Line = i18n( "Black has played the ending well" );
			break;
		case 128:
			Line = i18n( "White has played the ending very well" );
			break;
		case 129:
			Line = i18n( "Black has played the ending very well" );
			break;
		case 130:
			Line = i18n( "White has slight counterplay" );
			break;
		case 131:
			Line = i18n( "Black has slight counterplay" );
			break;
		case 132:
			Line = i18n( "White has moderate counterplay" );
			break;
		case 133:
			Line = i18n( "Black has moderate counterplay" );
			break;
		case 134:
			Line = i18n( "White has decisive counterplay" );
			break;
		case 135:
			Line = i18n( "Black has decisive counterplay" );
			break;
		case 136:
			Line = i18n( "White has moderate time control pressure" );
			break;
		case 137:
			Line = i18n( "Black has moderate time control pressure" );
			break;
		case 138:
			Line = i18n( "White has severe time control pressure" );
			break;
		case 139:
			Line = i18n( "Black has severe time control pressure" );
		case 140:
			Line = i18n( "With the idea..." );
			break;
		case 141:
			Line = i18n( "Aimed against..." );
			break;
		case 142:
			Line = i18n( "Better Move" );
			break;
		case 143:
			Line = i18n( "Worse Move" );
			break;
		case 144:
			Line = i18n( "Equivalent move" );
			break;
		case 145:
			Line = i18n( "Editor's Remark" );
			break;
		case 146:
			Line = i18n( "Novelty" );
			break;
		case 147:
			Line = i18n( "Weak point" );
			break;
		case 148:
			Line = i18n( "Endgame" );
			break;
		case 149:
			Line = i18n( "Line" );
			break;
		case 150:
			Line = i18n( "Diagonal" );
			break;
		case 151:
			Line = i18n( "White has a pair of Bishops" );
			break;
		case 152:
			Line = i18n( "Black has a pair of Bishops" );
			break;
		case 153:
			Line = i18n( "Bishops of opposite color" );
			break;
		case 154:
			Line = i18n( "Bishops of same color" );
			break;
		case 190:
			Line = i18n( "Etc." );
			break;
		case 191:
			Line = i18n( "Doubled pawns" );
			break;
		case 192:
			Line = i18n( "Isolated pawn" );
			break;
		case 193:
			Line = i18n( "Connected pawns" );
			break;
		case 194:
			Line = i18n( "Hanging pawns" );
			break;
		case 195:
			Line = i18n( "Backwards pawn" );
			break;
		default:
			Line = "";
			break;
	}
	return Line;
}

