#include "MW4Headers.hpp"

#include "data server.h"
#include "data_client.hpp"

#pragma warning (push)
#include <stlport\vector>
#pragma warning (pop)

#ifdef LAB_ONLY
namespace NDataClient
{
	int g_CurrentRunID=0;
	bool g_Inited=false;
	unsigned char pszStringBinding[255];					// rpc binding
	std::vector<CDataEntry*> *g_StatData;
	MemoryBlockOf<CDataEntry> *CDataEntry::m_EmptyData;
	void ConnectDataClient (const char *server);
};

using namespace NDataClient;

CDataEntry::CDataEntry (int runnumber,int version,int type,double time)
{
	m_RunNumber = runnumber;
	m_DataType = type;
	m_Version = version;
	m_Time = time;
	m_ObjectID = 0;
	m_PosX = 0;
	m_PosY = 0;
	m_PosZ = 0;
	m_Int1 = 0;
	m_Int2 = 0;
	m_Int3 = 0;
	m_Int4 = 0;
	m_Float1 = 0;
	m_Float2 = 0;
	m_Float3 = 0;
	m_Float4 = 0;
	m_String = NULL;
}

CDataEntry::CDataEntry (int run,int version,int type,double time,int objid,float posx,float posy,float posz,int int1,int int2,int int3,int int4,float float1,float float2,float float3,float float4,const char *str)
{
	m_RunNumber = run;
	m_DataType = type;
	m_Version = version;
	m_Time = time;
	m_ObjectID = objid;
	m_PosX = posx;
	m_PosY = posy;
	m_PosZ = posz;
	m_Int1 = int1;
	m_Int2 = int2;
	m_Int3 = int3;
	m_Int4 = int4;
	m_Float1 = float1;
	m_Float2 = float2;
	m_Float3 = float3;
	m_Float4 = float4;
	m_String = NULL;
	if (str)
	{
		int len = strlen (str)+1;
		m_String = new char[len];
		Str_Copy (m_String,str,len);
	}
}

CDataEntry::CDataEntry (const CDataEntry& p1)
{
	m_RunNumber 		= p1.m_RunNumber;
	m_DataType 			= p1.m_DataType;
	m_Version 			= p1.m_Version;
	m_Time					= p1.m_Time;
	m_ObjectID 			= p1.m_ObjectID;
	m_PosX 					= p1.m_PosX;
	m_PosY 					= p1.m_PosY;
	m_PosZ          = p1.m_PosZ;
	m_Int1          = p1.m_Int1;
	m_Int2          = p1.m_Int2;
	m_Int3          = p1.m_Int3;
	m_Int4				 	= p1.m_Int4;
	m_Float1 				= p1.m_Float1;
	m_Float2 				= p1.m_Float2;
	m_Float3 				= p1.m_Float3;
	m_Float4 				= p1.m_Float4;
	if (p1.m_String)
	{
		int len = strlen (p1.m_String)+1;
		m_String = new char[len];
		Str_Copy (m_String,p1.m_String,len);
	}
	else
		m_String = NULL;
}

CDataEntry::~CDataEntry (void)
{
	delete[] m_String;
}

CDataEntry &CDataEntry::operator= (const CDataEntry &p1)
{
	delete[] m_String;

	m_RunNumber 		= p1.m_RunNumber;
	m_DataType 			= p1.m_DataType;
	m_Version 			= p1.m_Version;
	m_Time					= p1.m_Time;
	m_ObjectID 			= p1.m_ObjectID;
	m_PosX 					= p1.m_PosX;
	m_PosY 					= p1.m_PosY;
	m_PosZ          = p1.m_PosZ;
	m_Int1          = p1.m_Int1;
	m_Int2          = p1.m_Int2;
	m_Int3          = p1.m_Int3;
	m_Int4				 	= p1.m_Int4;
	m_Float1 				= p1.m_Float1;
	m_Float2 				= p1.m_Float2;
	m_Float3 				= p1.m_Float3;
	m_Float4 				= p1.m_Float4;
	if (p1.m_String)
	{
		int len = strlen (p1.m_String)+1;
		m_String = new char[len];
		Str_Copy (m_String,p1.m_String,len);
	}
	else
		m_String = NULL;
	return *this;
}
void CDataEntry::Record (void)
{
	const char *p5;
	if (m_String ==NULL)
		p5 = "";
	else
		p5 = m_String;
	RecordData (g_CurrentRunID,DATA_VERSION,m_Time,m_DataType,m_ObjectID,m_PosX,m_PosY,m_PosZ,m_Int1,m_Int2,m_Int3,m_Int4,m_Float1,m_Float2,m_Float3,m_Float4,(const unsigned char *) p5);
}


void InitDataClient (const char *server)
{
#if LAB_ONLY
	if (g_Inited)
		return;
	CDataEntry::m_EmptyData = new MemoryBlockOf<CDataEntry> (1000,100,"Stat Data Blocks");
	Register_Object (CDataEntry::m_EmptyData);
	g_StatData = new std::vector<CDataEntry *>;
	ConnectDataClient (server);
#else
	g_Inited = false;
#endif
}

void NDataClient::ConnectDataClient (const char *server)
{
	if (g_Inited)
		return;
	RpcTryExcept
	{
		RPC_STATUS status;
		if (!server)
		{
			sprintf ((char *) pszStringBinding,"ncalrpc:[MW4DataServer]");
		}
		else
		{
			sprintf ((char *) pszStringBinding,"ncacn_ip_tcp:%s[1405]",server);
		}
		/* Set the binding handle that will be used to bind to the server. */
		status = RpcBindingFromStringBinding(pszStringBinding,&data_server_IfHandle);
		if (status)
		{
			SPEWALWAYS ((NULL,"Failed to connect to data server"));
			return ;
		}
		g_Inited = true;
		g_CurrentRunID = StartRunID ();
	}
	RpcExcept (1)
	{
		SPEWALWAYS ((NULL,"Failed to connect to data server"));
		g_Inited = false;
	}
	RpcEndExcept
}

void KillDataClient (void)
{
	if (!g_Inited)
	{
		Unregister_Object (CDataEntry::m_EmptyData);
		delete CDataEntry::m_EmptyData;
		CDataEntry::m_EmptyData = NULL;
		delete g_StatData;
		g_StatData = NULL;
		return;
	}

	RpcTryExcept
	{
		DumpCollectedData ();
		FinishRun (g_CurrentRunID);
		g_Inited = false;
		RPC_STATUS status;
		pszStringBinding[0] = 0;

		status = RpcBindingFree(&data_server_IfHandle);	 // remote calls done; unbind
	}
	RpcExcept (1)
	{
		PAUSE (("Critical Failure disconnecting from data server"));
		g_Inited = false;
	}
	RpcEndExcept
	Unregister_Object (CDataEntry::m_EmptyData);
	delete CDataEntry::m_EmptyData;
	CDataEntry::m_EmptyData = NULL;
	delete g_StatData;
	g_StatData = NULL;
}

void DumpCollectedData (void)
{
	std::vector<CDataEntry*>::iterator iter;
	
	RpcTryExcept
	{
	for (iter = g_StatData->begin ();iter != g_StatData->end ();iter++)
	{
		if (*iter)
		{
			(*iter)->Record ();
		}
	}
	}
	RpcExcept (1)
	{
		PAUSE (("Critical Failure dumping collected data to server"));
	}
	RpcEndExcept
	for (iter = g_StatData->begin ();iter != g_StatData->end ();iter++)
	{
		delete *iter;
		*iter = NULL;
	}

}

void AddData (int type,int objectid,Stuff::Point3D loc,int int1,int int2,int int3,int int4,float float1,float float2,float float3,float float4,const char *str)
{
	if (!g_Inited)
		return;
//	RpcTryExcept
	{
		const char *p5;
		if (str ==NULL)
			p5 = "";
		else
			p5 = str;
		CDataEntry *data;
		data = new CDataEntry (g_CurrentRunID,DATA_VERSION,type,gos_GetElapsedTime (),objectid,loc.x,loc.y,loc.z,int1,int2,int3,int4,float1,float2,float3,float4,(const char *) p5);
		g_StatData->push_back (data);
//		RecordData (g_CurrentRunID,DATA_VERSION,gos_GetElapsedTime (),type,objectid,loc.x,loc.y,loc.z,int1,int2,int3,int4,float1,float2,float3,float4,(const unsigned char *) p5);
	}
//	RpcExcept (1)
	{
//		PAUSE (("Failed to log data to server, disconnecting"));
//		KillDataClient ();
	}
//	RpcEndExcept
}

void AddData (int type,const char *str)
{
	AddData (type,-1,Stuff::Point3D (-1,-1,-1),0,0,0,0,0,0,0,0,str);
}

void AddData (int type, bool flag)
{
	AddData(type,-1,Stuff::Point3D(-1,-1,-1),(int)flag,0,0,0,0,0,0,0,"");
}

void AddMessageData (const char *str)
{
	Verify (str);
	AddData (MESSAGE,-1,Stuff::Point3D (-1,-1,-1),0,0,0,0,0,0,0,0,str);
}

void AddCreationData (const char *prefix,const char *str,int objectid)
{
	char *temp;
	if (!str)
		str = "Unknown name";
	Verify (prefix);
	temp = new char[strlen (str)+128];
	Str_Copy (temp,prefix,strlen (str)+128);
	Str_Cat (temp," ",strlen (str)+128);
	Str_Cat (temp,str,strlen (str)+128);
	Str_Cat (temp," created",strlen (str)+128);
	AddData (CREATION,objectid,Stuff::Point3D (-1,-1,-1),0,0,0,0,0,0,0,0,temp);
	delete temp;
}

void DataClient::Add_AddSkill(int skill, int objectid)
{
	char *temp;
	switch (skill)
	{
		case 0:	{	temp = "Pilot Skill Add";	break;	}
		case 1:	{	temp = "Gunnery Skill Add";	break;	}
		case 2:	{	temp = "Elite Skill Add";	break;	}
		default:{	temp = "Unknown Skill Add";	break;	}
	}
	AddData (SKILL_ADD,objectid,Stuff::Point3D (-1,-1,-1),0,0,0,0,0,0,0,0,temp);

}

void DataClient::Add_BuildVersion(const char* version)
{
	AddData(BUILD_VERSION,version);
}

void DataClient::Add_CompileDate(const char* date)
{
	AddData(COMPILE_DATE,date);
}

void DataClient::Add_CompileTime(const char* time)
{
	AddData(COMPILE_TIME,time);
}

void DataClient::Add_UserName(const char* name)
{
	AddData(USER_NAME,name);
}

void DataClient::Add_MachineName(const char* name)
{
	AddData(MACHINE_NAME,name);
}

void DataClient::Add_DateTime(const char* datetime)
{
	AddData(DATE_TIME,datetime);
}

void DataClient::Add_MissionName(const char* name)
{
	AddData(MISSION_NAME,name);
}

void DataClient::Add_PlayerMech(const char* name)
{
	AddData(PLAYER_MECH,name);
}

void DataClient::Add_NetworkingFlag(bool networking)
{
	AddData(NETWORKING,networking);
}

void DataClient::Add_Damage(int receiver_id, const char* receiver, int sender_id, const char* sender, float damage, const char* damage_type, float time)
{
	std::string s(sender);
	s += "\n";
	s += receiver;
	s += "\n";
	s += damage_type;
	AddData(DAMAGE,-1,Stuff::Point3D (-1,-1,-1),receiver_id,sender_id,0,0,damage,time,0,0,s.c_str());
}

void DataClient::Add_Destroyed(int destroyed_id, const char* destroyed, float time)
{
	AddData(DESTROYED,-1,Stuff::Point3D (-1,-1,-1),destroyed_id,0,0,0,time,0,0,0,destroyed);
}

void DataClient::Add_Objective(const char* objective_name, bool succeeded, float time)
{
	AddData(OBJECTIVE,-1,Stuff::Point3D (-1,-1,-1),(int)succeeded,0,0,0,time,0,0,0,objective_name);
}

void DataClient::Add_ToHitRoll(const char* shooter_name, int shooter_id, float base_to_hit, float modified_to_hit, float rolled, float time)
{
	AddData(TO_HIT_ROLL,-1,Stuff::Point3D (-1,-1,-1),shooter_id,0,0,0,base_to_hit,modified_to_hit,rolled,time,shooter_name);
}

void DataClient::Add_StartMission(float time)
{
	AddData(START_MISSION,-1,Stuff::Point3D(-1,-1,-1),0,0,0,0,time,0,0,0,0);
}

void DataClient::Add_EndMission(float time)
{
	AddData(END_MISSION,-1,Stuff::Point3D(-1,-1,-1),0,0,0,0,time,0,0,0,0);
}

#endif	// lab_only

