/*
Quake III *.dm_6? Demo Specifications

Copyright (C) 2003 Andrey '[SkulleR]' Nazarov
Based on Argus and Quake II source code
Also contains some stuff from Q3A SDK

Argus is Copyright (C) 2000 Martin Otten
Quake II and Quake III are Copyright (C) 1997-2001 ID Software, Inc

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.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

//
// main.c - example main program
//

#include "main.h"

demoFileState_t	demo;
demoState_t		ds;
sqlite3			*db;
cgs_t			cgs;
cg_t			cg;

char *GetFileName(const char *path)
{
    char *filename = strrchr(path, '\\');
    if (filename == NULL)
        filename = path;
    else
        filename++;
    return filename;
}

static void Open_Database( void ) {

	int rc;

	rc = sqlite3_open("demos.db", &db);
	if (rc)	{
		sqlite3_close(db);
		Com_Error( ERR_DROP, "SQLite: %s\n", sqlite3_errmsg(db) );
	}
	else {
		Com_Printf( "%s\n", "Opened data.db");
	}
}

static void Create_DemoTable( void ) {

	int rc;
	char *error;
	const char *sqlCreateTable;

	// Execute SQL
	sqlCreateTable = "create table demo (id integer primary key, demo_path STRING unique, demo_pov INTEGER);";
	rc = sqlite3_exec(db, sqlCreateTable, NULL, NULL, &error);
	if (rc)	{
		Com_Printf( "%s\n", sqlite3_errmsg(db));
		sqlite3_free(error);
	}
	else {
		Com_Printf( "%s\n", "Created demo table");
	}
}

static void Update_DemoPov( void ) {

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

	ci = &cgs.clientinfo[ds.snap->ps.clientNum];

	// Execute SQL
	sql = va("update demo set demo_pov = '%i' where id = '%i';", ci->clientNum, demo.demoId);
	rc = sqlite3_exec(db, sql, NULL, NULL, &error);
	if (rc)	{
		Com_Printf( "%s\n", sqlite3_errmsg(db));
		sqlite3_free(error);
	}
	else {
		Com_Printf( "%s\n", "Updated demo");
	}
}

static void Create_FragTable( void ) {

	int rc;
	char *error;
	const char *sqlCreateTable;

	// Execute SQL
	sqlCreateTable = "create table frag (id integer primary key, demo_id INTEGER, round_time INTEGER, frame_time INTEGER, attacker INTEGER, target INTEGER, attacker_name STRING, target_name STRING, message STRING, weapon INTEGER, killtype INTEGER, teamkill INTEGER, FOREIGN KEY(demo_id) REFERENCES demo(id));";
	rc = sqlite3_exec(db, sqlCreateTable, NULL, NULL, &error);
	if (rc)	{
		Com_Printf( "%s\n", sqlite3_errmsg(db));
		sqlite3_free(error);
	}
	else {
		Com_Printf( "%s\n", "Created frag table");
	}
}

static void Create_PlayerTable( void ) {

	int rc;
	char *error;
	const char *sqlCreateTable;

	// Execute SQL
	sqlCreateTable = "create table player (id integer primary key, demo_id INTEGER, player_id INTEGER, player_name STRING, team INTEGER, FOREIGN KEY(demo_id) REFERENCES demo(id));";
	rc = sqlite3_exec(db, sqlCreateTable, NULL, NULL, &error);
	if (rc)	{
		Com_Printf( "%s\n", sqlite3_errmsg(db));
		sqlite3_free(error);
	}
	else {
		Com_Printf( "%s\n", "Created player table");
	}
}

static void Insert_DemoToDb( char *demoName ) {

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

	// Execute SQL
	sql = va("delete from demo where demo_path = \"%s\";", demoName);
	rc = sqlite3_exec(db, sql, NULL, NULL, &error);
	if (rc)	{
		Com_Printf( "%s\n", sqlite3_errmsg(db));
		sqlite3_free(error);
	}
	else {
		Com_Printf( "%s\n", "Deleting from demo");
	}

	// Execute SQL
	sql = va("INSERT INTO demo VALUES(NULL,\"%s\",'%i');", demoName, -1);
	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 demo table");
	}

	Com_sprintf( demo.demoName, sizeof( demo.demoName ), "%s", demoName );
	Com_Printf("demoName: %s\n", demo.demoName);
	
	demo.demoId = (int)sqlite3_last_insert_rowid(db);
	Com_Printf("demoId: %i\n", demo.demoId);

	// Execute SQL
	sql = va("delete from player where demo_id in (select id from demo where demo.demo_path = \"%s\");", demo.demoName);
	rc = sqlite3_exec(db, sql, NULL, NULL, &error);
	if (rc)	{
		Com_Printf( "%s\n", sqlite3_errmsg(db));
		sqlite3_free(error);
	}
	else {
		Com_Printf( "%s\n", "Deleting from player");
	}

	// Execute SQL
	sql = va("delete from frag where demo_id in (select id from demo where demo.demo_path = \"%s\");", demo.demoName);
	rc = sqlite3_exec(db, sql, NULL, NULL, &error);
	if (rc)	{
		Com_Printf( "%s\n", sqlite3_errmsg(db));
		sqlite3_free(error);
	}
	else {
		Com_Printf( "%s\n", "Deleting from frag");
	}
}

/*
============
Com_AppendToGameState
============
*/
static void Com_AppendToGameState( gameState_t *gameState, int index, const char *configString ) {
	int len;

	if( !configString || !(len=strlen( configString )) ) {
		return;
	}

	if( gameState->dataCount + len + 2 >= MAX_GAMESTATE_CHARS ) {
		Com_Error( ERR_DROP, "Com_AppendToGameState: MAX_GAMESTATE_CHARS" );
	}

	gameState->stringOffsets[index] = gameState->dataCount + 1;
	strcpy( &gameState->stringData[gameState->dataCount + 1], configString );
	gameState->dataCount += len + 1;
}

/*
============
Com_InsertIntoGameState
============
*/
void Com_InsertIntoGameState( gameState_t *gameState, int index, const char *configString ) {
	char *strings[MAX_CONFIGSTRINGS];
	int ofs;
	int i;

	if( index < 0 || index >= MAX_CONFIGSTRINGS ) {
		Com_Error( ERR_DROP, "Com_InsertIntoGameState: bad index %i", index );
	}

	if( !gameState->stringOffsets[index] ) {
		// just append to the end of gameState
		Com_AppendToGameState( gameState, index, configString );
		return;
	}

	//
	// resort gameState
	//
	for( i=0 ; i<MAX_CONFIGSTRINGS ; i++ ) {
		ofs = gameState->stringOffsets[i];
		if( !ofs ) {
			strings[i] = NULL;
		} else if( i == index ) {
			strings[i] = CopyString( configString );
		} else {
			strings[i] = CopyString( &gameState->stringData[ofs] );
		}
	}

	memset( gameState, 0, sizeof( *gameState ) );

	for( i=0 ; i<MAX_CONFIGSTRINGS ; i++ ) {
		if( strings[i] ) {
			Com_AppendToGameState( gameState, i, strings[i] );
			free( strings[i] );
		}
	}

}

/*
============
Com_GetStringFromGameState
============
*/
char *Com_GetStringFromGameState( gameState_t *gameState, int index ) {
	int ofs;

	if( index < 0 || index >= MAX_CONFIGSTRINGS ) {
		Com_Error( ERR_DROP, "Com_GetStringFromGameState: bad index  %i", index  );
	}

	ofs = gameState->stringOffsets[index];

	if( !ofs ) {
		return "";
	}

	return &gameState->stringData[ofs];
}

int main( int argc, char **argv ) {

	clientInfo_t *pov;

	if( argc < 2 ) {
		Com_Error( ERR_FATAL, "Usage: dm_60 [demofile]\n" );
	}
	if( !(demo.demofile=fopen( argv[1], "rb" )) ) {
		Com_Error( ERR_FATAL, "Couldn't open demofile" );
	}
	
	Open_Database();
	Create_DemoTable();
	Create_FragTable();
	Create_PlayerTable();

	Insert_DemoToDb(argv[1]);

	Com_Printf( "Building Huffman trees... " );
	Huff_Init();
	Com_Printf( "done\n\n" );

	while( !demo.gameStatesParsed ) {
		if( !Parse_NextDemoMessage() ) {
			break;
		}
	}

	GameStateParsed();

	Com_Printf("---end---\n");

	while( 1 ) {
		if( !Parse_NextDemoMessage() ) {
			break;
		}
		NewFrameParsed();
	}

	Update_DemoPov();

	fclose( demo.demofile );

	return EXIT_SUCCESS;
}

