//====================================================================================================
//
// Name: UNLOZE Forum Integration.
// Author: .George & zaCade (Original by Botox)
// Description: Handles forum access ingame.
//
//====================================================================================================
#include <sourcemod>
#include <SteamWorks>
#include <unloze>
#include <UNLOZE.secret> //#define UNLOZE_APIKEY here

#pragma newdecls required

/* STRINGS */
char G_sGroup[MAXPLAYERS+1][64];

/* BOOLS */
bool G_bPreAdminChecked[MAXPLAYERS+1];
bool G_bResponseFailed[MAXPLAYERS+1];
bool G_bResponsePassed[MAXPLAYERS+1];

bool g_bLateLoad = false;

Database g_hDatabase = null;

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
{
	
	CreateNative("AsyncHasSteamIDReservedSlot", Native_AsyncHasSteamIDReservedSlot);
	
	RegPluginLibrary("UNLOZE_ForumIntegration");
	
	g_bLateLoad = late;
	
	return APLRes_Success;
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public Plugin myinfo =
{
	name         = "UNLOZE Forum Integration",
	author       = ".George & zaCade (Original by Botox)",
	description  = "Handles forum access ingame",
	version      = "1.2.1"
};

//----------------------------------------------------------------------------------------------------
// Purpose: Late load
//----------------------------------------------------------------------------------------------------
public void OnPluginStart()
{
	EstablishConnection();
}

public void EstablishConnection()
{
	if (SQL_CheckConfig("xenforo"))
	{
		Database.Connect(ConnectionCallback, "xenforo");
	}
	else
	{
		SetFailState("'xenforo' not found in 'sourcemod/configs/databases.cfg'");
	}
}

public void ConnectionCallback(Database db, const char[] error, any data)
{
	if (db == null)
	{
		SetFailState("Failed to connect to the database, will attempt to reconnect on map change");
		return;
	}
	
	g_hDatabase = db;
	
	if (g_bLateLoad)
	{
		/* Late load */
		for(int client = 1; client <= MaxClients; client++)
		{
			if(IsClientConnected(client))
			{
				OnClientConnected(client);
			}
			if(IsClientAuthorized(client) && !IsFakeClient(client))
			{
				char sSteamID32[32];
				if(GetClientAuthId(client, AuthId_Steam2, sSteamID32, sizeof(sSteamID32)))
				{
					OnClientAuthorized(client, sSteamID32);
				}
			}
		}
	}
}




//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnRebuildAdminCache(AdminCachePart part)
{
	if (part != AdminCache_Admins)
	{
		return;
	}
	
	CreateTimer(1.0, OnRebuildAdminCachePost, INVALID_HANDLE, TIMER_FLAG_NO_MAPCHANGE);
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public Action OnRebuildAdminCachePost(Handle hTimer)
{
	for (int client = 1; client <= MaxClients; client++)
	{
		if(G_bResponsePassed[client] && G_bPreAdminChecked[client])
		{
			ApplyGroupFlags(client);
		}
	}
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnClientConnected(int client)
{
	G_bPreAdminChecked[client] = false;
	G_bResponseFailed[client] = false;
	G_bResponsePassed[client] = false;
	
	G_sGroup[client][0] = 0;
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnClientDisconnect(int client)
{
	G_bPreAdminChecked[client] = false;
	G_bResponseFailed[client] = false;
	G_bResponsePassed[client] = false;
	
	G_sGroup[client][0] = 0;
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnClientAuthorized(int client, const char[] sSteamID32)
{
	if (IsFakeClient(client))
	{
		return;
	}
	char sSteamID64[32];
	SteamID32toSteamID64(sSteamID32, sSteamID64, sizeof(sSteamID64));
	
	char sRequest[256];
	Format(sRequest, sizeof(sRequest), "select * from unloze_forum_2.xf_user_connected_account ka inner JOIN unloze_forum_2.xf_user_upgrade_active kak on ka.user_id = kak.user_id where provider_key  = '%s'", sSteamID64);
	//PrintToChatAll("OnClientAuthorized plugin start sRequest: %s", sRequest);
	g_hDatabase.Query(SQL_FUCKYOU, sRequest, GetClientSerial(client));
	
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void SQL_FUCKYOU(Database db, DBResultSet results, const char[] error, int data)
{
	int client;
	if ((client = GetClientFromSerial(data)) == 0 || db == null || results == null)
	{
		return;
	}
	//PrintToChatAll("SQL fuck you");
	if (results.RowCount && results.FetchRow())
	{
		OnClientAuthorized_OnTransferResponse("Game-Donator", data);
	}
	else
	{
		char sSID[32];
		GetClientAuthId(client, AuthId_Steam2, sSID, sizeof(sSID));
		char sSteamID64[32];
		SteamID32toSteamID64(sSID, sSteamID64, sizeof(sSteamID64));
		char sRequest[256];
		Format(sRequest, sizeof(sRequest), "select * from unloze_forum_2.xf_user xfu inner join unloze_forum_2.xf_user_connected_account xuea ON xfu.user_id = xuea.user_id where find_in_set('6',secondary_group_ids) <> 0 and provider_key  = '%s'", sSteamID64);
		g_hDatabase.Query(SQL_FUCKYOU_mapper, sRequest, GetClientSerial(client));
	}
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void SQL_FUCKYOU_mapper(Database db, DBResultSet results, const char[] error, int data)
{
        int client; 
        if ((client = GetClientFromSerial(data)) == 0 || db == null || results == null)
	{
                return;
	}
        if (results.RowCount && results.FetchRow())
        {
        	OnClientAuthorized_OnTransferResponse("Game-Donator", data);
        }
	else
	{
		char sSID[32];
                GetClientAuthId(client, AuthId_Steam2, sSID, sizeof(sSID));
                char sSteamID64[32];
                SteamID32toSteamID64(sSID, sSteamID64, sizeof(sSteamID64));
                char sRequest[256];
                Format(sRequest, sizeof(sRequest), "select * from unloze_forum_2.xf_user xfu inner join unloze_forum_2.xf_user_connected_account xuea ON xfu.user_id = xuea.user_id where find_in_set('21',secondary_group_ids) <> 0 and provider_key  = '%s'", sSteamID64);
                g_hDatabase.Query(SQL_FUCKYOU_retired, sRequest, GetClientSerial(client));
	}
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void SQL_FUCKYOU_retired(Database db, DBResultSet results, const char[] error, int data)
{
	if ( db == null || results == null)
	{
		return;
	}
        if (results.RowCount && results.FetchRow())
        {
                OnClientAuthorized_OnTransferResponse("Game-Donator", data);
        }
        else
        {
		OnClientAuthorized_OnTransferResponse("NOGROUP", data);
	}
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public int OnClientAuthorized_OnTransferResponse(char[] sData, int iSerial)
{
	int client = GetClientFromSerial(iSerial);
	
	if (!client) //Player disconnected.
	{
		return;
	}
	
	TrimString(sData);
	StripQuotes(sData);
	//PrintToChatAll("reached sData with status 200");	
	//LogMessage("reached sData with status 200: %s", sData);
	strcopy(G_sGroup[client], sizeof(G_sGroup[]), sData);
	
	G_bResponsePassed[client] = true;
	
	if (G_bPreAdminChecked[client])
	{
		NotifyPostAdminCheck(client);
	}
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public Action OnClientPreAdminCheck(int client)
{
	G_bPreAdminChecked[client] = true;
	
	if (G_bResponsePassed[client] || G_bResponseFailed[client])
	{
		return Plugin_Continue;
	}
	
	RunAdminCacheChecks(client);
	return Plugin_Handled;
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnClientPostAdminFilter(int client)
{
	ApplyGroupFlags(client);
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
stock void ApplyGroupFlags(int client)
{
	if (!G_bResponsePassed[client])
	{
		return;
	}
	AdminId AdmID;
	GroupId GrpID;
	
	if ((AdmID = GetUserAdmin(client)) == INVALID_ADMIN_ID)
	{
		LogMessage("Creating new admin for %L", client);
		
		AdmID = CreateAdmin();
		SetUserAdmin(client, AdmID, true);
	}
	
	if ((GrpID = FindAdmGroup(G_sGroup[client])) != INVALID_GROUP_ID)
	{
		if (AdminInheritGroup(AdmID, GrpID))
		{
			LogMessage("%L added to group %s", client, G_sGroup[client]);
		}
	}
	else
	{
		LogMessage("%L group not found %s", client, G_sGroup[client]);
	}
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public int Native_AsyncHasSteamIDReservedSlot(Handle plugin, int numParams)
{
	char sSteamID32[32];
	GetNativeString(1, sSteamID32, sizeof(sSteamID32));
	
	AsyncHasSteamIDReservedSlotCallbackFunc callback;
	callback = GetNativeCell(2);
	
	any data;
	data = GetNativeCell(3);
	
	char sSteamID64[32];
	SteamID32toSteamID64(sSteamID32, sSteamID64, sizeof(sSteamID64));
	
	char sRequest[256];
	Format(sRequest, sizeof(sRequest), "select * from unloze_forum_2.xf_user_connected_account ka inner JOIN unloze_forum_2.xf_user_upgrade_active kak on ka.user_id = kak.user_id where provider_key  = '%s'", sSteamID64);
	
	DataPack hDataPack = new DataPack();
	hDataPack.WriteString(sSteamID32);
	hDataPack.WriteFunction(callback);
	hDataPack.WriteCell(plugin);
	hDataPack.WriteCell(data);
	
	g_hDatabase.Query(SQL_FUCKYOU2, sRequest, hDataPack);
}

public void SQL_FUCKYOU2(Database db, DBResultSet results, const char[] error, DataPack fuck)
{
	if (db == null || results == null)
	{
		return;
	}
	if (results.RowCount && results.FetchRow())
	{
		Native_AsyncHasSteamIDReservedSlot_OnTransferResponse("Game-Donator", fuck);
	}
	else
	{
		char sSID[32];
		ResetPack(fuck);
                fuck.ReadString(sSID, sizeof(sSID));
                char sSteamID64[32];
                SteamID32toSteamID64(sSID, sSteamID64, sizeof(sSteamID64));
                char sRequest[256];
                Format(sRequest, sizeof(sRequest), "select * from unloze_forum_2.xf_user xfu inner join unloze_forum_2.xf_user_connected_account xuea ON xfu.user_id = xuea.user_id where find_in_set('6',secondary_group_ids) <> 0 and provider_key  = '%s'", sSteamID64);
                g_hDatabase.Query(SQL_FUCKYOU_mapper2, sRequest, fuck);
	}
}

public void SQL_FUCKYOU_mapper2(Database db, DBResultSet results, const char[] error, DataPack fuck)
{
	if (db == null || results == null)
	{
		return;
	}
        if (results.RowCount && results.FetchRow())
        {
                Native_AsyncHasSteamIDReservedSlot_OnTransferResponse("Game-Donator", fuck);
        }
	else
	{
		char sSID[32];
                ResetPack(fuck);
                fuck.ReadString(sSID, sizeof(sSID));
                char sSteamID64[32];
                SteamID32toSteamID64(sSID, sSteamID64, sizeof(sSteamID64));
                char sRequest[256];
		Format(sRequest, sizeof(sRequest), "select * from unloze_forum_2.xf_user xfu inner join unloze_forum_2.xf_user_connected_account xuea ON xfu.user_id = xuea.user_id where find_in_set('21',secondary_group_ids) <> 0 and provider_key  = '%s'", sSteamID64);
                //LogMessage("sRequest: %s", sRequest);
		g_hDatabase.Query(SQL_FUCKYOU_retired2, sRequest, fuck);
	}
}

public void SQL_FUCKYOU_retired2(Database db, DBResultSet results, const char[] error, DataPack fuck)
{
	if (db == null || results == null)
	{
		return;
	}
        if (results.RowCount && results.FetchRow())
        {
                Native_AsyncHasSteamIDReservedSlot_OnTransferResponse("Game-Donator", fuck);
        }
        else
        {
		Native_AsyncHasSteamIDReservedSlot_OnTransferResponse("NOGROUP", fuck);
	}
}


//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public int Native_AsyncHasSteamIDReservedSlot_OnTransferResponse(char[] sData, DataPack hDataPack)
{
	hDataPack.Reset();
	
	char sSteamID32[32];
	hDataPack.ReadString(sSteamID32, sizeof(sSteamID32));
	
	AsyncHasSteamIDReservedSlotCallbackFunc callback;
	callback = view_as<AsyncHasSteamIDReservedSlotCallbackFunc>(hDataPack.ReadFunction());
	
	Handle plugin;
	plugin = hDataPack.ReadCell();
	
	any data;
	data = hDataPack.ReadCell();
	
	TrimString(sData);
	StripQuotes(sData);
	
	int result;
	if (StrEqual(sData, "Game-Donator", false))
	{
		result = 1;
	}
	else
	{
		result = 0;
	}
	
	Call_StartFunction(plugin, callback);
	Call_PushString(sSteamID32);
	Call_PushCell(result);
	Call_PushCell(data);
	Call_Finish();
	
	delete hDataPack;
	return;
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
stock bool SteamID32toSteamID64(const char[] sSteamID32, char[] sSteamID64, int iSize)
{
	if (strlen(sSteamID32) < 11 || strncmp(sSteamID32[0], "STEAM_", 6))
	{
		sSteamID64[0] = 0;
		return false;
	}
	
	int iUpper = 765611979;
	int isSteam64ID = StringToInt(sSteamID32[10]) * 2 + 60265728 + sSteamID32[8] - 48;
	
	int iDiv = isSteam64ID / 100000000;
	int iIdx = 9 - (iDiv ? (iDiv / 10 + 1) : 0);
	
	iUpper += iDiv;
	
	IntToString(isSteam64ID, sSteamID64[iIdx], iSize - iIdx);
	iIdx = sSteamID64[9];
	
	IntToString(iUpper, sSteamID64, iSize);
	sSteamID64[9] = iIdx;
	
	return true;
}


