#pragma semicolon 1
#pragma newdecls required

#include <sourcemod>
#include <sdktools>
#include <cstrike>

KeyValues g_Config;

char g_sStageName[32];

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public Plugin myinfo =
{
	name        = "Stage Display",
	author      = "Neon",
	description = "",
	version     = "1.0",
	url         = "https://steamcommunity.com/id/n3ontm"
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnPluginStart()
{
	HookEvent("round_start",  OnRoundStart, EventHookMode_PostNoCopy);
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public APLRes AskPluginLoad2(Handle hMyself, bool bLate, char[] sError, int errorSize)
{
	CreateNative("SD_GetStage", Native_GetStage);

	RegPluginLibrary("StageDisplay");
	return APLRes_Success;
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnMapStart()
{
	g_sStageName = "unknown";

	if(g_Config)
		delete g_Config;

	char sMapName[PLATFORM_MAX_PATH];
	GetCurrentMap(sMapName, sizeof(sMapName));

	char sConfigFile[PLATFORM_MAX_PATH];
	BuildPath(Path_SM, sConfigFile, sizeof(sConfigFile), "configs/stagedisplay/%s.cfg", sMapName);

	if(!FileExists(sConfigFile))
	{
		LogMessage("Could not find mapconfig: \"%s\"", sConfigFile);
		return;
	}

	LogMessage("Found mapconfig: \"%s\"", sConfigFile);

	g_Config = new KeyValues("stagedisplay");
	if(!g_Config.ImportFromFile(sConfigFile))
	{
		delete g_Config;
		SetFailState("ImportFromFile() failed!");
		return;
	}
	g_Config.Rewind();
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnRoundStart(Event hEvent, const char[] sEvent, bool bDontBroadcast)
{
	CreateTimer(3.0, CheckStageTimer, INVALID_HANDLE, TIMER_FLAG_NO_MAPCHANGE);
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public Action CheckStageTimer(Handle timer)
{
	CheckStage();
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void CheckStage()
{
	if(!g_Config)
		return;

	g_Config.Rewind();

	char sMethod[64];
	g_Config.GetString("method", sMethod, sizeof(sMethod));
	if(!sMethod[0])
	{
		LogError("Could not find \"method\"");
		return;
	}

	char sStageName[64];
	char sDiffName[64];


	if(StrEqual(sMethod, "counter"))
	{
		char sCounter[64];
		if(!g_Config.GetString("counter", sCounter, sizeof(sCounter)))
		{
			LogError("Could not find \"counter\"");
			return;
		}

		int iCounterEnt = INVALID_ENT_REFERENCE;
		iCounterEnt = FindEntityByTargetname(iCounterEnt, sCounter, "*");
		if(iCounterEnt == INVALID_ENT_REFERENCE)
		{
			LogError("Could not find entity: \"%s\"", sCounter);
			return;
		}

		static int iOffset = -1;
		if (iOffset == -1)
			iOffset = FindDataMapInfo(iCounterEnt, "m_OutValue");

		int iValue = RoundToNearest(GetEntDataFloat(iCounterEnt, iOffset));

		char sValue[8];
		IntToString(iValue, sValue, sizeof(sValue));

		g_Config.GetString(sValue, sStageName, sizeof(sStageName));
		if(!sStageName[0])
		{
			LogError("Could not find stage \"%s\"", sValue);
			return;
		}
	}
	else if(StrEqual(sMethod, "score"))
	{
		int iValue = CS_GetTeamScore(CS_TEAM_CT);

		char sValue[8];
		IntToString(iValue, sValue, sizeof(sValue));

		g_Config.GetString(sValue, sStageName, sizeof(sStageName));
		if(!sStageName[0])
		{
			LogError("Could not find stage \"%s\"", sValue);
			return;
		}
	}
	else
	{
		LogError("Unknown method \"%s\"", sMethod);
		return;
	}

	g_Config.Rewind();
	bool bHasDiffCounter = false;
	if(g_Config.JumpToKey("diffcounter", false))
	{
		bHasDiffCounter = true;

		char sDiffCounter[64];
		if(!g_Config.GetString("counter", sDiffCounter, sizeof(sDiffCounter)))
		{
			LogError("Could not find \"diffcounter\"");
			return;
		}

		int iDiffCounterEnt = INVALID_ENT_REFERENCE;
		iDiffCounterEnt = FindEntityByTargetname(iDiffCounterEnt, sDiffCounter, "*");
		if(iDiffCounterEnt == INVALID_ENT_REFERENCE)
		{
			LogError("Could not find entity: \"%s\"", sDiffCounter);
			return;
		}

		static int iOffset = -1;
		if (iOffset == -1)
			iOffset = FindDataMapInfo(iDiffCounterEnt, "m_OutValue");

		int iValue = RoundToNearest(GetEntDataFloat(iDiffCounterEnt, iOffset));

		char sValue[8];
		IntToString(iValue, sValue, sizeof(sValue));

		g_Config.GetString(sValue, sDiffName, sizeof(sDiffName));
		if(!sStageName[0])
		{
			LogError("Could not find difficulty \"%s\"", sValue);
			return;
		}
	}

	if(bHasDiffCounter)
		Format(g_sStageName, sizeof(g_sStageName), "%s - %s", sStageName, sDiffName);
	else
		Format(g_sStageName, sizeof(g_sStageName), "%s", sStageName);
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public int Native_GetStage(Handle hPlugin, int numParams)
{
	int length = GetNativeCell(2);

	char[] sStage = new char[length + 1];
	Format(sStage, length + 1, "%s", g_sStageName);

	if (strcmp(sStage, "unknown", true) == 0)
		return 0;

	return !(SetNativeString(1, sStage, length + 1));
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
int FindEntityByTargetname(int entity, const char[] sTargetname, const char[] sClassname="*")
{
	if(sTargetname[0] == '#') // HammerID
	{
		int HammerID = StringToInt(sTargetname[1]);

		while((entity = FindEntityByClassname(entity, sClassname)) != INVALID_ENT_REFERENCE)
		{
			if(GetEntProp(entity, Prop_Data, "m_iHammerID") == HammerID)
				return entity;
		}
	}
	else // Targetname
	{
		int Wildcard = FindCharInString(sTargetname, '*');
		char sTargetnameBuf[64];

		while((entity = FindEntityByClassname(entity, sClassname)) != INVALID_ENT_REFERENCE)
		{
			if(GetEntPropString(entity, Prop_Data, "m_iName", sTargetnameBuf, sizeof(sTargetnameBuf)) <= 0)
				continue;

			if(strncmp(sTargetnameBuf, sTargetname, Wildcard) == 0)
				return entity;
		}
	}

	return INVALID_ENT_REFERENCE;
}