/**
 * \file Parser.cpp
 * 
 * Implementation of the Parser class
 */

#include "Common/Protocol/Parser.h"
#include "Common/Protocol/ParseStrings.h"
#include "Common/Protocol/ParseStructs.h"
#include "Common/World/ParamStructs.h"
#include "Common/Tasks.h"
#include "Common/Support/Debug.h"
#include <stdio.h>
#include <string.h>

/**
 * Parser constructor
 */
Parser::Parser() : Module("Parser", "Parser module", "v0.1.003")
{
	teamName[0] = 0;
	synchro = NULL;

#ifndef COACH
	realSide = LEFT;
#endif

	Main::GetInstance()->RegisterModule(this, MESSAGE_PROCESS_TASK);
}

/**
 * Parser initialization
 * \param argc Number of program arguments
 * \param argv Program arguments themselves
 * \returns Error status: INIT_OK or INIT_ERR
 */
int Parser::Init(int argc, char** argv, int)
{
#ifdef COACH
	synchro = (CoachSynchronizationInterface*) Main::GetInstance()->GetInterface(SYNCHRONIZATION_TASK);
#else
	synchro = (SynchronizationInterface*) Main::GetInstance()->GetInterface(SYNCHRONIZATION_TASK);
	memory = (MemoryInterface*) Main::GetInstance()->GetInterface(MEMORY_TASK);
	tactics = (TacticsInterface*) Main::GetInstance()->GetInterface(TACTICS_TASK);
#endif

	return INIT_OK;
}


Interface* Parser::GetInterface(int task) const
{
	return (MsgProcessInterface*) this;
}

void Parser::SetTeamName(const char* name)
{
	strncpy(teamName, name, 32);
	teamName[31] = 0;
}

void Parser::SetRealSide(RealSide rs)
{
#ifndef COACH
	realSide = rs;
#endif // COACH
}

/**
 * Parse object in brackets
 *
 * str: "(xxx aaa (y x)) xx"
 * out: "xxx aaa (y x)"
 * returns: pointer to first character of " xx"
 *
 * \param str String to parse
 * \param out Buffer where text inside brackets will be copied
 * \return Pointer to first character after closing bracket or NULL on error
 */
const char* Parser::ParseBracket(const char* str, char* out)
{
	if(str == NULL || out == NULL) return NULL;
	int brackets = 1;

	// Find first bracket
	while(*str != '\0' && *str != '(') str++;
	if(*str == '\0') return NULL;

	// Ci sme vnutri uvodzoviek
	bool quotes = false;

	while(brackets > 0)
	{
		str++;
		switch(*str)
		{
			case '(':
				if(!quotes) brackets++;
				break;
			case ')':
				if(!quotes) brackets--;
				break;
			case 0:
				return NULL;
			case '\"': //uvodzovka
				quotes = !quotes;
				break;
			default:
				break;
		}

		if(brackets > 0)
		{
			*out = *str;
			out++;
		}
		else
		{
			*out = '\0';
		}
	}

	str++;
	return str;
}

/**
 * Parse object
 *
 * str: "xxx aaa (y x)"
 * out: "xxx"
 * returns: pointer to first character of " aaa (y x)"
 *
 * \param str String to parse
 * \param out Buffer where first object will be copied
 * \return Pointer to first character after the object or NULL on error
 */
const char* Parser::ParseObj(const char* str,char* out)
{
	if(str == NULL || out == NULL) return NULL;

	// Consume leading spaces
	while(*str == ' ') str++;
	if(*str == 0) return NULL;

	if(*str == '\"')
	{
		str++;
		while(*str != '\"')
		{
			*out = *str;
			if(*str == '\0') return NULL;
			out++;
			str++;
		}
		str++;
	}
	else while(*str != '\0' && *str != ' ')
	{
		*out = *str;
		out++;
		str++;
	}

	*out = '\0';
	return str;
}

/**
 * Parse message received from server. This method
 * calls all other Parse* methods.
 * \param msg Message to parse
 * \returns Error status: 0 for success; != 0 for error
 */
int Parser::ParseMsg(const char* msg)
{
	static char message[BUFFERSIZE];
	
	if(!ParseBracket(msg, message))
	{
		WARNN("message not starting with a bracket");
		return 1;						// false
	}

	static char typ[64];
	const char* nextStr = ParseObj(message, typ);

	if(nextStr == NULL) return 1;		// false

	int success = 0;

#ifdef COACH
	if(strcmp(typ, "see_global") == 0) success = ParseSeeGlobal(nextStr);
#else  // COACH
	if(strcmp(typ, "sense_body") == 0) success = ParseSenseBody(nextStr);
	else if(strcmp(typ, "see") == 0) success = ParseSee(nextStr);
#endif // COACH
	else if(strcmp(typ, "ok") == 0) success = ParseOk(nextStr);
	else if(strcmp(typ, "hear") == 0) success = ParseHear(nextStr);
	else if(strcmp(typ, "change_player_type") == 0) success = ParseChangePT(nextStr);
	else if(strcmp(typ, "player_type") == 0) success = ParsePlayerType(nextStr);
	else if(strcmp(typ, "init") == 0) success = ParseInit(nextStr);
	else if(strcmp(typ, "server_param") == 0) success = ParseServerParam(nextStr);
	else if(strcmp(typ, "player_param") == 0) success = ParsePlayerParam(nextStr);
	else if(strcmp(typ, "score") == 0) success = ParseScore(nextStr);

	else if(strcmp(typ, "error") == 0) WARNN("server reports \"%s\"", msg);
	else if(strcmp(typ, "warning") == 0) WARNN("server reports \"%s\"", msg);
	else if(strcmp(typ, "can't") == 0) WARNN("server reports \"%s\"", msg);
	else WARNN("not parsed: %s", msg);

	return success;
}

/**
 * Parse score message
 * \param msg Message to parse
 * \return Error status: 0 for success; != 0 for error
 */
int Parser::ParseScore(const char* msg)
{
	int cas;
	unsigned ourScore, theirScore;
	
	if(sscanf(msg, " %d %d %d", &cas, &ourScore, &theirScore) != 3)
	{
		return 1;
	}

	if(synchro != NULL) synchro->OnScore(cas, ourScore, theirScore);

	return 0;
}

/**
 * Parse init message
 * \param msg Message to parse
 * \return Error status: 0 for success; != 0 for error
 */
int Parser::ParseInit(const char* msg)
{
	char side;

#ifdef COACH
	if(sscanf(msg, " %c", &side) != 1) return 1;
	
	// Rename debug file to identify coach
	char id[64];
	sprintf(id, "c__%c", side);
	DBG_SET_ID(id);

	// Call the callback
	if(synchro != NULL) synchro->OnInit(side == 'l');
#else
	int num;
	char mode[32];

	if(sscanf(msg, " %c %d %s", &side, &num, mode) != 3) return 1;

	if(side == 'l') realSide = LEFT;
	else if(side == 'r') realSide = RIGHT;
	else return 1;

	// Rename debug file to show player team and number
#ifdef GOALIE
	char type = 'g';
#else
	char type = 'p';
#endif

	char id[64];
	sprintf(id, "%c%02d%c", type, num, side);
	DBG_SET_ID(id);

	// Call the callback
	if(synchro != NULL) synchro->OnInit(realSide, num, ParsePlayMode(mode));
#endif

	return 0;
}

/**
 * Parse hear message
 * \param msg Message to parse
 * \return Error status: 0 for success; != 0 for error
 */
int Parser::ParseHear(const char* msg)
{
	//DBGN("hear %s", msg);

	/* A player may hear:
     *  from referee (hear TIME referee PLAY_MODE)
     * from offline coach (hear TIME coach "MSG")
     * from new online coach (hear TIME online_coach_{left|right} TIME_RECEIVED_BY_SERVER CLANG_MSG)
     *  from player to itself (hear TIME self "MSG")
     * from player to others (hear TIME DIRECTION <opp|our UNUM> "MSG") 
     * from player to others [disabled by default yet posible] (hear TIME <opp|our UNUM>)
	 */
	/* A coach may hear:
     *  from referee (hear TIME referee PLAY_MODE)
     * ??? from offline coach (hear TIME coach "MSG")
     * from players (hear TIME (p "TEAMNAME" UNUM) "MSG") 
	 */
	 
	static char tmp[BUFFERSIZE];

	// Parse time
	int time;
	msg = ParseObj(msg, tmp);
	if(msg == NULL) return 1;
	if(sscanf(tmp, "%d", &time) != 1) return 1;

	// Parse message source
#ifdef COACH
	// Coach gets player info in brackets
	if(msg[1] == '(') msg = ParseBracket(msg, tmp);
	else msg = ParseObj(msg, tmp);
#else // COACH
	msg = ParseObj(msg, tmp);
#endif // COACH

	if(msg == NULL) return 1;

	// Who did send the message?
	if(strcmp("referee", tmp) == 0)
	{
		msg = ParseObj(msg, tmp);
		if(msg == NULL) return 1;

		PlayMode mode = ParsePlayMode(tmp);

		if(mode != PM_Null && synchro != NULL) synchro->OnChangeMode(time, mode);
	}
	else if(strcmp("self", tmp) == 0) {}  // ignore myself 
#ifndef COACH
	else if(strcmp("online_coach_left", tmp) == 0) 
	{
//		msg = ParseObj(msg, tmp); // time
		CLangParseMsg(msg);
	}
	else if(strcmp("online_coach_right", tmp) == 0) 
	{
//		msg = ParseObj(msg, tmp); // time
		CLangParseMsg(msg);
	}
#endif // COACH
	else if(strcmp("coach", tmp) == 0) {}
	else
	{
		static char playerMsg[BUFFERSIZE];

#ifdef COACH
		// Message from a player - (p "TEAMNAME" UNUM) "MSG"
		static char tmp2[BUFFERSIZE];
		
		// playerMsg is the actual message said
		msg = ParseObj(msg, playerMsg);
		if(msg == NULL) return 1;

		// tmp2 should be "p"
		msg = ParseObj(tmp, tmp2);
		if(msg == NULL || strcmp(tmp2, "p") != 0) return 1;

		// team name would be in tmp
		msg = ParseObj(msg, tmp);
		if(msg == NULL) return 1;

		// uniform number would be in tmp2
		msg = ParseObj(msg, tmp2);
		if(msg == NULL) return 1;
		int uniformNumber = atoi(tmp2);
		if(uniformNumber < 1 || uniformNumber > 11) return 1;

		bool ourTeam = (strcmp(teamName, tmp) == 0);
		//DBGN("At %i: %s player %i says %s.", time, ourTeam ? "our" : "their", uniformNumber, playerMsg);

		if(synchro != NULL)
			synchro->OnHear(time, ourTeam, uniformNumber, playerMsg);
#else  // COACH 
		// Message from a player - DIRECTION <opp|our UNUM> "MSG"
		// Ignore the second variation - <opp|our UNUM>
		float direction;
		if(sscanf(tmp, "%f", &direction) != 1) return 1;
		
		// Team (our or opp) goes to tmp
		msg = ParseObj(msg, tmp);
		if(msg == NULL) return 1;

		int uniformNumber = 0;
		bool ourTeam = (strcmp("our", tmp) == 0);
		if(ourTeam)
		{
			// Uniform number goes to tmp
			msg = ParseObj(msg, tmp);
			if(msg == NULL) return 1;
			uniformNumber = atoi(tmp);
			if(uniformNumber < 1 || uniformNumber > 11) return 1;
		}

		// Actual message
		msg = ParseObj(msg, playerMsg);
		if(msg == NULL) return 1;

		//DBGN("At %i: %s player %i (dir %f) says %s.", time, ourTeam ? "our" : "their", uniformNumber, direction, playerMsg);

		if(synchro != NULL)
			synchro->OnHear(time, direction, ourTeam, uniformNumber, playerMsg);
#endif // COACH
	}

	return 0;
}

#ifndef COACH
/**
 * Parse sense_body message
 * \param msg Message to parse
 * \return Error status: 0 for success; != 0 for error
 */
int Parser::ParseSenseBody(const char* msg)
{
	static char item[128];
	static char itemType[64];
	static char tmp1[32], tmp2[32];
	static const char* nextStr;

	// POZOR presne tato instancia SENSE_BODY sa pouziva
	// vselikde v programe (na konci tejto metody na nu
	// odovzdame pointer). Ak nebude static, cele to zhaluzi.
	// Mimochodom to je vynikajuci napad :]
	static SENSE_BODY sb;
	memset(&sb, 0, sizeof(SENSE_BODY));

	// Time
	msg = ParseObj(msg, item);
	if(sscanf(item, "%d", &sb.time) != 1) return 1;

	// Rest of message
	msg = ParseBracket(msg, item);
	while(msg != NULL) {
		nextStr = ParseObj(item, itemType);
		if(nextStr == NULL) return 1;

		if(strcmp(itemType, "view_mode") == 0)
		{
			if(sscanf(nextStr, " %s %s", tmp1, tmp2) != 2) return 1;

			if(strcmp(tmp1, "high") == 0) sb.viewQuality = HIGH_QUALITY;
			else if(strcmp(tmp1, "low") == 0) sb.viewQuality = LOW_QUALITY;
			else return 1;

			if(strcmp(tmp2, "narrow") == 0) sb.viewWidth = NARROW_VIEW;
			else if(strcmp(tmp2, "normal") == 0) sb.viewWidth = NORMAL_VIEW;
			else if(strcmp(tmp2, "wide") == 0) sb.viewWidth = WIDE_VIEW;
			else return 1;
		}
		else if(strcmp(itemType, "stamina") == 0)
		{
			if(sscanf(nextStr, " %f %f", &sb.stamina, &sb.effort) != 2) return 1;
		}
		else if(strcmp(itemType, "speed") == 0)
		{
			int rval = sscanf(nextStr, " %f %f", &sb.speedSize, &sb.speedDirection);
			if(rval != 2 && rval != 1) return 1;
		}
		else if(strcmp(itemType, "head_angle") == 0)
		{
			if(sscanf(nextStr, " %f", &sb.headAngle) != 1) return 1;
		}
		else if(strcmp(itemType, "tackle") == 0)
		{
			// MH> added (tackle (expires <EXPIRES>) (count <COUNT>))
			if(sscanf(nextStr, " ( expires %d ) ( count %d )",
				&sb.tackleExpires, &sb.counts.tackleCount) != 2) return 1;
		}
		else if(strcmp(itemType, "focus") == 0)
		{
			// MH> added
			// (focus (target none) (count <COUNT>))
			// (focus (target {l|r} <UNUM>) (count <COUNT>)
			nextStr = ParseBracket(nextStr, tmp1);
			if(nextStr == NULL) return 1;

			if(strcmp(tmp1, "target none") == 0) sb.focusedNumber = 0;
			else
			{
				char side;
				if(sscanf(tmp1, " target %c %d", &side, &sb.focusedNumber) != 2) return 1;
				sb.focusedSide = (side == 'l' && realSide == LEFT) || (side == 'r' && realSide == RIGHT);
			}

			if(sscanf(nextStr, " ( count %d )", &sb.counts.attentiontoCount) != 1) return 1;
		}
		else if(strcmp(itemType, "arm") == 0)
		{
			// MH> added
			// (arm (movable <MOVABLE>) (expires <EXPIRES>)
			// (target <DIST> <DIR>) (count <COUNT>))'
			if(sscanf(nextStr, 
				" ( movable %d ) ( expires %d ) ( target %f %f ) ( count %d )",
				&sb.armMovableAfter, &sb.armExpires, &sb.armDistance, 
				&sb.armDirection, &sb.counts.pointtoCount) != 5) return 1;
		}
		else if(strcmp(itemType, "kick") == 0)
		{
			if(sscanf(nextStr, " %d", &sb.counts.kickCount) != 1) return 1;
		}
		else if(strcmp(itemType, "dash") == 0)
		{
			if(sscanf(nextStr, " %d", &sb.counts.dashCount) != 1) return 1;
		}
		else if(strcmp(itemType, "turn") == 0)
		{
			if(sscanf(nextStr, " %d", &sb.counts.turnCount) != 1) return 1;
		}
		else if(strcmp(itemType, "say") == 0)
		{
			if(sscanf(nextStr, " %d", &sb.counts.sayCount) != 1) return 1;
		}
		else if(strcmp(itemType, "turn_neck") == 0)
		{
			if(sscanf(nextStr, " %d", &sb.counts.turnNeckCount) != 1) return 1;
		}
		else if(strcmp(itemType, "catch") == 0)
		{
			if(sscanf(nextStr, " %d", &sb.counts.catchCount) != 1) return 1;
		}
		else if(strcmp(itemType, "move") == 0)
		{
			if(sscanf(nextStr, " %d", &sb.counts.moveCount) != 1) return 1;
		}
		else if(strcmp(itemType, "change_view") == 0)
		{
			if(sscanf(nextStr, " %d", &sb.counts.changeViewCount) != 1) return 1;
		}
		else
		{
			WARNN("unknown field in sense_body: %s", item);
		}

		msg = ParseBracket(msg, item);
	}

	if(synchro) synchro->OnSenseBody(&sb);

	return 0;
}

/**
 * Parse see message
 * \param msg Message to parse
 * \return Error status: 0 for success; != 0 for error
 */
int Parser::ParseSee(const char* msg)
{
//	DBGN("%s", msg);

	static VISUAL_INFO info;
	memset(&info, 0, sizeof(VISUAL_INFO));

	static char item[256];
	static char seenObj[64];
	static char typeObj[32];

	static char tag1[32];

	int rval;
	const char* nextStr;
	const char* nextStr2;

	msg = ParseObj(msg, item);
	if(sscanf(item, "%d", &info.time) != 1) return 1;

	msg = ParseBracket(msg, item);

	while(msg)
	{
		nextStr = ParseBracket(item, seenObj);
		if(!nextStr) return 1;

		nextStr2 = ParseObj(seenObj, typeObj);
		if(!nextStr2) return 1;

		switch(typeObj[0])
		{
			case 'p':			// Player
				nextStr2 = ParseObj(nextStr2, tag1);
				
				if(nextStr2 != NULL)
				{
					if(strcmp(teamName, tag1) == 0)			// Our player
					{
						rval = ParseSeePlayer(nextStr2, nextStr, 
							&info.ours[info.oursCnt]);
						if(rval != 0)
						{
							WARNN("error parsing player %s", item);
							return 1;
						}
						
						//DBGN("see our player %i", info.ours[info.oursCnt].uniformNumber);
						info.oursCnt++;
					}
					else									// Their player
					{
						rval = ParseSeePlayer(nextStr2, nextStr, 
							&info.their[info.theirCnt]);
						if(rval != 0)
						{
							WARNN("error parsing player %s", item);
							return 1;
						}
						
						info.theirCnt++;
					}
				}
				else										// Unknown player
				{
					rval = ParseSeePlayer("", nextStr, &info.unknown[info.unknownCnt]);
					if(rval != 0)
					{
						WARNN("error parsing player %s", item);
						return 1;
					}
						
					info.unknownCnt++;
				}

				break;

			case 'P':			// Player near us
				rval = ParseSeePlayer("", nextStr, &info.nearby[info.nearbyCnt]);
				if(rval != 0)
				{
					WARNN("error parsing player %s", item);
					return 1;
				}
						
				info.nearbyCnt++;
				break;

			case 'f':			// Flag
				info.landmarks[info.landmarkCnt].type = ParseSeeFlagType(nextStr2);
				if(info.landmarks[info.landmarkCnt].type == NoLandmark)
				{
					WARNN("unknown flag type %s", nextStr2);
					return 1;
				}

				rval = ParseSeeLandmark(nextStr, &info.landmarks[info.landmarkCnt]);
				if(rval != 0)
				{
					WARNN("error parsing flag: %s", item);
					return 1;
				}

				info.landmarkCnt++;
				break;

			case 'F':			// Flag near player (not used)
				break;

			case 'g':			// Goal
				if(!ParseObj(nextStr2, tag1)) return 1;

				// Find out goal type
				if((tag1[0] == 'l' && realSide == LEFT) || (tag1[0] == 'r' && realSide == RIGHT))
					info.landmarks[info.landmarkCnt].type = GOAL_L;
				else if((tag1[0] == 'r' && realSide == LEFT) || (tag1[0] == 'l' && realSide == RIGHT))
					info.landmarks[info.landmarkCnt].type = GOAL_R;
				else
				{
					WARNN("unknown flag type %s", nextStr2);
					return 1;
				}

				// Parse its position
				rval = ParseSeeLandmark(nextStr, &info.landmarks[info.landmarkCnt]);
				if(rval != 0)
				{
					WARNN("error parsing goal: %s", item);
					return 1;
				}

				info.landmarkCnt++;
				break;
			
			case 'G':			// Goal near us (not used)
				break;

			case 'b':			// Ball
			case 'B':			// Ball near us
				rval = ParseSeeLandmark(nextStr, &info.ball);
				info.ballCnt = 1;
				if(rval != 0)
				{
					WARNN("error parsing ball: %s", item);
					return 1;
				}

				break;

			case 'l':			// Line
				if(!ParseObj(nextStr2, tag1)) return 1;
				else if((tag1[0] == 't' && realSide == LEFT) || (tag1[0] == 'b' && realSide == RIGHT))
					info.lines[info.lineCnt].type = Top;
				else if((tag1[0] == 'b' && realSide == LEFT) || (tag1[0] == 't' && realSide == RIGHT))
					info.lines[info.lineCnt].type = Bottom;
				else if((tag1[0] == 'l' && realSide == LEFT) || (tag1[0] == 'r' && realSide == RIGHT))
					info.lines[info.lineCnt].type = Left;
				else if((tag1[0] == 'r' && realSide == LEFT) || (tag1[0] == 'l' && realSide == RIGHT))
					info.lines[info.lineCnt].type = Right;
				else return 1;

				rval = sscanf(nextStr, " %f %f",
					&info.lines[info.lineCnt].dist, &info.lines[info.lineCnt].dir);

				if(rval != 2)
				{
					WARNN("error parsing line: %s", item);
					return 1;
				}

				info.lineCnt++;
				break;
		
			default:
				WARNN("unknown object %s", typeObj);
				break;
		}

		msg = ParseBracket(msg, item);
	}

	if(synchro) synchro->OnSee(&info);
	return 0;
}
#endif // ifndef COACH

/**
 * Parse ok message - feedback from server
 * e.g. "ok eye on", "ok teamnames ...", "ok change_player_type ..."
 * \param msg Message to parse
 * \return Error status: 0 for success; != 0 for error
 * \author Peter Trebaticky
 */
int Parser::ParseOk(const char* msg)
{
#ifdef COACH
	if(strncmp(msg, " team_graphic ", 14) == 0)
	{
		int x, y;
		if(sscanf(msg, " team_graphic %d %d", &x, &y) == 2)
			synchro->OnOkTeamGraphic(x, y);
	}
#endif // COACH

	return 0;
}

#ifdef COACH 
/**
 * Parse see_global message (only for coach)
 * \param msg Message to parse
 * \return Error status: 0 for success; != 0 for error
 * \author Peter Trebaticky
 */
int Parser::ParseSeeGlobal(const char* msg)
{
	static COACH_VISUAL_INFO info;
	memset(&info, 0, sizeof(COACH_VISUAL_INFO));
	static AGENT agentHelp;   // Just to use it with ParseSeePlayer(...)
	static LANDMARK ballHelp; // Just to use it with ParseSeeLandmark(...)

	static char item[256];
	static char seenObj[64];
	static char typeObj[32];

	static char tag1[32];
	static char tag2[32];
	static char tag3[32];

	int rval;
	const char* nextStr;
	const char* nextStr2;

	msg = ParseObj(msg, item);
	if(sscanf(item, "%d", &info.time) != 1) return 1;

// ak sa nemylim, tu maju bug, nevyhodnoti to posledneho hraca.
	
// sakra vsak to je cele divne, toto mam pocit ze nema nic spolocne so spravou see_global	
	
	msg = ParseBracket(msg, item);

	while(msg != NULL)
	{
		nextStr = ParseBracket(item, seenObj);
		if(!nextStr) return 1;

		nextStr2 = ParseObj(seenObj, typeObj);
		if(!nextStr2) return 1;

		switch(typeObj[0])
		{
			case 'p':			// Player
				nextStr2 = ParseObj(nextStr2, tag1);
				
				if(nextStr2 != NULL)
				{
					if(strcmp(teamName, tag1) == 0)			// Our player
					{
						rval = ParseSeePlayer(nextStr2, nextStr, &agentHelp);
						if(rval != 0)
						{
							WARNN("error parsing player %s", item);
							return 1;
						}

						// Copy acquired information from help variable
						info.ours[info.oursCount].uniformNumber = 
							agentHelp.uniformNumber;
						info.ours[info.oursCount].goalie = agentHelp.goalie;
						// Matus: toto vyzera divne, ked sa nastavuje X a Y suradnica zo
						// vzdialenosti a uhla... ale asi to je dobre (??).
						info.ours[info.oursCount].pos.SetX(agentHelp.dist);
						info.ours[info.oursCount].pos.SetY(agentHelp.dir);
						info.ours[info.oursCount].speed.SetX(agentHelp.distChange);
						info.ours[info.oursCount].speed.SetY(agentHelp.dirChange);
						info.ours[info.oursCount].bodyFacingDir =
							agentHelp.bodyFacingDir;
						info.ours[info.oursCount].headFacingDir =
							agentHelp.headFacingDir;

						info.oursCount++;
					}
					else									// Their player
					{
						rval = ParseSeePlayer(nextStr2, nextStr, &agentHelp);
						if(rval != 0)
						{
							WARNN("error parsing player %s", item);
							return 1;
						}

						// Copy acquired information from help variable
						info.their[info.theirCount].uniformNumber = 
							agentHelp.uniformNumber;
						info.their[info.theirCount].goalie = agentHelp.goalie;
						info.their[info.theirCount].pos.SetX(agentHelp.dist);
						info.their[info.theirCount].pos.SetY(agentHelp.dir);
						info.their[info.theirCount].speed.SetX(agentHelp.distChange);
						info.their[info.theirCount].speed.SetY(agentHelp.dirChange);
						info.their[info.theirCount].bodyFacingDir =
							agentHelp.bodyFacingDir;
						info.their[info.theirCount].headFacingDir =
							agentHelp.headFacingDir;
						
						info.theirCount++;
					}
				}

				break;

			case 'g':			// Goal (not useful for coach...)

				break;
			
			case 'b':			// Ball
				rval = ParseSeeLandmark(nextStr, &ballHelp);
				if(rval != 0)
				{
					WARNN("error parsing ball: %s", item);
					return 1;
				}

				// Copy acquired information from help variable
				info.ball.pos.SetX(ballHelp.dist);
				info.ball.pos.SetY(ballHelp.dir);
				info.ball.speed.SetX(ballHelp.distChange);
				info.ball.speed.SetY(ballHelp.dirChange);
				
				break;

			default:
				WARNN("unknown object %s", typeObj);
				break;
		}

		msg = ParseBracket(msg, item);
	}

	if(synchro != NULL) synchro->OnSeeGlobal(&info);
	return 0;
}
#endif // COACH

/**
 * Parse seen player
 * \param str1 Whatever was left from object description after parsing team name
 * \param str2 Whatever is after the object description
 * \param agent Struct AGENT where we store parsed information
 * \return Error status: 0 for success; != 0 for error
 */
int Parser::ParseSeePlayer(const char* str1, const char* str2, AGENT* agent)
{
//	DBGN("parsing player: \"%s\" \"%s\"", str1, str2);
	
	static char tag1[32];

	// Parse uniform information
	int rval = sscanf(str1, " %d %s", &agent->uniformNumber, tag1);

	if(rval <= 0) agent->uniformNumber = 0;
	else if(rval == 1) agent->goalie = false;
	else if(rval == 2 && strcmp("goalie", tag1) == 0) agent->goalie = true;
	else return 1;

	// Parse player position and state
	float tmp[7];
	rval = sscanf(str2, " %f %f %f %f %f %f %f", 
		&tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5], &tmp[6]);

	// Decide what was provided by server according to number of player params
	agent->valid = agent->distValid = agent->changesValid = 
		agent->facingValid = agent->armValid = false;
	
	switch(rval)
	{
		case 1:
			agent->dir = tmp[0];
			break;

		case 2:
			agent->dist = tmp[0]; agent->dir = tmp[1];
			agent->distValid = true;
			break;

		case 3:
			agent->dist = tmp[0]; agent->dir = tmp[1];
			agent->armDir = tmp[2];
			agent->distValid = true; agent->armValid = true;
			break;

		case 4:
			agent->dist = tmp[0]; agent->dir = tmp[1];
			agent->distChange = tmp[2]; agent->dirChange = tmp[3];
			agent->distValid = true; agent->changesValid = true;
			break;

		case 6: // This uses coach in ParseSeeGlobal(...)
			agent->dist = tmp[0]; agent->dir = tmp[1];
			agent->distChange = tmp[2]; agent->dirChange = tmp[3];
			agent->bodyFacingDir = tmp[4]; agent->headFacingDir = tmp[5];
			agent->distValid = true; agent->changesValid = true;
			agent->facingValid = true;
			break;

		case 7:
			agent->dist = tmp[0]; agent->dir = tmp[1];
			agent->distChange = tmp[2]; agent->dirChange = tmp[3];
			agent->bodyFacingDir = tmp[4]; agent->headFacingDir = tmp[5];
			agent->armDir = tmp[6];
			agent->distValid = true; agent->changesValid = true;
			agent->facingValid = true; agent->armValid = true;
			break;
		
		default:
			return 1;
	}

	agent->valid = true;
	return 0;
}

/**
 * Parse seen landmark
 * \param str Whatever is after the landmark description
 * \param landmark Struct LANDMARK where we store parsed information
 * \return Error status: 0 for success; != 0 for error
 */
int Parser::ParseSeeLandmark(const char* str, LANDMARK* landmark)
{
	// Parse landmark position and state
	float tmp[4];
	int rval = sscanf(str, " %f %f %f %f", &tmp[0], &tmp[1], &tmp[2], &tmp[3]);

	// Decide what was provided by server according to number of player params
	landmark->valid = landmark->distValid = landmark->changesValid = false;
	
	switch(rval)
	{
		case 1:
			landmark->dir = tmp[0];
			break;

		case 2:
			landmark->dist = tmp[0]; landmark->dir = tmp[1];
			landmark->distValid = true;
			break;

		case 4: // This uses coach in ParseSeeGlobal(...)
			landmark->dist = tmp[0]; landmark->dir = tmp[1];
			landmark->distChange = tmp[2]; landmark->dirChange = tmp[3];
			landmark->distValid = true; landmark->changesValid = true;
			break;

		default:
			return 1;
	}

	landmark->valid = true;
	return 0;
}

/**
 * Parse flag type from see message
 * \param str String to parse
 * \return Flag type; NoLandmark on error
 */
FlagType Parser::ParseSeeFlagType(const char* str)
{
	LANDMARK_TRANSLATION *translation;
	
#ifdef COACH
	translation = LANDMARKS_LEFT;
#else // COACH
	if(realSide == LEFT) translation = LANDMARKS_LEFT;
	else translation = LANDMARKS_RIGHT;
#endif // COACH

	for(int i = NoLandmark + 1; i < FLAG_MAX; i++)
	{
		int length = strlen(str);

		if(strncmp(&str[1], translation[i].string, length) == 0)
		{
			return translation[i].landmark;
		}
	}

	WARNN("unknown landmark: %s", str);
	return NoLandmark;
}

void Parser::ParseVizParams6(const char* msg, int* entries, float* dist,
	float* dir, float* distChng, float* dirChng, float* bodyDir,
	float* headDir)
{
	int poc = sscanf(msg, " %f %f %f %f %f %f",
		dist, dir, distChng, dirChng, bodyDir, headDir);

	if(poc > 0) *entries = poc;
	else *entries = 0;
}

void Parser::ParseVizParams4(const char* msg, int* entries, float* dist,
	float* dir, float* distChng, float* dirChng)
{
	int poc = sscanf(msg, " %f %f %f %f", dist, dir, distChng, dirChng);
	if(poc > 0) *entries = poc;
	else *entries = 0;
}

void Parser::ParseVizParams2(const char* msg, int* entries, float* dist,
	float* dir)
{
	int poc = sscanf(msg, " %f %f", dist, dir);
	if(poc > 0) *entries = poc;
	else *entries = 0;
}

int Parser::ParseChangePT(const char* msg)
{
	unsigned num;
	int type;
	static int itWasWritten=0;

	switch(sscanf(msg, " %u %d", &num, &type))
	{
		case 1:					//druhy tim
			return 0;
		case 2:					//nas tim
			//oznamit dalej
			if(synchro != NULL) synchro->OnChangePlayerType(num, type);
			if(itWasWritten < 6) 
			{
				TXTN("CHANGE TYPE %d, %d", num, type);
				itWasWritten++;
			}
			return 0;
		default:				//chyba
			return 1;
	}
}

/**
 * Get play mode from play mode string
 *
 * \param str Play mode as string
 * \returns Play mode as a number (PM_Null for unknown play mode)
 */
PlayMode Parser::ParsePlayMode(const char* str)
{
	PLAY_MODE_TRANSLATION *translation;
	
#ifdef COACH
	translation = PLAY_MODES_LEFT;
#else // COACH
	if(realSide == LEFT) translation = PLAY_MODES_LEFT;
	else translation = PLAY_MODES_RIGHT;
#endif // COACH

	for(int i = PM_Null + 1; i < PM_MAX; i++)
	{
		int length = strlen(translation[i].string);

		// We may get things like "goal_l_3" here, so we have to use strncmp.
		if(strncmp(str, translation[i].string, length) == 0)
		{
			return translation[i].mode;
		}
	}

	WARNN("unknown play mode: %s", str);

	return PM_Null;
}


/**
 * If name equals "pattern", assign integer value to params.pattern and continue.
 * Helper macro used only in ParseServerParam.
 *
 * \param name String to compare with pattern
 * \param pattern Pattern for comparing
 * \param value String containing an integer value
 * \param params ServerParams to which we assign
 * \param counter Integer counter which will be incremented after assigning
 * \author Matus Horvath
 */
#define IF_EQUAL_ASSIGN_INT(name, pattern, value, params, counter) \
	if(strcmp(name, #pattern) == 0) \
	{ \
		int tmp; \
		if(sscanf(value, "%i", &tmp) != 1) \
		{ \
			WARNN("could not convert %s to int.", value); \
			return 1; \
		} \
		params.pattern = tmp; \
		counter++; \
		continue; \
	}

/**
 * If name equals "pattern", assign string value to params.pattern and continue.
 * Helper macro used only in ParseServerParam.
 *
 * \param name String to compare with pattern
 * \param pattern Pattern for comparing
 * \param value String containing an integer value
 * \param params ServerParams to which we assign
 * \param counter Integer counter which will be incremented after assigning
 * \author Matus Horvath
 */
#define IF_EQUAL_ASSIGN_STRING(name, pattern, value, params, counter) \
	if(strcmp(name, #pattern) == 0) \
	{ \
		strcpy(params.pattern, value); \
		counter++; \
		continue; \
	}

/**
 * If name equals "pattern", assign float value to params.pattern and continue.
 * Helper macro used only in ParseServerParam.
 *
 * \param name String to compare with pattern
 * \param pattern Pattern for comparing
 * \param value String containing an integer value
 * \param params ServerParams to which we assign
 * \param counter Integer counter which will be incremented after assigning
 * \author Matus Horvath
 */
#define IF_EQUAL_ASSIGN_FLOAT(name, pattern, value, params, counter) \
	if(strcmp(name, #pattern) == 0) \
	{ \
		float tmp; \
		if(sscanf(value, "%f", &tmp) != 1)\
		{ \
			WARNN("could not convert %s to float.", value); \
			return 1; \
		} \
		params.pattern = tmp; \
		counter++; \
		continue; \
	}

/**
 * Parse server parameters sent after (init).
 *
 * \param msg Message to parse
 * \returns 0 -> success, != 0 -> failure
 * \author Matus Horvath
 */
int Parser::ParseServerParam(const char* msg)
{
	static SERVER_PARAMS params;
	static char item[64], name[32], value[32];
	int counter = 0;

//	DBGN("Parsing server_param");

	while(true)
	{
		if(msg == NULL) return 1;

		msg = ParseBracket(msg, item);
		if(msg == NULL) break;		// no more parameters, but that's ok
//		DBGN("1: %s", item);

		const char* tmp = ParseObj(item, name);
		if(tmp == NULL) return 1;
//		DBGN("2: %s", name);
		
		tmp = ParseObj(tmp, value);
		if(tmp == NULL) return 1;
//		DBGN("3: %s", value);

		/*
		 * First line of the following means this:
		 *
	 		if(strcmp(name, "catch_ban_cycle") == 0)
			{
				int tmp;
				if(sscanf(value, "%i", &tmp) != 1)
				{
					WARNN("could not convert %s to int.", value);
					return 1;
				}
				params.catch_ban_cycle = tmp;
				counter++;
				continue;
			}
		 */

		IF_EQUAL_ASSIGN_INT(name, catch_ban_cycle, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, clang_advice_win, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, clang_define_win, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, clang_del_win, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, clang_info_win, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, clang_mess_delay, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, clang_mess_per_cycle, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, clang_meta_win, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, clang_rule_win, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, clang_win_size, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, coach_port, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, drop_ball_time, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, freeform_send_period, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, freeform_wait_period, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, game_log_compression, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, game_log_version, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, goalie_max_moves, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, half_time, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, hear_decay, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, hear_inc, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, hear_max, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, max_goal_kicks, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, olcoach_port, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, point_to_ban, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, point_to_duration, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, port, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, recv_step, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, say_coach_cnt_max, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, say_coach_msg_size, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, say_msg_size, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, send_step, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, send_vi_step, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, sense_body_step, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, simulator_step, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, slow_down_factor, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, start_goal_l, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, start_goal_r, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, synch_micro_sleep, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, synch_offset, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, tackle_cycles, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, text_log_compression, value, params, counter)
		IF_EQUAL_ASSIGN_STRING(name, game_log_dir, value, params, counter)
		IF_EQUAL_ASSIGN_STRING(name, game_log_fixed_name, value, params, counter)
		IF_EQUAL_ASSIGN_STRING(name, landmark_file, value, params, counter)
		IF_EQUAL_ASSIGN_STRING(name, log_date_format, value, params, counter)
		IF_EQUAL_ASSIGN_STRING(name, text_log_dir, value, params, counter)
		IF_EQUAL_ASSIGN_STRING(name, text_log_fixed_name, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, coach, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, coach_w_referee, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, old_coach_hear, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, wind_none, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, wind_random, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, back_passes, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, forbid_kick_off_offside, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, free_kick_faults, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, fullstate_l, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, fullstate_r, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, game_log_dated, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, game_log_fixed, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, game_logging, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, log_times, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, profile, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, proper_goal_kicks, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, record_messages, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, send_comms, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, synch_mode, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, team_actuator_noise, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, text_log_dated, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, text_log_fixed, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, text_logging, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, use_offside, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, verbose, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, audio_cut_dist, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, ball_accel_max, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, ball_decay, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, ball_rand, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, ball_size, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, ball_speed_max, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, ball_weight, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, catch_probability, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, catchable_area_l, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, catchable_area_w, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, ckick_margin, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, control_radius, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, dash_power_rate, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, effort_inc, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, effort_inc_thr, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, effort_dec, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, effort_dec_thr, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, effort_init, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, effort_min, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, goal_width, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, inertia_moment, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, kick_power_rate, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, kick_rand, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, kick_rand_factor_l, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, kick_rand_factor_r, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, kickable_margin, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, maxmoment, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, maxneckang, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, maxneckmoment, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, maxpower, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, minmoment, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, minneckang, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, minneckmoment, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, minpower, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, offside_active_area_size, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, offside_kick_margin, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, player_accel_max, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, player_decay, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, player_rand, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, player_size, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, player_speed_max, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, player_weight, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, prand_factor_l, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, prand_factor_r, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, quantize_step, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, quantize_step_l, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, recover_dec, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, recover_dec_thr, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, recover_min, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, slowness_on_top_for_left_team, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, slowness_on_top_for_right_team, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, stamina_inc_max, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, stamina_max, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, stopped_ball_vel, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, tackle_back_dist, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, tackle_dist, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, tackle_exponent, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, tackle_power_rate, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, tackle_width, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, visible_angle, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, visible_distance, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, wind_ang, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, wind_dir, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, wind_force, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, wind_rand, value, params, counter)

		WARNN("unknown server parameter: %s\n", name);
	}

	if(counter > SERVER_PARAMS_COUNT)
	{
		WARNN("SERVER_PARAMS_COUNT is too low, set it to %i\n", counter);
	}
	else if(counter < SERVER_PARAMS_COUNT)
	{
		WARNN("server did not provide all needed parameters (%i missing)\n",
			SERVER_PARAMS_COUNT - counter);
	}

	if(synchro != NULL) synchro->OnServerParam(&params);
	return 0;
}

/**
 * Parse player parameters sent after (server_param).
 *
 * \param msg Message to parse
 * \returns 0 -> success, != 0 -> failure
 * \author Matus Horvath
 */
int Parser::ParsePlayerParam(const char* msg)
{
	static PLAYER_PARAMS params;
	static char item[64], name[32], value[32];
	int counter = 0;

//	DBGN("Parsing player_param");

	while(true)
	{
		if(msg == NULL) return 1;

		msg = ParseBracket(msg, item);
		if(msg == NULL) break;		// no more parameters, but that's ok
//		DBGN("1: %s", item);

		const char* tmp = ParseObj(item, name);
		if(tmp == NULL) return 1;
//		DBGN("2: %s", name);
		
		tmp = ParseObj(tmp, value);
		if(tmp == NULL) return 1;
//		DBGN("3: %s", value);

		// See ParseServerParams for explanation of these
		IF_EQUAL_ASSIGN_INT(name, player_types, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, pt_max, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, random_seed, value, params, counter)
		IF_EQUAL_ASSIGN_INT(name, subs_max, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, dash_power_rate_delta_max, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, dash_power_rate_delta_min, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, effort_max_delta_factor, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, effort_min_delta_factor, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, extra_stamina_delta_max, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, extra_stamina_delta_min, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, inertia_moment_delta_factor, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, kick_rand_delta_factor, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, kickable_margin_delta_max, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, kickable_margin_delta_min, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, new_dash_power_rate_delta_max, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, new_dash_power_rate_delta_min, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, new_stamina_inc_max_delta_factor, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, player_decay_delta_max, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, player_decay_delta_min, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, player_size_delta_factor, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, player_speed_max_delta_max, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, player_speed_max_delta_min, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, stamina_inc_max_delta_factor, value, params, counter)

		WARNN("unknown player parameter: %s\n", name);
	}

	if(counter > PLAYER_PARAMS_COUNT)
	{
		WARNN("PLAYER_PARAMS_COUNT is too low, set it to %i\n", counter);
	}
	else if(counter < PLAYER_PARAMS_COUNT)
	{
		WARNN("server did not provide all needed player parameters (%i missing)\n",
			PLAYER_PARAMS_COUNT - counter);
	}

	if(synchro != NULL) synchro->OnPlayerParam(&params);
	return 0;
}


/**
 * Parse player type sent after (player_param).
 *
 * \param msg Message to parse
 * \returns 0 -> success, != 0 -> failure
 * \author Matus Horvath
 */
int Parser::ParsePlayerType(const char* msg)
{
	static PLAYER_TYPE params;
	static char item[64], name[32], value[32];
	int counter = 0;

//	DBGN("Parsing player_type");

	// Parse (id) (should be first)
	msg = ParseBracket(msg, item);
	if(msg == NULL) return 1;

	const char* tmp = ParseObj(item, name);
	if(tmp == NULL) return 1;
		
	tmp = ParseObj(tmp, value);
	if(tmp == NULL) return 1;

	int id;
	if(strcmp(name, "id") != 0) return 1;
	if(sscanf(value, "%i", &id) != 1) return 1;

//	DBGN("ID: %i", id);

	// Parse rest of message
	while(true)
	{
		if(msg == NULL) return 1;

		msg = ParseBracket(msg, item);
		if(msg == NULL) break;		// no more parameters, but that's ok
//		DBGN("1: %s", item);

		const char* tmp = ParseObj(item, name);
		if(tmp == NULL) return 1;
//		DBGN("2: %s", name);
		
		tmp = ParseObj(tmp, value);
		if(tmp == NULL) return 1;
//		DBGN("3: %s", value);

		// See ParseServerParams for explanation of these
		IF_EQUAL_ASSIGN_FLOAT(name, player_speed_max, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, stamina_inc_max, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, player_decay, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, inertia_moment, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, dash_power_rate, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, player_size, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, kickable_margin, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, kick_rand, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, extra_stamina, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, effort_max, value, params, counter)
		IF_EQUAL_ASSIGN_FLOAT(name, effort_min, value, params, counter)

		WARNN("unknown player type parameter: %s\n", name);
	}

	if(counter > PLAYER_TYPE_PARAMS_COUNT)
	{
		WARNN("PLAYER_TYPE_PARAMS_COUNT is too low, set it to %i\n", counter);
	}
	else if(counter < PLAYER_TYPE_PARAMS_COUNT)
	{
		WARNN("server did not provide all needed player type parameters (%i missing)\n",
			PLAYER_TYPE_PARAMS_COUNT - counter);
	}

	params.id = id;
	if(synchro != NULL) synchro->OnPlayerType(id, &params);
	return 0;
}


/////////////////////////// CLANG /////////////////////////////

#ifndef COACH

int Parser::CLangStripQuotes(const char* str, char* out)
{
	if(str == NULL || out == NULL) return -1;

	// Consume leading spaces
	while(*str == ' ') str++;
	if(*str == 0) return -2;

    // nothing to strip 
    if(*str != '\"') return -3;

	if(*str == '\"')
	{
		str++;
		while(*str != '\"')
		{
			*out = *str;
			if(*str == '\0') return -3;
			out++;
			str++;
		}
		str++;
	}

	*out = '\0';
	return 0;
}

/**
 * Parse message received from server. This method
 * calls all other Parse* methods.
 * \param msg Message to parse
 * \returns Error status: 0 for success; != 0 for error
 */
int Parser::CLangParseMsg(const char* msg)
{
	char message[BUFFERSIZE];
	
	if(!ParseBracket(msg, message))
	{
		WARNN("message not starting with a bracket");
		return 1;						// false
	}

	char typ[64];
	const char* nextStr = ParseObj(message, typ);

	if(nextStr == NULL) return 1;		// false

	int success = 0;

    if(strcmp(typ, "freeform") == 0) success = CLangParseFreeform(nextStr);
    else if (strcmp(typ, "define") == 0)
	{
		WARNN("%s", msg);
		success = CLangParseDefine(nextStr);
	}
	else if(strcmp(typ, "error") == 0) WARNN("server reports \"%s\"", msg);
	else if(strcmp(typ, "warning") == 0) WARNN("server reports \"%s\"", msg);
	else if(strcmp(typ, "can't") == 0) WARNN("server reports \"%s\"", msg);
	else WARNN("not parsed: %s", msg);

	return success;
}

int Parser::CLangParseFreeform(const char* msg)
{
    int success;
    static char message[BUFFERSIZE];

    success = CLangStripQuotes(msg, message);
    
    if(success != 0)
    {
       WARNN("freeform not parsed: %s ", msg);
       return success;
    }

    success = CLangParseMsg(message);

	return success;

}

int Parser::CLangParseDefine(const char* msg)
{
    int success = 1;
    char message[BUFFERSIZE];

    if(!ParseBracket(msg, message))
	{
		WARNN("message not starting with a bracket");
		return success;						// false
	}    
    
	char typ[64];
	const char* nextStr = ParseObj(message, typ);

	if(nextStr == NULL) return success;		// false    

    if(strcmp(typ, "definerule") == 0) success = CLangParseDefinerule(nextStr);

    // not a 'definerule' define message
    // definec, defined, definer, definea
	return success;

}

int Parser::CLangParseDefinerule(const char* msg)
{
    int success = 1;
	char action[64];
    char rule[64];

    const char* nextStr = ParseObj(msg, action);

   	if(nextStr == NULL) return success;		// false    

    nextStr = ParseObj(nextStr, rule);

    if(nextStr == NULL) return success;		// false    

    if (strcmp(rule, "direc") == 0)
    {

      if(strcmp(action, "SetParameter") == 0) 
		  success = CLangParseSetParameter(nextStr);
      else if (strcmp(action, "ChangeFormation") == 0) 
		  success = CLangParseChangeFormation(nextStr);

      // add here other defined actions

    } else if ((strcmp(rule, "model") == 0))
    {
        // not used; not implemented
    }

	return success;

}

int Parser::CLangParseSetParameter(const char* msg)
{
    int success = 1;
    static char message[BUFFERSIZE];
    static char condition[BUFFERSIZE];
    static char typeofaction[BUFFERSIZE];
    int delimiter = '=';

    if(!ParseBracket(msg, message))
	{
		WARNN("message not starting with a bracket");
		return success;						// false
	}    

    const char* nextStr  = ParseObj(message, condition);

    if(nextStr == NULL) return success;		// false    

    nextStr  = ParseObj(nextStr, typeofaction);   

    if(nextStr == NULL) return success;		// false    

    if (!CLangEvaluateCondition(condition)) return success; //false

    // get name=value pair
    static char name[100];
    char* value = strchr(typeofaction, delimiter);
    int pos = value - typeofaction;
    // skip delimiter
    value = value + 1;

    strncpy(name, typeofaction, pos);

	// MH: do the actual parsing in Variables::ParseVariable
	if(memory->GetWorld()->variables->ParseVariable(name, value)) success = 0;
	return success;
}

int Parser::CLangEvaluateCondition(const char* msg)
{
    static char message[BUFFERSIZE];
    static char condition[BUFFERSIZE];

    if(!ParseBracket(msg, message))
	{
		WARNN("message not starting with a bracket");
		return false;
	}    

    const char* nextStr = ParseObj(message, condition);

   	if(nextStr == NULL) return false;

    if(strcmp(condition, "true") == 0) return true;
    else if (strcmp(condition, "false") == 0) return false;
    // only true, false conditions are evaluated
    // other, complex conditions arent implemented
    else WARN("cannot evaluate condition");

    return false;
}

int Parser::CLangParseChangeFormation(const char* msg)
{
    int success = 0;
    char message[BUFFERSIZE];
    char condition[BUFFERSIZE];
    char typeofaction[BUFFERSIZE];

    if(!ParseBracket(msg, message))
	{
		WARNN("message not starting with a bracket");
		return success;						// false
	}    

    const char* nextStr  = ParseObj(message, condition);

    if(nextStr == NULL) return success;		// false    

    nextStr  = ParseObj(nextStr, typeofaction);   

    if(nextStr == NULL) return success;		// false    

    if(!CLangEvaluateCondition(condition)) return success; //false

    if(tactics) tactics->ChangeFormation(typeofaction);

	return 1;

}

#endif // COACH