/**************************************************************************/
/*                                                                        */
/* SAMP-MySQL v0.1 plugin                                                 */
/*                                                                        */
/* Coded by  ADreNaLINe-DJ                                                */
/* Contact: adrenalinedj@msn.com                                          */
/*                                                                        */
/*                                                                        */
/* This program is free software; you can redistribute it and/or modify   */
/*  it under the terms of the GNU General Public License as published by  */
/*  the Free Software Foundation; either version 3 of the License, or     */
/*  (at your option) any later version.                                   */
/*   This program is distributed in the hope that it will be useful,      */
/*  but WITHOUT ANY WARRANTY; without even the implied warranty of        */
/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
/*  GNU General Public License for more details.                          */
/*                                                                        */
/*  You should have received a copy of the GNU General Public License     */
/*  along with this program.  If not, see <http://www.gnu.org/licenses/>. */
/*                                                                        */
/**************************************************************************/

#include "SDK/plugin.h"
#if defined WIN32
  //include this before mysql.h because it depends on socket types
  #include <winsock.h>
#endif
#include <mysql/mysql.h>
#include <malloc.h>
#include <string.h>

typedef void (*logprintf_t)(char* format, ...);

logprintf_t logprintf;
void **ppPluginData;
extern void *pAMXFunctions;

//Some declaration functions
static char *pcCreateAndFillStringFromCell(AMX *amx,cell params);
int set_amxstring(AMX *amx,cell amx_addr, char *source,int max);

//Global variables
MYSQL connexion;
MYSQL_RES *result;


PLUGIN_EXPORT unsigned int PLUGIN_CALL Supports()
{
	return SUPPORTS_VERSION | SUPPORTS_AMX_NATIVES;
}

PLUGIN_EXPORT bool PLUGIN_CALL Load( void **ppData )
{
	pAMXFunctions = ppData[PLUGIN_DATA_AMX_EXPORTS];
	logprintf = (logprintf_t)ppData[PLUGIN_DATA_LOGPRINTF];

	logprintf("\n/************************************************/\n/* SAMP-MySQL v0.1 Plugin loaded successfully ! */\n/************************************************/\n");
	return true;
}

PLUGIN_EXPORT void PLUGIN_CALL Unload( )
{
	logprintf("\n/**************************************************/\n/* SAMP-MySQL v0.1 Plugin unloaded successfully ! */\n/**************************************************/\n");
}

/*********************************************/
/* Initialisation and connection to database */
/*********************************************/
static cell AMX_NATIVE_CALL n_samp_mysql_connect( AMX* amx, cell* params )
{
	const char* serveur;
	const char* user;
	const char* password;
    MYSQL* retval;
    serveur=pcCreateAndFillStringFromCell(amx, params[1]);
	user=pcCreateAndFillStringFromCell(amx, params[2]);
	password=pcCreateAndFillStringFromCell(amx, params[3]);
  mysql_init(&connexion);
  retval=mysql_real_connect(&connexion, serveur, user, password, 0, 0, 0, 0);
  if(retval)
  {
  	logprintf("\nConnection to MySQL database: Successfull !");
  	return 1;
  }
  else
  {
  	logprintf("\nConnection to MySQL database: Failed !");
  	logprintf("%s",mysql_error(&connexion));
  	return 0;
  }
}

/***********************/
/* Select the database */
/***********************/
static cell AMX_NATIVE_CALL n_samp_mysql_select_db( AMX* amx, cell* params )
{
	int retval;
	const char *db;
  db=pcCreateAndFillStringFromCell(amx, params[1]);
  retval=mysql_select_db(&connexion, db); //mysql_select_db returns 0 if success
  if(!retval)
  {
  	return 1;
  }
  else
  {
        logprintf("Error in mysql_select_db: %s",mysql_error(&connexion));
		return 0;
	}
}

/****************************************************/
/* Execute a query (connection must be initialized) */
/****************************************************/
static cell AMX_NATIVE_CALL n_samp_mysql_query( AMX* amx, cell* params )
{
	int retval;
	const char *query;
  query=pcCreateAndFillStringFromCell(amx, params[1]);
  retval=mysql_query(&connexion, query); //mysql_query returns 0 if success
  if(!retval)
  {
  	return 1;
  }
  else
  {
        logprintf("Error in mysql_query: %s",mysql_error(&connexion));
		return 0;
	}
}

/******************************************************/
/* Prepare the result (query must be executed before) */
/******************************************************/
static cell AMX_NATIVE_CALL n_samp_mysql_store_result( AMX* amx, cell* params )
{
	result=mysql_store_result(&connexion);
	if(result!=0)
	{
		return 1;
	}
	else
	{
        logprintf("Error in mysql_store_result: %s",mysql_error(&connexion));
		return 0;
	}
}

/******************************************************************/
/* Return a line of result (store_result must be executed before) */
/******************************************************************/
static cell AMX_NATIVE_CALL n_samp_mysql_fetch_row( AMX* amx, cell* params )
{
	MYSQL_ROW rowtoreturn;
	int num_fields;
	int i, stringsize, len;
	char *stringtoreturn;

	num_fields=mysql_num_fields(result);
	rowtoreturn=mysql_fetch_row(result);
	stringsize=0;
	for(i=0;i<num_fields;i++)
	{
		stringsize=stringsize+strlen(rowtoreturn[i]);
	}
	stringsize=stringsize+num_fields+1;
	stringtoreturn=(char*)malloc(stringsize);
	stringtoreturn[0]='\0';
	for(i=0;i<num_fields;i++)
	{
		strcat(stringtoreturn, rowtoreturn[i]);
		if(i!=num_fields-1)
		{
			strcat(stringtoreturn, "|");
		}
	}
    len = strlen(stringtoreturn);
	set_amxstring(amx, params[1], stringtoreturn, len);
	return 1;
}

/**********************************************************************************/
/* Return the number of rows in the result (store_result must be executed before) */
/**********************************************************************************/
static cell AMX_NATIVE_CALL n_samp_mysql_num_rows( AMX* amx, cell* params )
{
	int retval;
	retval=mysql_num_rows(result);
	return retval;
}

/************************************************************************************/
/* Return the number of fields in the result (store_result must be executed before) */
/************************************************************************************/
static cell AMX_NATIVE_CALL n_samp_mysql_num_fields( AMX* amx, cell* params )
{
	int retval;
	retval=mysql_num_fields(result);
	return retval;
}

/************************************/
/* Close the connection to database */
/************************************/
static cell AMX_NATIVE_CALL n_samp_mysql_close( AMX* amx, cell* params )
{
  mysql_close(&connexion);
	return 1;
}

AMX_NATIVE_INFO SAMPMySQLNatives[ ] =
{
	{ "samp_mysql_connect",			n_samp_mysql_connect },
	{ "samp_mysql_select_db",			n_samp_mysql_select_db },
	{ "samp_mysql_query",			n_samp_mysql_query },
	{ "samp_mysql_store_result",			n_samp_mysql_store_result },
	{ "samp_mysql_fetch_row",			n_samp_mysql_fetch_row },
	{ "samp_mysql_num_rows",			n_samp_mysql_num_rows },
	{ "samp_mysql_num_fields",			n_samp_mysql_num_fields },
	{ "samp_mysql_close",			n_samp_mysql_close },
	{ 0,					0 }
};

PLUGIN_EXPORT int PLUGIN_CALL AmxLoad( AMX *amx )
{
	return amx_Register( amx, SAMPMySQLNatives, -1 );
}

PLUGIN_EXPORT int PLUGIN_CALL AmxUnload( AMX *amx )
{
	return AMX_ERR_NONE;
}

/***********************************************/
/* Function returns string from a "cell" param */
/***********************************************/
static char *pcCreateAndFillStringFromCell(AMX *amx,cell params)
{
    char *szDest;
    int nLen;
    cell *pString;
    amx_GetAddr(amx,params,&pString);
    amx_StrLen(pString, &nLen);
    szDest = new char[nLen+1];
    amx_GetString(szDest, pString, 0, UNLIMITED);
    return szDest;
}

/********************************************/
/* Function that set a string in the params */
/* Very useful for functions like           */
/* mysql_fetch_row                          */
/*                                          */
/* function provided by Static              */
/********************************************/
int set_amxstring(AMX *amx,cell amx_addr, char *source,int max)
{
  cell* dest = (cell *)(amx->base + (int)(((AMX_HEADER *)amx->base)->dat + amx_addr));
  cell* start = dest;
  while (max--&&*source)
    *dest++=(cell)*source++;
  *dest = 0;
  return dest-start;
}
