#pragma semicolon 1

#include <sourcemod>

#define PL_VERSION    "0.6"
#define CVAR_DISABLED "OFF"
#define CVAR_ENABLED  "ON"

public Plugin:myinfo =
{
	name        = "Advertisements",
	author      = "Tsunami",
	description = "Display advertisements",
	version     = PL_VERSION,
	url         = "http://www.tsunami-productions.nl"
};

new g_iFrames                 = 0;
new g_iTickrate;
new bool:g_bTickrate          = true;
new Float:g_flTime;
new Handle:g_hAdvertisements  = INVALID_HANDLE;
new Handle:g_hCenterAd[MAXPLAYERS + 1];
new Handle:g_hEnabled;
new Handle:g_hFile;
new Handle:g_hInterval;
new Handle:g_hTimer;

static g_iSColors[4]             = {1,               3,              3,           4};
static g_iTColors[13][3]         = {{255, 255, 255}, {255, 0, 0},    {0, 255, 0}, {0, 0, 255}, {255, 255, 0}, {255, 0, 255}, {0, 255, 255}, {255, 128, 0}, {255, 0, 128}, {128, 255, 0}, {0, 255, 128}, {128, 0, 255}, {0, 128, 255}};
static String:g_sSColors[4][13]  = {"{DEFAULT}",     "{LIGHTGREEN}", "{TEAM}",    "{GREEN}"};
static String:g_sTColors[13][12] = {"{WHITE}",       "{RED}",        "{GREEN}",   "{BLUE}",    "{YELLOW}",    "{PURPLE}",    "{CYAN}",      "{ORANGE}",    "{PINK}",      "{OLIVE}",     "{LIME}",      "{VIOLET}",    "{LIGHTBLUE}"};

public APLRes:AskPluginLoad2(Handle:myself, bool:late, String:error[], err_max)
{
	MarkNativeAsOptional("GetUserMessageType");
	
	return APLRes_Success;
}

public OnPluginStart()
{
	CreateConVar("sm_advertisements_version", PL_VERSION, "Display advertisements", FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY);
	g_hEnabled        = CreateConVar("sm_advertisements_enabled",  "1",                  "Enable/disable displaying advertisements.");
	g_hFile           = CreateConVar("sm_advertisements_file",     "advertisements.txt", "File to read the advertisements from.");
	g_hInterval       = CreateConVar("sm_advertisements_interval", "30",                 "Amount of seconds between advertisements.");
	
	HookConVarChange(g_hInterval, ConVarChange_Interval);
	RegServerCmd("sm_advertisements_reload", Command_ReloadAds, "Reload the advertisements");
}

public OnMapStart()
{
	ParseAds();
	
	g_hTimer          = CreateTimer(GetConVarInt(g_hInterval) * 1.0, Timer_DisplayAds, _, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE);
}

public OnGameFrame()
{
	if(g_bTickrate)
	{
		g_iFrames++;
		
		new Float:flTime = GetEngineTime();
		if(flTime >= g_flTime)
		{
			if(g_iFrames == g_iTickrate)
			{
				g_bTickrate = false;
			}
			else
			{
				g_iTickrate = g_iFrames;
				g_iFrames   = 0;    
				g_flTime    = flTime + 1.0;
			}
		}
	}
}

public ConVarChange_Interval(Handle:convar, const String:oldValue[], const String:newValue[])
{
	if(g_hTimer)
		KillTimer(g_hTimer);
	
	g_hTimer          = CreateTimer(GetConVarInt(g_hInterval) * 1.0, Timer_DisplayAds, _, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE);
}

public Handler_DoNothing(Handle:menu, MenuAction:action, param1, param2) {}

public Action:Command_ReloadAds(args)
{
	ParseAds();
	return Plugin_Handled;
}

public Action:Timer_DisplayAds(Handle:timer)
{
	if(!GetConVarBool(g_hEnabled))
		return;
	
	decl AdminFlag:fFlagList[16], String:sBuffer[256], String:sFlags[16], String:sText[256], String:sType[6];
	KvGetString(g_hAdvertisements, "type",  sType,  sizeof(sType));
	KvGetString(g_hAdvertisements, "text",  sText,  sizeof(sText));
	KvGetString(g_hAdvertisements, "flags", sFlags, sizeof(sFlags), "none");
	
	if(!KvGotoNextKey(g_hAdvertisements))
	{
		KvRewind(g_hAdvertisements);
		KvGotoFirstSubKey(g_hAdvertisements);
	}
	
	new bool:bAdmins = StrEqual(sFlags, ""), bool:bFlags = !StrEqual(sFlags, "none");
	if(bFlags)
		FlagBitsToArray(ReadFlagString(sFlags), fFlagList, sizeof(fFlagList));
	
	if(StrContains(sText, "{CURRENTMAP}") != -1)
	{
		GetCurrentMap(sBuffer, sizeof(sBuffer));
		ReplaceString(sText, sizeof(sText), "{CURRENTMAP}", sBuffer);
	}
	
	if(StrContains(sText, "{DATE}")       != -1)
	{
		FormatTime(sBuffer, sizeof(sBuffer), "%m/%d/%Y");
		ReplaceString(sText, sizeof(sText), "{DATE}",       sBuffer);
	}
	
	if(StrContains(sText, "{TICKRATE}")   != -1)
	{
		IntToString(g_iTickrate, sBuffer, sizeof(sBuffer));
		ReplaceString(sText, sizeof(sText), "{TICKRATE}",   sBuffer);
	}
	
	if(StrContains(sText, "{TIME}")       != -1)
	{
		FormatTime(sBuffer, sizeof(sBuffer), "%I:%M:%S%p");
		ReplaceString(sText, sizeof(sText), "{TIME}",       sBuffer);
	}
	
	if(StrContains(sText, "{TIME24}")     != -1)
	{
		FormatTime(sBuffer, sizeof(sBuffer), "%H:%M:%S");
		ReplaceString(sText, sizeof(sText), "{TIME24}",     sBuffer);
	}
	
	if(StrContains(sText, "{TIMELEFT}")   != -1)
	{
		new iMins, iSecs, iTimeLeft;
		
		if(GetMapTimeLeft(iTimeLeft) && iTimeLeft > 0)
		{
			iMins = iTimeLeft / 60;
			iSecs = iTimeLeft % 60;
		}
		
		Format(sBuffer, sizeof(sBuffer), "%d:%02d", iMins, iSecs);
		ReplaceString(sText, sizeof(sText), "{TIMELEFT}",   sBuffer);
	}
	
	if(StrContains(sText, "\\n")          != -1)
	{
		Format(sBuffer, sizeof(sBuffer), "%c", 13);
		ReplaceString(sText, sizeof(sText), "\\n",          sBuffer);
	}
	
	decl Handle:hConVar, String:sConVar[64], String:sName[64];
	new iStart = StrContains(sText, "{BOOL:");
	while(iStart != -1)
	{
		new iEnd = StrContains(sText[iStart + 6], "}");
		if(iEnd != -1)
		{
			strcopy(sConVar, iEnd + 1, sText[iStart + 6]);
			Format(sName, sizeof(sName), "{BOOL:%s}", sConVar);
			
			if((hConVar = FindConVar(sConVar)))
				ReplaceString(sText, sizeof(sText), sName, GetConVarBool(hConVar) ? CVAR_ENABLED : CVAR_DISABLED);
		}
		
		new iStart2 = StrContains(sText[iStart + 1], "{BOOL:") + iStart + 1;
		if(iStart == iStart2)
			break;
		
		iStart = iStart2;
	}
	
	iStart = StrContains(sText, "{");
	while(iStart != -1)
	{
		new iEnd = StrContains(sText[iStart + 1], "}");
		if(iEnd != -1)
		{
			strcopy(sConVar, iEnd + 1, sText[iStart + 1]);
			Format(sName, sizeof(sName), "{%s}", sConVar);
			
			if((hConVar = FindConVar(sConVar)))
			{
				GetConVarString(hConVar, sBuffer, sizeof(sBuffer));
				ReplaceString(sText, sizeof(sText), sName, sBuffer);
			}
		}
		
		new iStart2 = StrContains(sText[iStart + 1], "{") + iStart + 1;
		if (iStart == iStart2) {
			break;
		} else {
			iStart = iStart2;
		}
	}
	
	if(StrContains(sType, "C") != -1)
	{
		for(new i = 1; i <= MaxClients; i++)
		{
			if(IsClientInGame(i) && !IsFakeClient(i) &&
			   ((!bAdmins && !(bFlags && HasFlag(i, fFlagList))) ||
			    bAdmins && (GetUserFlagBits(i) & (ADMFLAG_GENERIC|ADMFLAG_ROOT))))
			{
				PrintCenterText(i, sText);
				
				new Handle:hCenterAd;
				g_hCenterAd[i] = CreateDataTimer(1.0, Timer_CenterAd, hCenterAd, TIMER_FLAG_NO_MAPCHANGE|TIMER_REPEAT);
				WritePackCell(hCenterAd,   i);
				WritePackString(hCenterAd, sText);
			}
		}
	}
	if(StrContains(sType, "H") != -1)
	{
		for(new i = 1; i <= MaxClients; i++)
		{
			if(IsClientInGame(i) && !IsFakeClient(i) &&
			   ((!bAdmins && !(bFlags && HasFlag(i, fFlagList))) ||
			    bAdmins && (GetUserFlagBits(i) & (ADMFLAG_GENERIC|ADMFLAG_ROOT))))
				PrintHintText(i, sText);
		}
	}
	if(StrContains(sType, "M") != -1)
	{
		new Handle:hPl = CreatePanel();
		DrawPanelText(hPl, sText);
		SetPanelCurrentKey(hPl, 10);
		
		for(new i = 1; i <= MaxClients; i++)
		{
			if(IsClientInGame(i) && !IsFakeClient(i) &&
			   ((!bAdmins && !(bFlags && HasFlag(i, fFlagList))) ||
			    bAdmins && (GetUserFlagBits(i) & (ADMFLAG_GENERIC|ADMFLAG_ROOT))))
				SendPanelToClient(hPl, i, Handler_DoNothing, 10);
		}
		
		CloseHandle(hPl);
	}
	if(StrContains(sType, "S") != -1)
	{
		new iTeamColors = StrContains(sText, "{TEAM}"), String:sColor[4];
		Format(sText, sizeof(sText), "%c%c%c%s", 1, 11, 1, sText);
		
		for(new c = 0; c < sizeof(g_iSColors); c++)
		{
			if(StrContains(sText, g_sSColors[c]))
			{
				Format(sColor, sizeof(sColor), "%c", g_iSColors[c]);
				ReplaceString(sText, sizeof(sText), g_sSColors[c], sColor);
			}
		}
		
		if(iTeamColors == -1)
		{
			for(new i = 1; i <= MaxClients; i++)
			{
				if(IsClientInGame(i) && !IsFakeClient(i) &&
				   ((!bAdmins && !(bFlags && HasFlag(i, fFlagList))) ||
				    bAdmins && (GetUserFlagBits(i) & (ADMFLAG_GENERIC|ADMFLAG_ROOT))))
					PrintToChat(i, sText);
			}
		}
		else
		{
			for(new i = 1; i <= MaxClients; i++)
			{
				if(IsClientInGame(i) && !IsFakeClient(i) &&
				   ((!bAdmins && !(bFlags && HasFlag(i, fFlagList))) ||
				    bAdmins && (GetUserFlagBits(i) & (ADMFLAG_GENERIC|ADMFLAG_ROOT))))
					SayText2(i, sText);
			}
		}
	}
	if(StrContains(sType, "T") != -1)
	{
		decl String:sColor[16];
		new iColor = -1, iPos = BreakString(sText, sColor, sizeof(sColor));
		
		for(new i = 0; i < sizeof(g_sTColors); i++)
		{
			if(StrEqual(sColor, g_sTColors[i]))
				iColor = i;
		}
		
		if(iColor == -1)
		{
			iPos     = 0;
			iColor   = 0;
		}
		
		new Handle:hKv = CreateKeyValues("Stuff", "title", sText[iPos]);
		KvSetColor(hKv, "color", g_iTColors[iColor][0], g_iTColors[iColor][1], g_iTColors[iColor][2], 255);
		KvSetNum(hKv,   "level", 1);
		KvSetNum(hKv,   "time",  10);
		
		for(new i = 1; i <= MaxClients; i++)
		{
			if(IsClientInGame(i) && !IsFakeClient(i) &&
			   ((!bAdmins && !(bFlags && HasFlag(i, fFlagList))) ||
			    bAdmins && (GetUserFlagBits(i) & (ADMFLAG_GENERIC|ADMFLAG_ROOT))))
				CreateDialog(i, hKv, DialogType_Msg);
		}
		
		CloseHandle(hKv);
	}
}

public Action:Timer_CenterAd(Handle:timer, Handle:pack)
{
	decl String:sText[256];
	static iCount          = 0;
	
	ResetPack(pack);
	new iClient            = ReadPackCell(pack);
	ReadPackString(pack, sText, sizeof(sText));
	
	if(IsClientInGame(iClient) && ++iCount < 5)
	{
		PrintCenterText(iClient, sText);
		
		return Plugin_Continue;
	}
	else
	{
		iCount               = 0;
		g_hCenterAd[iClient] = INVALID_HANDLE;
		
		return Plugin_Stop;
	}
}

ParseAds()
{
	if(g_hAdvertisements)
		CloseHandle(g_hAdvertisements);
	
	g_hAdvertisements = CreateKeyValues("Advertisements");
	
	decl String:sFile[256], String:sPath[256];
	GetConVarString(g_hFile, sFile, sizeof(sFile));
	BuildPath(Path_SM, sPath, sizeof(sPath), "configs/%s", sFile);
	
	if(!FileExists(sPath))
		SetFailState("File Not Found: %s", sPath);
	
	FileToKeyValues(g_hAdvertisements, sPath);
	KvGotoFirstSubKey(g_hAdvertisements);
}

SayText2(to, const String:message[])
{
	new Handle:hBf = StartMessageOne("SayText2", to);
	if(!hBf)
		return;
	
#if SOURCEMOD_V_MAJOR >= 1 && SOURCEMOD_V_MINOR >= 5
	if(GetFeatureStatus(FeatureType_Native, "GetUserMessageType") == FeatureStatus_Available && GetUserMessageType() == UM_Protobuf)
	{
		PbSetBool(hBf,   "chat",     true);
		PbSetInt(hBf,    "ent_idx",  to);
		PbSetString(hBf, "msg_name", message);
		PbAddString(hBf, "params",   "");
		PbAddString(hBf, "params",   "");
		PbAddString(hBf, "params",   "");
		PbAddString(hBf, "params",   "");
	}
	else
	{
#endif
		BfWriteByte(hBf,   to);
		BfWriteByte(hBf,   true);
		BfWriteString(hBf, message);
#if SOURCEMOD_V_MAJOR >= 1 && SOURCEMOD_V_MINOR >= 5
	}
#endif
	EndMessage();
}

bool:HasFlag(iClient, AdminFlag:fFlagList[16])
{
	new iFlags = GetUserFlagBits(iClient);
	if(iFlags & ADMFLAG_ROOT)
		return true;
	
	for(new i = 0; i < sizeof(fFlagList); i++)
	{
		if(iFlags & FlagToBit(fFlagList[i]))
			return true;
	}
	
	return false;
}