#include "pgsql.h"
#include "clog.h"
#include <string>
#include <iostream>

PGconn *conn;

int pgsql_db_connect(const char*host,const char*name,const char*user,const char*pass,long port)
{
	FILE_LOG(logSQL) << "pgsql_db_connect()";
	static std::string connection_str;

	if(host) {                                                                                                                    
		connection_str+="host=";
		connection_str+=host;                                                       
	}                                                                                                                                
	if(name) {                                                                                                                    
		connection_str+=" dbname=";
		connection_str+=name;                                                       
	}
	if(user) {                                                                    
		connection_str+=" user=";
		connection_str+=user;                                                       
	}
	if(pass) {                                                                                                                    
		connection_str+=" password=";
		connection_str+=pass;                                                       
	}                                                                                                                                
	if(port>0) {                                                                                                                  
		char pdb_port[20];
		connection_str+=" port=";
		connection_str+=pgsql_uitoa(port,pdb_port,10);                                 
	}

	conn = PQconnectdb(connection_str.c_str());
	if (PQstatus(conn) != CONNECTION_OK) {
		return 0;                                                                                                      
	}
	return 1;                                                                                                       
}

void pgsql_close() 
{
	FILE_LOG(logSQL) << "pgsql_close()";
	if (PQstatus(conn)==CONNECTION_OK) {
		PQfinish(conn);
	}
}

int pgsql_exec(const char * format, ... )
{
	FILE_LOG(logSQL) << "pgsql_exec()";
	char query[16384];
	va_list args;
	va_start (args, format);
	vsprintf (query, format, args);
	//perror (buffer);
	va_end (args);

	FILE_LOG(logSQL) << "About to run query: ";
	FILE_LOG(logSQL) << query;
	/* Escape any PostgrsSQL-unsafe characters */
	// user_size    = PQescapeStringConn (conn, user_data,    username, strlen(username), &pqesc_error);
	int num = 0;
	char *cmdTuples = NULL;
	PGresult *res = PQexec(conn, query); 
	if(!res) {
		/* Error */
		FILE_LOG(logSQL) << "Error: NULL result";
		num = -1;
	} else {
		switch (PQresultStatus(res)) {
			case PGRES_TUPLES_OK:
			case PGRES_COMMAND_OK:
				cmdTuples = PQcmdTuples(res);
				FILE_LOG(logSQL) << "PQcmdTuples: " << cmdTuples;
				num = atoi(cmdTuples);
				break;
			case PGRES_EMPTY_QUERY:
			case PGRES_BAD_RESPONSE:
			case PGRES_NONFATAL_ERROR:
			case PGRES_FATAL_ERROR:
			case PGRES_COPY_OUT:
			case PGRES_COPY_IN:
				num = -1;
				break;
		}
	}
	if (num<0) {
		FILE_LOG(logSQL) << "Affected rows: ERROR"; 
	} else {
		FILE_LOG(logSQL) << "Affected rows: " << num;
	}
	return num;
}

const PGresult* pgsql_query(const char * format, ... )
{
	FILE_LOG(logSQL) << "pgsql_query()";
	char query[16384];
	va_list args;
	va_start (args, format);
	vsprintf (query, format, args);
	//perror (buffer);
	va_end (args);

	FILE_LOG(logSQL) << "About to run query: ";
	FILE_LOG(logSQL) << query;
	/* Escape any PostgrsSQL-unsafe characters */
	// user_size    = PQescapeStringConn (conn, user_data,    username, strlen(username), &pqesc_error);
	int num = 0;
	const PGresult *res = PQexec(conn, query); 
	if(!res) {
		/* Error */
		num = -1;
		FILE_LOG(logSQL) << "Error: NULL result";
	} else {
		switch (PQresultStatus(res)) {
			case PGRES_TUPLES_OK:
			case PGRES_COMMAND_OK:
				num = PQntuples(res);
				FILE_LOG(logSQL) << "Found rows: " << num;
				break;
			case PGRES_EMPTY_QUERY:
			case PGRES_BAD_RESPONSE:
			case PGRES_NONFATAL_ERROR:
			case PGRES_FATAL_ERROR:
			case PGRES_COPY_OUT:
			case PGRES_COPY_IN:
				num = -1;
				break;
		}
	}
	if (num>0) {
		return res;
	}
	FILE_LOG(logSQL) << "Found rows: " << (num<0?"ERROR":"0"); 
	return NULL;
}

int pgsql_num_rows(const PGresult *res)
{
	if (res) {
		return PQntuples(res);
	}
	return 0;
}

int pgsql_num_fields(const PGresult *res)
{
	if (res) {
		return PQnfields(res);
	}
	return 0;
}

map<const char*,const char*> pgsql_fetch_assoc(const PGresult *res, int row)
{
	map<const char*, const char*> result;
	if (res) {
		const int rows = PQntuples(res);
		if (rows>0 && row<rows) {
			const int num = PQnfields(res);
			if (num>0) {
				for (int i=0; i<num; i++) {
					result[PQfname(res,i)] = PQgetvalue(res,row,i);
				}
				return result;
			}
		}
	}
	return result;
}

vector<const char*> pgsql_fetch_row(const PGresult *res, int row)
{
	vector<const char*> result;
	if (res) {
		const int rows = PQntuples(res);
		if (rows>0 && row<rows) {
			const int num = PQnfields(res);
			if (num>0) {
				for (int i=0; i<num; i++) {
					result.push_back(PQgetvalue(res,row,i));
				}
				return result;
			}
		}
	}
	return result;
}

char * pgsql_uitoa(unsigned n, char *s, int radix) 
{
        static const char tab[] =
                "0123456789abcdef";
        char *p = s;
        char *q = s;
        /* generate digits in reverse order */ 
        do { 
                *p++ = tab[n % radix];
                n /= radix;
        } while (n != 0);
        *p-- = '\0';
        /* reverse digits */
        while (q < p) {
                int temp = *p;
                *p-- = *q;
                *q++ = temp;
        }
        return s;
}

/*
vi:ts=2
*/
