//
// dump.c - ugly stuff, don't look!
//

#include "main.h"

typedef struct {
	entityState_t	currentState;	// zeiger auf ringbuff pso
	qboolean		currentValid;	// true if cg.frame holds this entity
	int				previousEvent;
} centity_t;

static char			clientNames[MAX_CLIENTS][36];
static centity_t	centities[MAX_GENTITIES];

//static void UpdateClientInfoAndAddToDb( int clientNum, const char *info ) {
//
//	clientInfo_t *ci;
//	clientInfo_t newInfo;
//
//	int rc;
//	char *error;
//	const char *sql;
//
//	if( !info || !info[0] ) {
//		Q_strncpyz( clientNames[clientNum], "BADNAME", sizeof( clientNames[0] ) );
//	} else {
//		Q_strncpyz( clientNames[clientNum], Info_ValueForKey( info, "n" ), sizeof( clientNames[0] ) );
//
//		ci = &cgs.clientinfo[clientNum];
//		cgs.teamNum = atoi( Info_ValueForKey( info, "t" ) );
//		newInfo.clientNum = clientNum;
//		newInfo.team = cgs.teamNum;
//		Q_strncpyz( newInfo.name, Info_ValueForKey( info, "n" ), sizeof(newInfo.name) );
//
//		*ci = newInfo;
//
//		// Execute SQL
//		sql = va("INSERT INTO player VALUES(NULL,\"%i\",\"%s\");", demo.demoId, clientNames[clientNum]);
//		rc = sqlite3_exec(db, sql, NULL, NULL, &error);
//		if (rc)	{
//			Com_Printf( "%s\n", sqlite3_errmsg(db));
//			sqlite3_free(error);
//		}
//		else {
//			sqlite3_exec(db, "COMMIT", NULL, NULL, &error);
//			Com_Printf( "%s\n", "Inserted a value into player table");
//		}
//	}
//}

static void UpdateClientInfo( int clientNum, const char *info ) {

	if( !info || !info[0] ) {
		Q_strncpyz( clientNames[clientNum], "BADNAME", sizeof( clientNames[0] ) );
	} else {
		Q_strncpyz( clientNames[clientNum], Info_ValueForKey( info, "n" ), sizeof( clientNames[0] ) );
	}
}

/*
======================
CG_NewClientInfo
======================
*/
void CG_NewClientInfo( int clientNum, const char *configString) {
	clientInfo_t *ci;	
	clientInfo_t newInfo;
	const char  *v;
	char        *slash;
	int rc;
	char *error;
	const char *sql;

	ci = &cgs.clientinfo[clientNum];

	if ( !configString[0] ) {
		memset( ci, 0, sizeof( *ci ) );
		return;     // player just left
	}

	// build into a temp buffer so the defer checks can use
	// the old value
	memset( &newInfo, 0, sizeof( newInfo ) );

	newInfo.clientNum = clientNum;

	// isolate the player's name
	v = Info_ValueForKey( configString, "n" );
	Q_strncpyz( newInfo.name, v, sizeof( newInfo.name ) );

	// team
	v = Info_ValueForKey( configString, "t" );
	newInfo.team = atoi( v );

	// replace whatever was there with the new one
	newInfo.infoValid = qtrue;
	*ci = newInfo;
			
	if (newInfo.clientNum < MAX_CLIENTS) {

		// Execute SQL
		sql = va("INSERT INTO player VALUES(NULL,'%i','%i',\"%s\",'%i');", demo.demoId, newInfo.clientNum, newInfo.name, newInfo.team);
		rc = sqlite3_exec(db, sql, NULL, NULL, &error);
		if (rc)	{
			Com_Printf( "%s\n", sqlite3_errmsg(db));
			sqlite3_free(error);
		}
		else {
			sqlite3_exec(db, "COMMIT", NULL, NULL, &error);
			Com_Printf( "%s\n", "Inserted a value into player table");
		}
	}
}

static void Insert_FragInToDb(char *attackerName, char *targetName, char *message, int attacker, int target, int msec, int frame, int weaponNum, int killtype, int teamkill)
{

	int rc;
	char *error;
	const char *sql;

	// Execute SQL
	sql = va("INSERT INTO frag VALUES(NULL,'%i','%i','%i','%i','%i',\"%s\",\"%s\",\"%s\",'%i','%i','%i');", demo.demoId, msec, frame, attacker, target, attackerName, targetName, message, weaponNum, killtype, teamkill);
	rc = sqlite3_exec(db, sql, NULL, NULL, &error);
	if (rc) {
		Com_Printf( "%s\n", sqlite3_errmsg(db));
		sqlite3_free(error);
	}
	else {
		sqlite3_exec(db, "COMMIT", NULL, NULL, &error);
		//Com_Printf( "%s\n", "Inserted a value into frag");
	}	
}

static void CG_CheckEvents( centity_t *cent ) {
	entityState_t *es = &cent->currentState;
	int event;
	int	mod;
	int	target, attacker;
	char *targetName, *attackerName;
	char		*message;
	char		*message2 = "";
	char		*message3 = "";
	const char	*targetInfo;
	int		killtype = 0;		// 0 = Axis; 1 = Allied; 2 = your kill
	clientInfo_t	*ci, *ca, *pov; // ca = attacker
	int			mins, seconds, tens;
	int			msec;
	char		*time;
	int teamkill = 0;

	if(cgs.gametype == GT_SINGLE_PLAYER) {
		return;
	}
	
	// check for event-only entities
	if( es->eType > ET_EVENTS ) {
		if( cent->previousEvent ) {
			return;	// already fired
		}
		cent->previousEvent = 1;

		es->event = es->eType - ET_EVENTS;
	} else {
		// check for events riding with another entity
		if ( es->event == cent->previousEvent ) {
			return;
		}
		cent->previousEvent = es->event;
		if( ( es->event & ~EV_EVENT_BITS ) == 0 ) {
			return;
		}
	}

	event = es->event & ~EV_EVENT_BITS;
	if( event != EV_OBITUARY ) {
		return;
	}

	// -NERVE - SMF

	//seconds = msec / 1000;
	//mins = seconds / 60;
	//seconds -= mins * 60;
	//tens = seconds / 10;
	//seconds -= tens * 10;

	//if ( msec < 0 )
	//	time = va( "[0:00]" );
	//else
	//	time = va( "%i:%i%i", mins, tens, seconds );

	target = es->otherEntityNum;
	attacker = es->otherEntityNum2;
	mod = es->eventParm;

	ci = &cgs.clientinfo[target];
	ca = &cgs.clientinfo[attacker];

	if( target < 0 || target >= MAX_CLIENTS ) {
		return;
	}

	if( attacker < 0 || attacker >= MAX_CLIENTS ) {
		attacker = target;
	}

	//targetName = clientNames[target];
	//attackerName = clientNames[attacker];

	targetName = ci->name;
	attackerName = ca->name;

	if( attacker == ds.snap->ps.clientNum ) {
		killtype = 2;
	}
	else if ( ci->team == TEAM_BLUE ) {
		killtype = 1;
	}
	else {
		killtype = 0;
	}

	if ( cgs.gametype >= GT_WOLF ) {
		msec = ( cgs.timelimit * 60.f * 1000.f ) - ( cg.time - cgs.levelStartTime );
	}
	else {
		msec = cg.time - cgs.levelStartTime;
	}

	switch( mod ) {
		case MOD_SUICIDE:
			message = "^7committed suicide";
			break;
		case MOD_FALLING:
			message = "^7fell to his death";
			break;
		case MOD_CRUSH:
			message = "^7was crushed";
			break;
		case MOD_WATER:
			message = "^7drowned";
			break;
		case MOD_SLIME:
			message = "^7died by toxic materials";
			break;
		case MOD_TRIGGER_HURT:
			message = "^7was killed";
			break;
		default:
			message = NULL;
			break;
	}

	if (attacker == target)	{
		switch (mod) {
		case MOD_DYNAMITE:
		case MOD_DYNAMITE_SPLASH:
			message = "^7dynamited himself to pieces";
			break;
		case MOD_GRENADE_SPLASH:
			message = "^7dove on his own grenade";
			break;
		case MOD_ROCKET_SPLASH:
			message = "^7vaporized himself";
			break;
		case MOD_AIRSTRIKE:
			message = "^7obliterated himself";
			break;
		case MOD_EXPLOSIVE:
			message = "^7died in his own explosion";
			break;
		default:
			message = "^7killed himself";
			break;
		}

		Com_Printf( "%s %s.\n", targetName, message );
	}

	if (message) {
		message3 = va("%s %s.", targetName, message);		
		if ( cgs.gamestate == GS_PLAYING && ds.snap->ps.pm_type != PM_INTERMISSION && !cg.warmup && msec != cg.time) {
			Com_Printf( "%s\n", message3);
			Insert_FragInToDb(attackerName, targetName, message3, attacker, target, msec, cg.time, mod, killtype, teamkill);
		}
		return;
	}

	// check for double client messages
	//if ( !attackerName ) {
	//	attacker = ENTITYNUM_WORLD;
	//	strcpy( attackerName, "noname" );
	//}

	if ( attacker != ENTITYNUM_WORLD ) {
		switch (mod) {

		case MOD_KNIFE_STEALTH:
		case MOD_KNIFE:
		case MOD_KNIFE2:
			message = "^7was stabbed by";
			message2 = "^7's knife";
			break;
		case MOD_LUGER:
			message = "^7was killed by";
			message2 = "^7's Luger 9mm";
			break;
		case MOD_COLT:
			message = "^7was killed by";
			message2 = "^7's .45ACP 1911";
			break;
		case MOD_MP40:
			message = "^7was killed by";
			message2 = "^7's MP40";
			break;
		case MOD_THOMPSON:
			message = "^7was killed by";
			message2 = "^7's Thompson";
			break;
		case MOD_STEN:
			message = "^7was killed by";
			message2 = "^7's Sten";
			break;
		case MOD_MAUSER:
			message = "^7was killed by";
			message2 = "^7's Mauser";
			break;
		case MOD_SNIPERRIFLE:
			message = "^7was killed by";
			message2 = "^7's sniper rifle";
			break;
		case MOD_GARAND:
			break;
		case MOD_SNOOPERSCOPE:
			break;
		case MOD_AKIMBO:
			break;
		case MOD_DYNAMITE:
		case MOD_DYNAMITE_SPLASH:
			message = "^7was blasted by";
			message2 = "^7's dynamite";
			break;	
		case MOD_ROCKET_LAUNCHER:
		case MOD_ROCKET_SPLASH:
			message = "^7was blasted by";
			message2 = "^7's Panzerfaust";
			break;
		case MOD_GRENADE_LAUNCHER:
		case MOD_GRENADE_SPLASH:
		case MOD_GRENADE_PINEAPPLE:
			message = "^7was exploded by";
			message2 = "^7's grenade";
			break;
		case MOD_VENOM:
			message = "^7was ventilated by";
			message2 = "^7's Venom";
			break;
		case MOD_VENOM_FULL:
			break;
		case MOD_FLAMETHROWER:
			message = "^7was cooked by";
			message2 = "^7's flamethrower";
			break;
		case MOD_TESLA:
			break;
		case MOD_SPEARGUN:
			break;
		case MOD_SPEARGUN_CO2:
			break;
		case MOD_MACHINEGUN:
			message = "^7was perforated by";
			message2 = "^7's crew-served MG42";
			break;
		case MOD_CROSS:
			break;
		case MOD_AIRSTRIKE:
			message = "^7was blasted by";
			message2 = "^7's support fire";
			break;
		case MOD_ARTY:
			message = "^7was shelled by";
			message2 = "^7's artillery";
			break;
		default:
			message = "^7was killed by";
			break;
		}
	}

	if (ci->team == ca->team) {
		message = "^1WAS KILLED BY TEAMMATE^7";
		message2 = "";
		teamkill = 1;
	}

	if (message) {
		message3 = va("%s %s %s%s", targetName, message, attackerName, message2);
		if ( cgs.gamestate == GS_PLAYING && ds.snap->ps.pm_type != PM_INTERMISSION && !cg.warmup && msec != cg.time) {
			Com_Printf( "%s\n", message3);
			Insert_FragInToDb(attackerName, targetName, message3, attacker, target, msec, cg.time, mod, killtype, teamkill);
		}
		return;
	}

	// we don't know what it was
	message3 = va("%s ^7died.", targetName);	
	if ( cgs.gamestate == GS_PLAYING && ds.snap->ps.pm_type != PM_INTERMISSION && !cg.warmup && msec != cg.time) {
		Com_Printf( "%s\n", message3);
		Insert_FragInToDb(attackerName, targetName, message3, attacker, target, msec, cg.time, mod, killtype, teamkill);
	}
}

static void UpdateClientGameState( int index, char *string ) {

	if ( index == CS_SERVERINFO ) {
		cgs.gametype = atoi(Info_ValueForKey( string, "g_gametype" ));
		cgs.timelimit = atof( Info_ValueForKey( string, "timelimit" ) );
		cgs.currentRound = atoi( Info_ValueForKey( string, "g_currentRound" ) );
		cgs.nextTimeLimit = atof( Info_ValueForKey( string, "g_nextTimeLimit" ) );
		cgs.gamestate = atoi( Info_ValueForKey( string, "gamestate" ) );
	}

	if ( index == CS_LEVEL_START_TIME ) {
		cgs.levelStartTime = atoi( string );
	}

	if ( index == CS_WARMUP) {
		cg.warmup = atoi( string );
	}
}

void GameStateParsed( void ) {
	int i;
	char *configString;
	const char	*info;

	for( i=0 ; i<MAX_CONFIGSTRINGS ; i++ ) {
		configString = Com_GetStringFromGameState( &ds.gameState, i );
		if( configString[0] ) {
			if( i < RESERVED_CONFIGSTRINGS ) {
				Com_Printf( "%s Info:\n", (i == CS_SERVERINFO) ? "Server" : "System" );
				Info_Print( configString );
				Com_Printf( "\n" );
			}

			UpdateClientGameState(i, configString);

			//else {
				//Com_Printf( "configString %i: \"%s\"\n", i, configString );
			//}
		}
	}

	for( i=0 ; i<MAX_CLIENTS ; i++ ) {
		configString = Com_GetStringFromGameState( &ds.gameState, CS_PLAYERS + i );
		//UpdateClientInfoAndAddToDb( i, configString );
		CG_NewClientInfo( i, configString );
	}
}

static void UpdateConfigString( int index, char *string ) {
	Com_InsertIntoGameState( &ds.gameState, index, string );

	if( index > CS_PLAYERS && index < CS_PLAYERS + MAX_CLIENTS ) {
		//UpdateClientInfo( index, string );
		CG_NewClientInfo( index, string );
	}
}

void NewFrameParsed( void ) {
	int i;
	entityState_t *es;
	char *serverCommand;

	for( i=ds.currentServerCommandNum+1 ; i<=ds.lastServerCommandNum ; i++ ) {
		serverCommand = ds.serverCommands[i & SERVERCMD_MASK];
		Cmd_TokenizeString( serverCommand );

		if( !Q_stricmp( Cmd_Argv( 0 ), "print" ) || !Q_stricmp( Cmd_Argv( 0 ), "cp" ) ) {
			//Com_Printf( "%s", Cmd_Args() );
		} else if( !Q_stricmp( Cmd_Argv( 0 ), "cs" ) ) {
			UpdateConfigString( atoi( Cmd_Argv( 1 ) ), Cmd_Argv( 2 ) );
			UpdateClientGameState( atoi( Cmd_Argv( 1 ) ), Cmd_Argv( 2 ) );
		}	
	}
	ds.currentServerCommandNum = ds.lastServerCommandNum;

	if( !ds.snap || !ds.snap->valid ) {
		return;
	}

	for( i=0 ; i<MAX_GENTITIES ; i++ ) {
		centities[i].currentValid = qfalse;
	}

	for( i=0 ; i<ds.snap->numEntities ; i++ ) {
		es = &ds.parseEntities[(ds.snap->firstEntity+i) & PARSE_ENTITIES_MASK];
		memcpy( &centities[es->number].currentState, es, sizeof( entityState_t ) );
		centities[es->number].currentValid = qtrue;
		CG_CheckEvents( &centities[es->number] );
	}

	for( i=0 ; i<MAX_GENTITIES ; i++ ) {
		if( !centities[i].currentValid ) {
			centities[i].previousEvent = 0;
		}
	}
}
