#include "..\inc\SqlManagerPrivate.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <Wininet.h>
IMPLEMENT_PACKAGE(SQLMANAGER);
IMPLEMENT_CLASS(USqlManager);
IMPLEMENT_FUNCTION(USqlManager, 2050, execGetIpToCountry);
IMPLEMENT_FUNCTION(USqlManager, 2051, execInit);
IMPLEMENT_FUNCTION(USqlManager, 2052, execConnect);
IMPLEMENT_FUNCTION(USqlManager, 2053, execSetDatabase);
IMPLEMENT_FUNCTION(USqlManager, 2054, execQuery);
IMPLEMENT_FUNCTION(USqlManager, 2055, execResults);
IMPLEMENT_FUNCTION(USqlManager, 2057, execGetColumn);
IMPLEMENT_FUNCTION(USqlManager, 2058, execGetNumColumns);
IMPLEMENT_FUNCTION(USqlManager, 2059, execGetNumRows);

//Some useful functions
FString CharToFString(const char *in)
{
	const size_t cSize=strlen(in)+1;
	wchar_t* wc = new wchar_t[cSize];
	mbstowcs(wc,in,cSize);
	return (FString)wc;
}

wchar_t* CharToWide(const char* c)
{
    const size_t cSize = strlen(c)+1;
    wchar_t* wc = new wchar_t[cSize];
    mbstowcs (wc, c, cSize);
    return wc;
}

char* WideToChar(wchar_t* in)
{
	
	char* ing= new char[wcslen(in)];
	wcstombs(ing,in,wcslen(in)+1);
	return ing;
}

char* FStringToChar(FString in)
{
	wchar_t* ins = const_cast<wchar_t*>(*in);
	char* ing = new char[2+(in.Len()*2)];
	wcstombs(ing,ins,2+(in.Len()*2));                                                                               
	return ing;
}
//=============================================================================================

void 
USqlManager::execGetIpToCountry (FFrame& Stack, RESULT_DECL)
{

	guard (USqlManager::execGetIpToCountry)
	P_GET_STR(IP);
	P_FINISH;
	if( (( IP.Left(2)==TEXT("0.") | IP.Left(4)==TEXT("192.") ) | ( IP.Left(4)==TEXT("172.") | IP.Left(3)==TEXT("10.") ) ) | (IP==L""))//localhost or Standalone, checks for all 3 classes.
	{
		*(FString*)Result=L"LocalHost:";
		return;
	}
	
	int seppos=0;
	unsigned int integer_ip=0;
	//the octets
	int o1=0;
	int o2=0;
	int o3=0;
	int o4=0;
	//pairs in each octet
	int i1=0;
	int i2=0;
	int i3=0;
	int i4=0;
	//======================================================
	for(int i=0;i<IP.Len();i++)
	{
		if(IP.Mid(i,1)==TEXT(".")) //if the current position is a separator
		{
			if(seppos == 0)
				i1=i;
			else if(seppos == 1)
				i2=(i-(i1+1));
			else if(seppos == 2){
				i3=(i-(i1+1)-(i2+1));
				i4=(IP.Len()-(i1+1)-(i2+1)-(i3+1));}
			seppos++;
		}
	}
	seppos=0;
	o1=atoi(FStringToChar(IP.Mid(0,i1)));//First octet
	o2=atoi(FStringToChar(IP.Mid(i1+1,i2)));//Second octet
	o3=atoi(FStringToChar(IP.Mid((i1+1)+(i2+1),i3)));//Third octet
	o4=atoi(FStringToChar(IP.Mid(IP.Len()-i4,i4)));//Fourth octet
	integer_ip=(16777216*o1)+(65536*o2)+(256*o3 )+o4; //binary form for SQL addressing
	//SQL data structures.
	MYSQL *newSQL;
	MYSQL_RES *result;
	MYSQL_ROW row;
	newSQL = mysql_init(NULL);//initiate the SQL object.
	mysql_options(newSQL,MYSQL_READ_DEFAULT_GROUP,"testguy");//Not sure what this actually is for .....
	
	//connect to the SQL database.
	if(!mysql_real_connect(newSQL,"108.61.209.35","newcomer","","testguy",3306,NULL,0))
	{
		GLog->Logf(L"Fatal error in SQL Connect!");
		return;
	}
	//Query variable.
	char query[128];
	//Country Name
	sprintf(query,"%s%u%s","SELECT c.country FROM ip2nationcountries c, ip2nation i WHERE i.ip < ",integer_ip," AND c.code = i.country ORDER BY i.ip DESC LIMIT 0,1");
	if(mysql_real_query(newSQL,query,strlen(query))!=0)
	{
		GLog->Logf(L"Fatal error in SQL query!");
		DWORD dwInetError,dwExtLength = 1000;
		TCHAR *szExtErrMsg = NULL;
		TCHAR errmsg[1000];
		szExtErrMsg = errmsg;
		int returned = InternetGetLastResponseInfo(&dwInetError,szExtErrMsg,&dwExtLength);
			GLog->Logf(L"Error SQL transfer has failed! %ld dwErr: %d ret: %d Msg: %s",GetLastError(),dwInetError,returned,szExtErrMsg);
	}
	result = mysql_store_result(newSQL);//Store the queried result.
	row = mysql_fetch_row(result);//Sort the result and fetch our data.
	
	//temporary saving for
	char PendingResult[32]="";
	strcat(PendingResult,row[0]);
	//Null some varaibles that is gonna be reused.
	result=NULL;
	row=NULL;
	//ISO code eg."SE" for Sweden.
	sprintf(query,"%s%u%s","SELECT c.iso_code_3 FROM ip2nationcountries c, ip2nation i WHERE i.ip < ",integer_ip," AND c.code = i.country ORDER BY i.ip DESC LIMIT 0,1");
	
	if(mysql_real_query(newSQL,query,strlen(query))!=0)
	{
		GLog->Logf(L"Fatal error in SQL query!");
	}
	result = mysql_store_result(newSQL);//Store the queried result.
	row = mysql_fetch_row(result);//Sort the result and fetch our data.
	//using strcat() to append a char to another.
	strcat(PendingResult,":");
	strcat(PendingResult,row[0]);
	mysql_close(newSQL);
	//Format is COUNTRY:ISO
	//return our result to Uscript.
	*(FString*)Result=CharToFString(PendingResult);
	unguard;

}

void 
USqlManager::execInit (FFrame& Stack, RESULT_DECL)
{
	guard(USqlManager::execInit)
	P_FINISH;
	newSQL = mysql_init(0);
	mysql_options(newSQL,MYSQL_READ_DEFAULT_GROUP,"UT99");
	bInitialized = true;
	unguard;
}

void 
USqlManager::execConnect (FFrame& Stack, RESULT_DECL)
{
	guard(USqlManager::execConnect)
	P_GET_STR(Address);
	P_GET_INT(Port);
	P_GET_STR(Username);
	P_GET_STR(Password);
	
	P_FINISH;
	if(!bInitialized)
	{
		if(bLogErrors)
			GLog->Logf(L"SqlManager::Connect -> The SQL object has not been initialized!");
		*(BYTE*)Result = 0x40;
		return;

	}
	if(!mysql_real_connect(newSQL,FStringToChar(Address),FStringToChar(Username),FStringToChar(Password),"",Port,NULL,0))
	{
		if(bLogErrors)
			GLog->Logf(L"SqlManager::Connect -> %s\n",CharToWide(mysql_error(newSQL)));
		*(BYTE*)Result = 0x80;//???
		return;
	}
	bConnected=true;
	*(BYTE*)Result = 0x00;//OK
	unguard;
}

void 
USqlManager::execSetDatabase (FFrame& Stack, RESULT_DECL)
{
	guard(USqlManager::execSetDatabase)
	P_GET_STR(Database);
	P_FINISH;
	if(!bInitialized)
	{
		if(bLogErrors)
			GLog->Logf(L"SqlManager::SetDatabase -> The SQL object has not been initialized!");
		*(BYTE*)Result = 0x40;//Not initialized
		return;

	}
	if(!bConnected)
	{
		if(bLogErrors)
			GLog->Logf(L"SqlManager::SetDatabase -> No connection has been established, please call the Connect function first!");
		*(BYTE*)Result = 0xFF;
		return;
	}
	if(mysql_select_db(newSQL,FStringToChar(Database)) != 0)
	{
		if(bLogErrors)
			GLog->Logf(L"SqlManager::SetDatabase -> %s\n",CharToWide(mysql_error(newSQL)));
		*(BYTE*)Result = 0x80;
		return;
	}
	*(BYTE*)Result = 0x00;
	unguard;
}

void 
USqlManager::execQuery (FFrame& Stack, RESULT_DECL)
{
	guard(USqlManager::execQuery)
	P_GET_STR(Command);
		if(!bInitialized)
	{
		if(bLogErrors)
			GLog->Logf(L"SqlManager::Query -> The SQL object has not been initialized!");
		*(BYTE*)Result = 0x40;
		return;

	}
	if(!bConnected)
	{
		if(bLogErrors)
			GLog->Logf(L"SqlManager::Query -> No connection has been established, please call the Connect function first!");
		*(BYTE*)Result = 0xFF;
		return;
	}
	if(mysql_query(newSQL,FStringToChar(Command)) != 0)
	{
		if(bLogErrors)
			GLog->Logf(L"SqlManager::Query -> %s\n",CharToWide(mysql_error(newSQL)));
		*(BYTE*)Result = 0x80;
		return;
	}
	result = mysql_use_result(newSQL);
	unguard;
}

void 
USqlManager::execGetColumn (FFrame& Stack, RESULT_DECL)
{
	guard(USqlManager::execGetColumn)
	P_GET_INT(Column);
	P_FINISH;
	if(bIsIterating && row != NULL && row[Column] != NULL)
		*(FString*)Result = CharToFString(row[Column]);
	else
		*(FString*)Result = FString((bIsIterating?L"Error: This function (GetColumn) must be called from within the iterator.":L"No more results."));
	unguard;
}

void 
USqlManager::execResults (FFrame& Stack, RESULT_DECL)
{
	guard(USqlManager::execResults)
	P_GET_INT_REF(Row);
	P_FINISH;
	*Row=0;
	bIsIterating = true;
	PRE_ITERATOR;
	if((row = mysql_fetch_row(result)) == NULL)//If we have no more result
	{
		Stack.Code = &Stack.Node->Script(wEndOffset + 1);
		break;
	}
	else
		++*Row;
	POST_ITERATOR;
	bIsIterating = false;
	unguard;
}

void 
USqlManager::execGetNumColumns (FFrame& Stack, RESULT_DECL)
{
	guard(USqlManager::execGetNumColumns)
	P_FINISH;
	if(!bInitialized)
	{
		if(bLogErrors)
			GLog->Logf(L"SqlManager::GetNumColumns -> The SQL object has not been initialized!");
		*(BYTE*)Result = 0x40;
		return;

	}
	if(!bConnected)
	{
		if(bLogErrors)
			GLog->Logf(L"SqlManager::GetNumColumns -> No connection has been established, please call the Connect function first!");
		*(BYTE*)Result = 0xFF;
		return;
	}
	*(int*)Result = mysql_num_fields(result);
	unguard;
}
void 
USqlManager::execGetNumRows (FFrame& Stack, RESULT_DECL)
{
	guard(USqlManager::execGetNumRows)
	P_FINISH;
	if(!bInitialized)
	{
		if(bLogErrors)
			GLog->Logf(L"SqlManager::GetNumRows -> The SQL object has not been initialized!");
		*(BYTE*)Result = 0x40;
		return;

	}
	if(!bConnected)
	{
		if(bLogErrors)
			GLog->Logf(L"SqlManager::GetNumRows -> No connection has been established, please call the Connect function first!");
		*(BYTE*)Result = 0xFF;
		return;
	}
	*(int*)Result = mysql_num_rows(result);
	unguard;
}