#include "YaRRIncludes.h"


/************************************** Polite Request ***************************************
** I have put a lot of time and effort into YaRR. If you want to use some of the source     **
** please tell me. Anything used from YaRR must be open source, as is scripts.dll.          **
***************************************** Thank you *****************************************/


Player **Players = 0;
Stacker<char *> *YaRRPlayers::PreJoin;
CRITICAL_SECTION YaRRPlayers::Mutex;

float RankInfo::Player_Damage_CoEfficient = 1.0;
float RankInfo::Vehicle_Damage_CoEfficient = 1.0;
float RankInfo::Building_Damage_CoEfficient = 1.5;
float RankInfo::Beacon_Damage_CoEfficient = 1.0;
float RankInfo::C4_Damage_CoEfficient = 1.0;	
float RankInfo::Player_Repair_CoEfficient = 1.0;
float RankInfo::Vehicle_Repair_CoEfficient = 0.25;
float RankInfo::Building_Repair_CoEfficient = 0.05;

void Player::ROF_Callback()
{
	const char *Weapon = Get_Current_Weapon_Preset(Get_GameObj(this->ID));
	if(ROF_Damage == 0)
	{
		return;
	}
	float ROF = ROF_Damage;
	

	Stacker<YaRRDatabase::Row *> results;
	YaRRDatabase::Query(&results, "SELECT * FROM RateOfFire WHERE WeaponPreset = '%q';", Weapon);
	if(results.Empty())
	{
		IRC::SendC('a', "Warning: Weapon preset \"%s\" not found. Please use !addrofpreset to set a rate of fire for this weapon.", Weapon);
	}
	else
	{
		float Threshold = (float)atof(YaRRDatabase::GetColumnData("ROF", results[0]->Columns));
		if(ROF > Threshold)
		{
			IRC::SendC('b', "Warning: %s seems to be using rate of fire cheats. (%.2f - %s)", this->Nick, ROF, Weapon);
		}
	}
	YaRRDatabase::DeleteResult(&results);
	ROF_Damage = 0;
}

void YaRRPlayers::Startup()
{
	DLOG;
	InitializeCriticalSection(&YaRRPlayers::Mutex);
	Players = (Player **)CAlloc(sizeof(Player *)*128);

	for(int i = 0; i < 128; i++)
	{
		Players[i] = 0;
	}
	PreJoin = Alloc(Stacker<char *>);
}

void YaRRPlayers::Shutdown()
{
	DLOG;
	if(Players)
	{
		for(int i = 0; i < 128; i++)
		{
			if(Players[i] != 0)
			{
				CDealloc(Players[i]);
			}
		}

		CDealloc(Players);
		Players = 0;
	}
	Dealloc(Stacker<char *>, PreJoin);
}


Player *YaRRPlayers::Find(int ID)
{
	DLOG;
	if(!Players)
	{
		return 0;
	}
	if(!Players[ID])
	{
		return 0;
	}
	return Players[ID];
}

void YaRRPlayers::GivePoints(int ID, int Points)
{
	DLOG;
	Player *p = Find(ID);
	if(!p)
	{
		return;
	}
	p->Points += Points;
}

void ROF_Callback(void *Data, int Number);

void YaRRPlayers::Joined(int ID)
{
	DLOG;
	const char *nick = Get_Player_Name_By_ID(ID);
	int count = 0;
	IterateStack(x, char *, PreJoin)
	{
		if(strcmp(x, nick) == 0)
		{
			CDealloc(x);
			PreJoin->Erase(count);
		}
		count++;
	}

	for(GenericSLNode *x = PlayerList->HeadNode; x != 0; x = x->NodeNext)
	{
		cPlayer *tmp = (cPlayer *)x->NodeData;
		if(tmp)
		{
			if(tmp->PlayerId == ID)
			{
				Player *p = Alloc(Player);
				YaRRThink::Add_Timer(1.0, ROF_Callback, p, 1);
				p->ID = ID;
				p->Points = 0;
				p->Muted = 0;
				p->Access = 'p';
				p->data = tmp;
				p->HeadShots = p->data->HeadShots;
				p->Spectating = 0;
				p->Shunned = 0;
				memset((void *)&p->Rank, 0, sizeof(RankInfo));
				strcpy(p->Nick, nick);
				Players[ID] = p;

				Stacker<YaRRDatabase::Row *> result;
				YaRRDatabase::Query(&result, "SELECT PPageC, PPageS FROM Players WHERE Nick = '%q';", nick);
				if(result.Empty())
				{
					p->PPageColour = YaRRSettings::MessageColour;
					strcpy(p->PPageSound, "none");
				}
				else
				{
					const char *hex = YaRRDatabase::GetColumnData("PPageC", result[0]->Columns);
					if(!YaRRFunctions::HexToRGB(&p->PPageColour, hex))
					{
						p->PPageColour = YaRRSettings::MessageColour;
					}
					strcpy(p->PPageSound, YaRRDatabase::GetColumnData("PPageS", result[0]->Columns));
				}
				YaRRDatabase::DeleteResult(&result);
			}
		}
	}
	delete []nick;
}

void YaRRPlayers::Leave(int ID)
{
	DLOG;
	Player *p = Find(ID);
	if(!p)
	{
		return;
	}
	if(p->Rooted && YaRRSettings::Ban_Rooted)
	{
		const char *Reason = "Left the game while rooted";
		const char *By = "YaRR";
		if(*p->Node != 0)
		{
			char Date[256];
			YaRRFunctions::FormatTime(time(0), "%x", Date, 256);
			YaRRDatabase::Query(0, "INSERT INTO NodeBans(Nick, Node, Reason, Banner, Date) VALUES('%q', '%q', '%q', '%q', '%q');", p->Nick, p->Node, Reason, By, Date);
			YaRRDatabase::Query(0, "INSERT INTO Log(Type, Action, time) VALUES('NODEBAN', '%s was banned by %s for: %s', '%s');", p->Nick, By, Reason);
			Stacker<YaRRDatabase::Row *> Result;
			YaRRDatabase::Query(&Result, "SELECT COUNT(*) FROM NodeBans;");
			IRC::SendC('a', "Ban ID: %.3d added for %s. Node: %s. Reason: \"%s\"", atoi(YaRRDatabase::GetColumnData("COUNT(*)", Result[0]->Columns)), p->Nick, p->Node, Reason);
			CDealloc(Reason);
			YaRRDatabase::DeleteResult(&Result);
		}
		YaRRDatabase::Query(0, "INSERT INTO Bans(Nick, IP, WhoBy, Reason, Time) VALUES('%q', '%q', '%q', '%q', %d);", p->Nick, Get_IP_Address(p->ID), By, Reason, time(0));
		YaRRDatabase::Query(0, "INSERT INTO Log(Type, Action, time) VALUES('BAN', '%s was banned by %s for: %s', '%d');", p->Nick, By, Reason, time(0));
		YaRRFunctions::ConsoleInputF("msg %s was banned by %s for: %s", p->Nick, By, Reason);
	}

	EnterCriticalSection(&YaRRPlayers::Mutex);
	YaRRVeteran::PlayerLeave(Players[ID]);
	CDealloc(Players[ID]);
	Players[ID] = 0;
	LeaveCriticalSection(&YaRRPlayers::Mutex);
}

bool YaRRPlayers::WasHeadShot(int ID)
{
	DLOG;
	Player *p = Find(ID);
	if(p->HeadShots < p->data->HeadShots)
	{
		return 1;
	}
	p->HeadShots = p->data->HeadShots;
	return 0;
}

Player *YaRRPlayers::Find_By_Name(const char *Name)
{
	DLOG;
	for(int i = 0; i < 128; i++)
	{
		if(Players[i] == 0)
		{
			continue;
		}
		if(strcmp(Players[i]->Nick, Name) == 0)
		{
			return Players[i];
		}
	}
	return 0;
}

void YaRRPlayers::MapLoad()
{
	DLOG;
	YaRRFunctions::DeleteList((void *)PreJoin);
	for(GenericSLNode *x = PlayerList->HeadNode; x != 0; x = x->NodeNext)
	{
		cPlayer *tmp = (cPlayer *)x->NodeData;
		if(tmp)
		{
			const char *nick = WideCharToChar((const wchar_t *)tmp->PlayerName);
			Player *p = Find_By_Name(nick);
			if(!p)
			{
				p = Alloc(Player);
				p->ID = tmp->PlayerId;
				p->Points = 0;
				p->Muted = 0;
				p->Access = 'p';
				p->data = tmp;
				p->HeadShots = p->data->HeadShots;
				p->BlockBeacons = 0;
				p->BlockCharacters = 0;
				p->BlockVehicles = 0;
				p->Spectating = 0;
				p->Shunned = 0;
				p->PPageColour = YaRRSettings::MessageColour;
				memset((void *)&p->Rank, 0, sizeof(RankInfo));
				strcpy(p->Nick, nick);
				strcpy(p->PPageSound, YaRRSettings::PPageSound);
				Players[p->ID] = p;
			}
			else
			{
				Players[p->ID] = 0;

				Player *p_ = Alloc(Player);
				p_->ID = tmp->PlayerId;
				p_->Points = 0;
				p_->Muted = p->Muted;
				p_->Access = p->Access;
				p_->data = tmp;
				p_->HeadShots = p_->data->HeadShots;
				p_->BlockBeacons = p->BlockBeacons;
				p_->BlockCharacters = p->BlockCharacters;
				p_->BlockVehicles = p->BlockVehicles;
				p_->Shunned = p->Shunned;
				p_->BHS = p->BHS;
				p_->Spectating = 0;
				p_->PPageColour = p->PPageColour;
				strcpy(p_->Nick, nick);
				strcpy(p_->PPageSound, p->PPageSound);
				Players[p_->ID] = p_;
				memset((void *)&p_->Rank, 0, sizeof(RankInfo));
				CDealloc(p);
			}
			delete []nick;
		}
	}
}	

void YaRRPlayers::LoadingMap(const char *Nick, bool Reserved)
{
	DLOG;
	bool found = 0;
	IterateStack(x, char *, PreJoin)
	{
		if(strcmp(x, Nick) == 0)
		{
			found = 1;
		}
	}
	if(found && !Reserved)
	{
		char *DTJLM = YaRRFunctions::Replace(YaRRFunctions::strdup2(YaRRStrings::Fetch(IRC_DTJLM)), ":nick:", Nick);
		IRC::SendC('b', "%s", DTJLM);
		CDealloc(DTJLM);
	}
	else if(found && Reserved)
	{
		char *DTJLMURS = YaRRFunctions::Replace(YaRRFunctions::strdup2(YaRRStrings::Fetch(IRC_DTJLMURS)), ":nick:", Nick);
		IRC::SendC('b', "%s", DTJLMURS);
		CDealloc(DTJLMURS);
	}
	else if(!found && Reserved)
	{
		char *JLMURS = YaRRFunctions::Replace(YaRRFunctions::strdup2(YaRRStrings::Fetch(IRC_JLMURS)), ":nick:", Nick);
		IRC::SendC('b', "%s", JLMURS);
		CDealloc(JLMURS);
	}
	else if(!found && !Reserved)
	{
		char *JLM = YaRRFunctions::Replace(YaRRFunctions::strdup2(YaRRStrings::Fetch(IRC_JLM)), ":nick:", Nick);
		IRC::SendC('b', "%s", JLM);
		CDealloc(JLM);
	}
}

void YaRRPlayers::ThinkingJoin(const char *Nick)
{
	DLOG;
	bool found = 0;
	IterateStack(x, char *, PreJoin)
	{
		if(strcmp(x, Nick) == 0)
		{
			found = 1;
		}
	}
	if(!found)
	{
		PreJoin->Push(YaRRFunctions::strdup2(Nick));
		char *TAJG = YaRRFunctions::Replace(YaRRFunctions::strdup2(YaRRStrings::Fetch(IRC_TAJG)), ":nick:", Nick);
		IRC::SendC('b', "%s", TAJG);
		CDealloc(TAJG);
	}
}

void YaRRPlayers::Lock()
{
	DLOG;
	EnterCriticalSection(&YaRRPlayers::Mutex);
}

void YaRRPlayers::Unlock()
{
	DLOG;
	LeaveCriticalSection(&YaRRPlayers::Mutex);
}