#include "general.h"
#include "NoC4DefuseOnLeave.h"

#include "scripts.h"
#include "engine.h"
#include "engine_da.h"
#include "da.h"
#include "GameObjManager.h"

struct ProxyOwner_t
{
	C4GameObj *C4;
	cPlayer *cPlayer;
};

/* Vector with as key the ID of the proxy C4 object and the value is the cPlayer* of the original owner */
SimpleDynVecClass<ProxyOwner_t> ProxyOwners;

/* Array of bools to cache if a player has spawned yet or not */
bool SpawnedOnce[128];


void NoC4DefuseOnLeave::Init()
{
	Register_Event(DAEvent::LEVELLOADED);
	Register_Event(DAEvent::SETTINGSLOADED);
	Register_Event(DAEvent::PLAYERJOIN);
	Register_Event(DAEvent::PLAYERLEAVE);
	Register_Object_Event(DAObjectEvent::CREATED, DAObjectEvent::ALL);
}

NoC4DefuseOnLeave::~NoC4DefuseOnLeave(){
}

/* Attach the "C4NoDefuse_Script" because we need its ::Killed() event */
void NoC4DefuseOnLeave::Object_Created_Event(GameObject *obj)
{
	/* if C4 and C4 mode is that of a Proxy C4 */
	if (Is_C4(obj) && (Get_C4_Mode(obj) == 3))
	{
		Attach_Script_Once(obj, "C4NoDefuse_Script", "");

		/* Set player data to NULL */
		C4GameObj* C4 = (C4GameObj*)obj;
		C4->Set_Player_Data(0);

		/* Add C4GameObj pointer and cPlayer* pointer to our vector */
		cPlayer* cP = Find_Player(Get_Player_ID(Get_C4_Planter(obj)));

		struct ProxyOwner_t Data;
		Data.C4 = C4;
		Data.cPlayer = cP;

		ProxyOwners.Add(Data);
	}
	else if (Commands->Is_A_Star(obj))
	{
		int ID = Get_Player_ID(obj);

		if (SpawnedOnce[ID] == false)
		{
			SpawnedOnce[ID] = true;
			Restore_Proxy_C4_After_Join(ID);
		}

		for (auto c4_node = GameObjManager::C4GameObjList.Head(); c4_node; c4_node = c4_node->Next())
		{
			C4GameObj* C4 = (C4GameObj *)c4_node->Data();
			for (int i = 0; i < ProxyOwners.Count(); i++)
			{
				/* if our C4 is in the C4 list and the cPlayer is equal to the owner cPlayer */
				if ((ProxyOwners[i].C4 == C4) && (ProxyOwners[i].cPlayer == Find_Player(ID)))
				{
					/* Restore owner */
					C4->Set_Owner(obj);
					C4->Set_Player_Data(0);
				}
			}
		}
	}
}

/* Empty our C4 ownership vector */
void NoC4DefuseOnLeave::Level_Loaded_Event()
{
	ProxyOwners.Delete_All();
}

/* Loop over all C4GameObjs and add the ones to our vector that have the same owner
as the player that left. Then set their owner and player data to NULL */
void  NoC4DefuseOnLeave::Player_Leave_Event(cPlayer *Player)
{
	int PlayerID = Player->Get_Id();
	SpawnedOnce[PlayerID] = false;
	/* Go over all Proxy C4 in the world */
	for (auto c4_node = GameObjManager::C4GameObjList.Head(); c4_node; c4_node = c4_node->Next())
	{
		GameObject *PlayerObj = Player->Get_GameObj();
		C4GameObj* C4 = (C4GameObj *)c4_node->Data();

		const AmmoDefinitionClass* ammo = C4->Get_Ammo_Def();
		int C4Team = Commands->Get_Player_Type((GameObject*)C4);

		/* Check if AmmoType is that of a Proxy C4 and if the c4 team is the same as the player's */
		if (((int)ammo->AmmoType == 3) && (C4Team == Get_Team(PlayerID)))
		{
			/* Check if C4 is a valid pointer and the C4's owner is the same as the player */
			if (C4 && (Get_C4_Planter((GameObject*)C4) == PlayerObj))
			{
				/* Set owner to NULL */
				C4->Set_Owner(0);
				/* Set PlayerDataClass to NULL */
				C4->Set_Player_Data(0);
			}
		}
	}
}

/* Restore ownership of Proxy C4 in our ProxyC4OwnerMap to PlayerID,
then remove the entry for his Proxy C4's. */
void Restore_Proxy_C4_After_Join(int PlayerID)
{
	/* Don't do anything if our ProxyOwners vector is empty */
	if (ProxyOwners.Count() == 0) { return; }

	cPlayer *Player = Find_Player(PlayerID);

	/* Go over all Proxy C4 in the world */
	for (auto c4_node = GameObjManager::C4GameObjList.Head(); c4_node; c4_node = c4_node->Next())
	{		
		C4GameObj* C4 = (C4GameObj *)c4_node->Data();

		const AmmoDefinitionClass* ammo = C4->Get_Ammo_Def();
		int C4Team = Commands->Get_Player_Type((GameObject*)C4);

		/* Check if AmmoType is that of a Proxy C4 and if the c4 team is the same as the player's */
		if ( ((int)ammo->AmmoType == 3) && (C4Team == Get_Team(PlayerID)) )
		{
			/* Check if C4 is a valid pointer and that it doesn't have an owner */
			if (C4 && (Get_C4_Planter((GameObject*)C4) == NULL))
			{
				cPlayer* cP = NULL;

				for (int i = 0; i < ProxyOwners.Count(); i++)
				{
					if (ProxyOwners[i].C4 == C4 && ProxyOwners[i].cPlayer == Player)
					{
						/* Assign cPlayer*, so entry exists */
						cP = ProxyOwners[i].cPlayer;
						/* Remove entry in the ProxyOwners vector */
						ProxyOwners.Delete(i);
						break;
					}
				}

				/* if an entry exists, i.e. cp != NULL */
				if (cP)
				{
					/* Restore the owner of the Proxy C4 */
					GameObject *PlayerObj = Get_GameObj(PlayerID);
					C4->Set_Owner(PlayerObj);
					/* Set PlayerDataClass to NULL */
					C4->Set_Player_Data(0);
				}
			}
		}
	}
}

void  NoC4DefuseOnLeave::Player_Join_Event(cPlayer *Player)
{
	SpawnedOnce[Player->Get_Id()] = false;
}

/* Call the ::Destroyed() event */
void C4NoDefuse_Script::Killed(GameObject *obj, GameObject *shooter)
{
	this->Destroyed(obj);
}

/* Remove an entry from our ProxyC4Owners vector if it exists */
void C4NoDefuse_Script::Destroyed(GameObject *obj)
{
	C4GameObj* C4 = (C4GameObj*) obj;
	for (int i = 0; i < ProxyOwners.Count(); i++)
	{
		if (ProxyOwners[i].C4 == C4)
		{
			/* Remove entry in the ProxyOwners then break because we're done */
			ProxyOwners.Delete(i);
			break;
		}
	}
}

ScriptRegistrant<C4NoDefuse_Script> C4NoDefuse_Script_Registrant("C4NoDefuse_Script","");

Register_Game_Feature(NoC4DefuseOnLeave, "NoC4DefuseOnLeave", "EnableNoC4DefuseOnLeave", 0);