#include "stinc.h"
#include "stsetting.h"
#include "stgame.h"
#include "stplayer.h"
#include "sttranslate.h"
#include "stmisc.h"


/*****************/
/* Misc variable */
/*****************/
aRandom stRandom;
aString stVersion;

/******************/
/* Misc functions */
/******************/
char *A_Or_An(const char *String, bool captial)
{
	if (!String || !*String)
		return (captial ? "A" : "a");
	if (!stricmp(String,"hour"))
		return (captial ? "An" : "an");
	const char *aeiou = "aeiou";
	while (*aeiou)
	{
		if (tolower(*String) == *aeiou)
			return (captial ? "An" : "an");
		*aeiou++;
	}
	return (captial ? "A" : "a");
}

void PatchData(void *buf, unsigned long size, unsigned long addr){
	unsigned long PID = GetCurrentProcessId();
	HANDLE PHandle = OpenProcess(PROCESS_ALL_ACCESS, false, PID);
	WriteProcessMemory(PHandle, (void *)addr, buf, size, NULL);
	CloseHandle(PHandle);
}

void PatchByte(unsigned char Byte, unsigned long size, unsigned long addr) {
	for (unsigned long i = 0; i < size; i++)
		PatchData(&Byte,1,addr +i);
}

void gzLogger(const char *header, const char *msg, ...)
{
	aDateTime now = aDateTime::Now();
	aFile log(aString::Format("%s_%d-%d-%04d.txt", gzGameMgr->GetSettings()->m_LogRoot.GetString(),	now.GetMonth(),	now.GetDay(), now.GetYear()), "a");
	if (log.IsOpened())
	{
		va_list arg;
		va_start(arg, msg);
		int len = _vscprintf(msg, arg);
		char *fmsg = new char[len + 1];
		vsprintf(fmsg, msg, arg);
		va_end(arg);
		printf("%s\n", fmsg);
		log.Write(aString::Format("[%02d:%02d:%02d] %s %s\n",	now.GetHour(), now.GetMinute(),now.GetSecond(), header, fmsg));
		delete[] fmsg;
	}
}

aString GetPresetInfo(nc_PhysicalGameObj *obj, bool checkExplosion)
{
	aString ret;
	if (obj == NULL || !obj->As_ArmedGameObj())
		ret = "NULL";
	else
	{
		if ((obj->As_ArmedGameObj() && obj->As_ArmedGameObj()->WeaponBag->current == 0) || obj->definition->Get_Class_ID() == 0xD001)
			ret = gzTranslator->Get(obj->definition->Get_Name());
		else
		{
			ret = gzTranslator->Get(obj->definition->Get_Name());
			ret += '/';
			if (checkExplosion && gzManagerClass::Get_Explosion_Obj())
			{
				if (gzManagerClass::Get_Explosion_Obj()->definition->Get_Class_ID() == 0x3006)
				{
					const char *name[] = { "Remote", "Timed", "Proximity" };
					ret += name[((nc_C4GameObj *)gzManagerClass::Get_Explosion_Obj())->AmmoDef->AmmoType.Get() - 1];
					ret += " C4";
				}
				else
					ret += gzTranslator->Get(gzManagerClass::Get_Explosion_Obj()->definition->Get_Name());
			}
			else if (obj->As_SoldierGameObj() && obj->As_SoldierGameObj()->Vehicle)
				ret = gzTranslator->Get(obj->As_SoldierGameObj()->Vehicle->definition->Get_Name());
			else
			{
				int curWeap = obj->As_ArmedGameObj()->WeaponBag->current;
				ret += gzTranslator->Get(obj->As_ArmedGameObj()->WeaponBag->Vector[curWeap]->WeaponDef->Get_Name());
			}
		}
	}
	return ret;
}


aString SecsToAscTime(unsigned int secs)
{
	if (secs == 0)
		return "0sec";

	aString ret;
	if ((secs / 86400) >= 1)
	{
		ret += aString::Format("%d%s ", (secs / 86400), ((secs / 86400) > 1 ? "days" : "day"));
		secs = (secs % 86400);
	}
	if ((secs / 3600) >= 1)
	{
		ret += aString::Format("%d%s ", (secs / 3600), ((secs / 3600) > 1 ? "hrs" : "hr"));
		secs = (secs % 3600);
	}
	if ((secs / 60) >= 1)
	{
		ret += aString::Format("%d%s ", (secs / 60), ((secs / 60) > 1 ? "mins" : "min"));
		secs = (secs % 60);
	}
	if (secs >= 1)
		ret += aString::Format("%d%s ", secs, (secs > 1) ? "secs" : "sec");
	
	ret.Resize(ret.GetLength() - 1);
	return ret;
}

void Send_Purchase_Response(int pID, int value)
{
	nc_cPurchaseResponseEvent *Response = nc_cPurchaseResponseEvent::Create();
	Response->Init(value,pID);
	Response->Set_Delete_Pending();
}

void AddFrameTime(float &data, bool condition)
{
	if (condition)
		data += nc_TimeManager::FrameSeconds;
}
void SubFrameTime(float &data, bool condition)
{
	if (condition)
		data -= nc_TimeManager::FrameSeconds;
}

void SendBhsColorMsg(nc_Vector3 color, const char *msg, ...)
{
	va_list arg;
	va_start(arg, msg);
	aString fmtMsg;
	fmtMsg.Format_Args(msg, arg);
	va_end(arg);

	nc_cScTextObj *hostMsg = nc_cScTextObj::Create();
	hostMsg->SenderId = -1;
	hostMsg->Type = 0;
	hostMsg->IsPopup = false;
	hostMsg->Message.Get_String(0, false);
	hostMsg->Message.Convert_From(fmtMsg.GetString());

	char bhsMsgStr[1024];
	_snprintf(bhsMsgStr, 1023, "j\n44\n%.0f\n%.0f\n%.0f\n%s\n",
		color.X,
		color.Y,
		color.Z,
		fmtMsg.GetString()
	);
	nc_cScTextObj *bhsMsg = nc_cScTextObj::Create();
	bhsMsg->SenderId = -2;
	bhsMsg->ReceiverId = -1;
	bhsMsg->Type = 0;
	bhsMsg->IsPopup = false;
	bhsMsg->Message.Convert_From(bhsMsgStr);

	for (int i = 1; i <= 127; i++)
	{
		gzPlayer *gzData = gzPlayerManager::Find(i);

		if (gzData && gzData->GetPlayerData()->IsActive && gzData->IsActive())
		{
			// Players with BHS.dll version lower than 2.6 or without bhs.dll will see "msg" as a host message
			if (gzData->GetBHSVersion() < 2.6f)
			{
				hostMsg->Set_Object_Dirty_Bit(i, nc_DB_CREATION, true);
				nc_cNetwork::Send_Object_Update(hostMsg, i);
			}
			else
			{
				bhsMsg->Set_Object_Dirty_Bit(i, nc_DB_CREATION, true);
				nc_cNetwork::Send_Object_Update(bhsMsg, i);
			}
		}
	}
	fmtMsg.Free_String();
	hostMsg->Set_Delete_Pending();
	bhsMsg->Set_Delete_Pending();
}

#ifdef DEBUGLOG
void DebugLog(const char *message, ...)
{
	gzCritical.Enter();
	if (message == NULL || !*message)
		return;

	va_list args;
	va_start(args, message);
	aString tmp;
	tmp.Format_Args(message, args);
	va_end(args);
	aFile file("debug.log", "a");
	if (file.IsOpened())
	{
		file.Write("[", 1);
		file.Write(aDateTime::Now().Format("%d-%m-%Y %H:%M:%S"));
		file.Write("] ", 2);
		file.Write(tmp);
		file.Write("\n", 1);
	}
	printf("%s\n", tmp.GetString());
	gzCritical.Leave();
}
#endif
