/*
	OnFloodDetected(playerid, ip[]);

	Just a simple include which detects flooding and
	has it's own callback.

	Created by Emmet on Monday, November 18, 2013.
*/
#tryinclude <foreach>

#if !defined MAX_IP_CONNECTIONS
	#define MAX_IP_CONNECTIONS (3)
#endif

#if !defined TIME_INTERVAL
	#define TIME_INTERVAL (3000)
#endif

// How many lines of chat in the TIME_INTERVAL before the player is flagged for flooding?
#if !defined FLOOD_CHAT_LIMIT
	#define FLOOD_CHAT_LIMIT (8)
#endif

// How many executed commands in the TIME_INTERVAL before the player is flagged for flooding?
#if !defined FLOOD_CMD_LIMIT
	#define FLOOD_CMD_LIMIT (8)
#endif

#define FLOOD_TYPE_CONNECT (1)
#define FLOOD_TYPE_CHAT    (2)
#define FLOOD_TYPE_COMMAND (3)

static stock
	g_FD_LastConnection,
	g_FD_ChatFlooding[MAX_PLAYERS][2],
	g_FD_CommandFlooding[MAX_PLAYERS][2]
;

static const g_NameArray[23][] =
{
    "CON", "PRN", "AUX", "CLOCK$",
    "NUL", "COM1", "COM2", "COM3",
    "COM4", "COM5", "COM6", "COM7",
    "COM8", "COM9", "LPT1", "LPT2",
    "LPT3", "LPT4", "LPT5", "LPT6",
    "LPT7", "LPT8", "LPT9"
};

forward OnFloodDetected(playerid, ip[], type);

stock isPlayerNameInvalid(playerid)
{
	new
	    length,
		playername[24]
	;
	length = strlen((GetPlayerName(playerid, playername, 24), playername));

	if (length == 3 || length == 4 || length == 6)
	{
	    for (new i = 0; i < sizeof(g_NameArray); i ++) if (!strcmp(g_NameArray[i], playername, true))
		{
			return 1;
		}
	}
	return 0;
}

public OnPlayerConnect(playerid)
{
	if (isPlayerNameInvalid(playerid)) return (Kick(playerid), 0);
	if (!g_FD_LastConnection || (gettime() - g_FD_LastConnection) < TIME_INTERVAL / 1000)
	{
	    // Get the player's IP and store it into a local array.
	    new
			szIP[16],
			szCompare[16],
			iConnections
		;
	    GetPlayerIp(playerid, szIP, sizeof (szIP));
		#if !defined foreach
	        for (new i = 0, j = GetMaxPlayers(); i != j; i ++) if (IsPlayerConnected(i))
		#else
		    foreach (new i : Player)
		#endif
  		{
  		    if (!IsPlayerNPC(i) && i != playerid)
			{
				GetPlayerIp(i, szCompare, sizeof (szCompare));
				if (!strcmp(szCompare, szIP))
				{
				    ++iConnections;
				    if (iConnections >= MAX_IP_CONNECTIONS && funcidx("OnFloodDetected") != -1)
				    {
				        // Call the function if it exists.
						CallLocalFunction("OnFloodDetected", "dsd", playerid, szIP, FLOOD_TYPE_CONNECT);
						break;
					}
				}
  		    }
    	}
	}
   	g_FD_LastConnection = gettime();
   	
   	g_FD_ChatFlooding[playerid][0] = 0;
   	g_FD_ChatFlooding[playerid][1] = 0;
   	
   	g_FD_CommandFlooding[playerid][0] = 0;
   	g_FD_CommandFlooding[playerid][1] = 0;
   	
	return CallLocalFunction("FD_OnPlayerConnect", "d", playerid);
}

public OnPlayerText(playerid, text[])
{
	if (g_FD_ChatFlooding[playerid][1] >= FLOOD_CHAT_LIMIT && (gettime() - g_FD_ChatFlooding[playerid][0]) < TIME_INTERVAL / 1000)
	{
	    if (funcidx("OnFloodDetected") != -1)
		{
			// Call the function if it exists.
			CallLocalFunction("OnFloodDetected", "dsd", playerid, ReturnIP(playerid), FLOOD_TYPE_CHAT);
			
			// Reset the variable.
			g_FD_ChatFlooding[playerid][1] = 0;
		}
	}
	g_FD_ChatFlooding[playerid][0] = gettime();
	g_FD_ChatFlooding[playerid][1] ++;

	CallLocalFunction("FD_OnPlayerText", "ds", playerid, text);
	return 1;
}

public OnPlayerCommandText(playerid, cmdtext[])
{
	if (g_FD_CommandFlooding[playerid][1] >= FLOOD_CMD_LIMIT && (gettime() - g_FD_CommandFlooding[playerid][0]) < TIME_INTERVAL / 1000)
	{
	    if (funcidx("OnFloodDetected") != -1)
		{
			// Call the function if it exists.
			CallLocalFunction("OnFloodDetected", "dsd", playerid, ReturnIP(playerid), FLOOD_TYPE_COMMAND);

			// Reset the variable.
			g_FD_CommandFlooding[playerid][1] = 0;
		}
	}
	g_FD_CommandFlooding[playerid][0] = gettime();
	g_FD_CommandFlooding[playerid][1] ++;

	return CallLocalFunction("FD_OnPlayerCommandText", "ds", playerid, cmdtext);
}
	
public OnPlayerDisconnect(playerid, reason)
{
	if (isPlayerNameInvalid(playerid)) return 0;
	return CallLocalFunction("FD_OnPlayerDisconnect", "dd", playerid, reason);
}

stock ReturnIP(playerid)
{
	new
		szIP[16];
	return (GetPlayerIp(playerid, szIP, 16), szIP);
}
	
stock KickIP(ip[])
{
	new szIP[16];

	if (ip[0])
	{
	    #if !defined foreach
			for (new i = 0, j = GetMaxPlayers(); i != j; i ++) if (IsPlayerConnected(i))
		#else
			foreach (new i : Player)
		#endif
		{
			GetPlayerIp(i, szIP, sizeof (szIP));

			if (!strcmp(szIP, ip))
			{
			    Kick(i);
			}
		}
	}
   	return 1;
}

stock BanIP(ip[])
{
	new szIP[24];

	if (ip[0])
	{
	    KickIP(ip);
	    format(szIP, sizeof(szIP), "banip %s", ip);
	    SendRconCommand(szIP);
	}
   	return 1;
}

#if defined _ALS_OnPlayerConnect
	#undef OnPlayerConnect
#else
	#define _ALS_OnPlayerConnect
#endif

#if defined _ALS_OnPlayerDisconnect
	#undef OnPlayerDisconnect
#else
	#define _ALS_OnPlayerDisconnect
#endif

#if defined _ALS_OnPlayerText
	#undef OnPlayerText
#else
	#define _ALS_OnPlayerText
#endif

#if defined _ALS_OnPlayerCommandText
	#undef OnPlayerCommandText
#else
	#define _ALS_OnPlayerCommandText
#endif

#define OnPlayerConnect 	FD_OnPlayerConnect
#define OnPlayerDisconnect  FD_OnPlayerDisconnect
#define OnPlayerText        FD_OnPlayerText
#define OnPlayerCommandText FD_OnPlayerCommandText

forward FD_OnPlayerConnect(playerid);
forward FD_OnPlayerDisconnect(playerid, reason);
forward FD_OnPlayerText(playerid, text[]);
forward FD_OnPlayerCommandText(playerid, cmdtext[]);