/*
** SellaNMS
** $Id: storagedata.cxx,v 1.7 2006/01/24 07:08:09 sella Exp $
** Copyright (c) 2001-2005 Digital Genesis Software, LLC. All Rights Reserved.
** Released under the GPL Version 2 License.
** http://www.digitalgenesis.com
*/

static const char rcsid[] = "$Id: storagedata.cxx,v 1.7 2006/01/24 07:08:09 sella Exp $";

#include "storagedata.h"
#include <signal.h>
#include <stdio.h>
#include <pthread.h>
#include <stl/string>
#include <stl/vector>
#include <stl/algorithm>

StorageData::StorageData() {
	this->resultSet = NULL;

	clear();
}

StorageData::StorageData(StorageData const &src) {
	*this = src;
}

StorageData::~StorageData() {
	clear();
}

void StorageData::clear() {
	if (this->resultSet != NULL) {
		dbi_result_free(this->resultSet);
		this->resultSet = NULL;
	}
	this->error = false;
	this->currentRow = 0;
	this->numberRows = 0;
	this->connection = NULL;
	this->connectionMutex = NULL;
}

RESULT StorageData::setResultSet(const dbi_result result_set, dbi_conn connection, pthread_mutex_t *connection_mutex) {
	RESULT result = SUCCESS;

	/* Clear previous data. */
	clear();

	/* Assigning the opaque pointer. */
	this->resultSet = result_set;
	this->connection = connection;

	/* Assign Mutex */
	this->connectionMutex = connection_mutex;

	/* Set row count. */
	this->numberRows = dbi_result_get_numrows(this->resultSet);

	return result;
}

inline bool StorageData::isError() {
	if (error || this->resultSet == NULL) {
		/* Clear error. */
		error = false;

		return true;
	}
	
	return false;
}

bool StorageData::firstRow() {
	bool status = false;

	if (!isSane()) return false;

	if (dbi_result_get_numrows(this->resultSet) > 0) {
		if ((status = (bool) dbi_result_first_row(this->resultSet))) {
			this->currentRow = 1;
		}
	}

	return status;
}

bool StorageData::lastRow() {
	bool status = false;

	if (!isSane()) return false;

	if (dbi_result_get_numrows(this->resultSet) > 0) {
		if ((status = (bool) dbi_result_last_row(this->resultSet))) {
			this->currentRow = this->numberRows;
		}
	}

	return status;
}

bool StorageData::nextRow() {
	bool status = true;

	if (!isSane()) return false;

	if (this->currentRow >= this->numberRows) {
		status = false;
	} else if (status = (bool) dbi_result_next_row(this->resultSet)) {
		this->currentRow++;
	}

	return status;
}

bool StorageData::prevRow() {
	bool status = true;

	if (!isSane()) return false;

	if (this->currentRow <= 1) {
		status = false;
	} else if (status = (bool) dbi_result_prev_row(this->resultSet)) {
		this->currentRow--;
	}

	return status;
}

bool StorageData::seekRow(const unsigned int &row) {
	bool status;

	if (!isSane()) return false;

	status = (bool) dbi_result_seek_row(this->resultSet, row);

	if (status)
		this->currentRow = row;

	return status;
}

int StorageData::getCurRow() {
	if (!isSane()) return -1;

	return this->currentRow;
}

int StorageData::getNumRow() {
	if (!isSane()) return -1;

	return this->numberRows;
}

int StorageData::getNumRowAffected() {
	if (!isSane(0)) return -1;

	return dbi_result_get_numrows_affected(this->resultSet);
}

unsigned long long StorageData::getLastInsertId(const string &table) {
	if (!isSane(0)) return 0;

	return dbi_conn_sequence_last(connection, table.c_str());
}

unsigned int StorageData::getFieldSize(const string &field) {
	if (!isSane(1)) return 0;

	return dbi_result_get_field_size(this->resultSet, field.c_str());
}

unsigned int StorageData::getFieldSizeIdx(const unsigned int &idx) {
	if (!isSane(1)) return 0;

	return dbi_result_get_field_size_idx(this->resultSet, idx);
}

unsigned int StorageData::getFieldLength(const string &field) {
	if (!isSane(1)) return 0;

	return dbi_result_get_field_length(this->resultSet, field.c_str());
}

unsigned int StorageData::getFieldLengthIdx(const unsigned int &idx) {
	if (!isSane(1)) return 0;

	return dbi_result_get_field_length_idx(this->resultSet, idx);
}

int StorageData::getFieldIdx(const string &field) {
	if (!isSane(1)) return 0;

	return dbi_result_get_field_idx(this->resultSet, field.c_str());
}

bool StorageData::getFieldName(string &field, const unsigned int &idx) {
	bool status = true;
	const char *name;

	if (!isSane(1)) return false;

	if ((name = dbi_result_get_field_name(this->resultSet, idx))) {
		field = name;
	} else {
		status = false;
	}

	return status;
}

unsigned int StorageData::getNumFields() {
	if (!isSane(1)) return 0;

	return dbi_result_get_numfields(this->resultSet);
}

bool StorageData::getFieldType(unsigned short &type, const string &field) {
	if (!isSane(1)) return false;

	type = dbi_result_get_field_type(this->resultSet, field.c_str());

	return (type) ? true : false;
}

bool StorageData::getFieldTypeIdx(unsigned short &type, const unsigned int &idx) {
	if (!isSane(1)) return false;

	type = dbi_result_get_field_type_idx(this->resultSet, idx);

	return (type) ? true : false;
}

bool StorageData::getFieldAttrib(unsigned int &attrib, const string &field, const unsigned long &attrib_min, const unsigned long attrib_max) {
	LMSG("DEBUG: StorageData::getFieldAttrib() not implemented.");
	abort();
}

bool StorageData::getFieldAttribIdx(unsigned int &attrib, const unsigned int &idx, const unsigned long &attrib_min, const unsigned long attrib_max) {
	LMSG("DEBUG: StorageData::getFieldAttribIdx() not implemented.");
	abort();
}

bool StorageData::getFieldAttribs(unsigned int &attribs, const string &field) {
	bool status = true;
	unsigned int dbi_value;

	if (!isSane(1)) return false;

	pthread_mutex_lock(connectionMutex);

	dbi_value = dbi_result_get_field_attribs(this->resultSet, field.c_str());
	if (isError()) {
		status = false;
	} else {
		attribs = dbi_value;
	}

	pthread_mutex_unlock(connectionMutex);

	return status;
}

bool StorageData::getFieldAttribsIdx(unsigned int &attribs, const unsigned int &idx) {
	bool status = true;
	unsigned int dbi_value;

	if (!isSane(1)) return false;

	pthread_mutex_lock(connectionMutex);

	dbi_value = dbi_result_get_field_attribs_idx(this->resultSet, idx);
	if (isError()) {
		status = false;
	} else {
		attribs = dbi_value;
	}

	pthread_mutex_unlock(connectionMutex);

	return status;
}

string StorageData::quoteString(const string &field) {
	char *buf;
	size_t len;
	bool status = true;
	dbi_driver driver;
	string quoted_field;

	len = field.size() + 1;
	buf = (char*) malloc(len);

	if (buf) {
		/* FIXME: This doesn't account for multiple databases that are different. */
		driver = dbi_driver_list(NULL);

		strncpy(buf, field.c_str(), len);

		/* Call to dbi_driver_quote_string() frees original allocation and reallocates new memory. */
		if (driver == NULL || dbi_driver_quote_string(driver, &buf) < 1) {
			status = false;
		}

		if (buf != NULL) {
			quoted_field = buf;
			free(buf);
		}
	}

	return quoted_field;
}

int StorageData::getFields(const char *format, ...) {
	LMSG("DEBUG: StorageData::getFields() not implemented.");
	abort();
}

bool StorageData::getAuto(string &value, const string &field) {
	bool status = false;
	unsigned short type;
	unsigned int attribs;

	if (!isSane(1)) return false;

	if (!getFieldType(type, field)) {
		LMSG("failed to get type for field '%s'.", field.c_str());
		return false;
	}

#if 0
#define DBI_STRING_FIXEDSIZE    (1 << 0) /* XXX unused as of now */

#define DBI_DATETIME_DATE               (1 << 0)
#define DBI_DATETIME_TIME               (1 << 1)
#endif

	switch (type) {
		case DBI_TYPE_INTEGER:
			/* Aquire special attribs. */
			getFieldAttribs(attribs, field);

			/* Isolate attributes we're interested in. */
			switch (attribs & (DBI_INTEGER_UNSIGNED | DBI_INTEGER_SIZE1 | DBI_INTEGER_SIZE2 | DBI_INTEGER_SIZE3 | DBI_INTEGER_SIZE4 | DBI_INTEGER_SIZE8)) {
				case (DBI_INTEGER_SIZE1):
					/* Get Signed Char */
					status = getChar(value, field);
					break;

				case (DBI_INTEGER_UNSIGNED | DBI_INTEGER_SIZE1):
					/* Get Unsigned Char */
					status = getUChar(value, field);
					break;

				case (DBI_INTEGER_SIZE2):
					/* Get Signed Short */
					status = getShort(value, field);
					break;

				case (DBI_INTEGER_UNSIGNED | DBI_INTEGER_SIZE2):
					/* Get Unsigned Short */
					status = getUShort(value, field);
					break;

				case (DBI_INTEGER_SIZE3):
				case (DBI_INTEGER_SIZE4):
					/* Get Signed Long */
					status = getLong(value, field);
					break;

				case (DBI_INTEGER_UNSIGNED | DBI_INTEGER_SIZE3):
				case (DBI_INTEGER_UNSIGNED | DBI_INTEGER_SIZE4):
					/* Get Unsigned Long */
					status = getULong(value, field);
					break;

				case (DBI_INTEGER_SIZE8):
					/* Get Signed Long Long */
					status = getLongLong(value, field);
					break;

				case (DBI_INTEGER_UNSIGNED | DBI_INTEGER_SIZE8):
					/* Get Unsigned Long Long */
					status = getULongLong(value, field);
					break;
			}
			break;

		case DBI_TYPE_DECIMAL:
			/* Aquire special attribs. */
			getFieldAttribs(attribs, field);

			/* Isolate attributes we're interested in. */
			switch (attribs & (DBI_DECIMAL_UNSIGNED | DBI_DECIMAL_SIZE4 | DBI_DECIMAL_SIZE8)) {
				case (DBI_DECIMAL_SIZE4):
				case (DBI_DECIMAL_UNSIGNED | DBI_DECIMAL_SIZE4):
					/* Get Signed/Unsigned Double */
					status = getFloat(value, field);
					break;

				case (DBI_DECIMAL_SIZE8):
				case (DBI_DECIMAL_UNSIGNED | DBI_DECIMAL_SIZE8):
					/* Get Signed/Unsigned Double */
					status = getDouble(value, field);
					break;
			}
			break;

		case DBI_TYPE_STRING:
			/* NOTE: Attrib DBI_STRING_FIXEDSIZE not supported by libdbi as of version 0.7.2. */
			status = getString(value, field);
			break;

		case DBI_TYPE_BINARY:
			status = getBinary(value, field);
			break;

		case DBI_TYPE_DATETIME:
			/* Aquire special attribs. */
			getFieldAttribs(attribs, field);

			if (attribs & DBI_DATETIME_DATE) {
				status = getDatetime(value, field);
			} else if (attribs & DBI_DATETIME_TIME) {
				LMSG("DEBUG: DBI_TYPE_DATETIME attribute DBI_DATETIME_TIME not implemented.");
			} else {
				LMSG("DEBUG: DBI_TYPE_DATETIME attribute %lu not implemented.", attribs);
			}

			break;

		default:
			LMSG("DEBUG: Unknown type '%d' with attrib '%d'", type, attribs);
	}

	return status;
}

bool StorageData::getChar(string &value, const string &field) {
	bool status;
	char buf[132];
	char dbi_value;

	if (status = getChar(dbi_value, field)) {
		/* hh = char, d = decimal */
		snprintf(buf, 132, "%hhd", dbi_value);
		value = buf;
	}
	
	return status;
}

bool StorageData::getChar(char &value, const string &field) {
	bool status = true;
	char dbi_value;

	if (!isSane(1)) return false;

	pthread_mutex_lock(connectionMutex);

	dbi_value = dbi_result_get_char(this->resultSet, field.c_str());
	if (isError()) {
		status = false;
	} else {
		value = dbi_value;
	}

	pthread_mutex_unlock(connectionMutex);

	return status;
}

bool StorageData::getUChar(string &value, const string &field) {
	bool status;
	char buf[132];
	unsigned char dbi_value;

	if (status = getUChar(dbi_value, field)) {
		/* hh = char, u = unsigned */
		snprintf(buf, 132, "%hhu", dbi_value);
		value = buf;
	}
	
	return status;
}

bool StorageData::getUChar(unsigned char &value, const string &field) {
	bool status = true;
	unsigned char dbi_value;

	if (!isSane(1)) return false;

	pthread_mutex_lock(connectionMutex);

	dbi_value = dbi_result_get_uchar(this->resultSet, field.c_str());
	if (isError()) {
		status = false;
	} else {
		value = dbi_value;
	}

	pthread_mutex_unlock(connectionMutex);

	return status;
}

bool StorageData::getShort(string &value, const string &field) {
	bool status;
	char buf[132];
	short dbi_value;

	if (status = getShort(dbi_value, field)) {
		/* h = short, d = decimal */
		snprintf(buf, 132, "%hd", dbi_value);
		value = buf;
	}
	
	return status;
}

bool StorageData::getShort(short &value, const string &field) {
	bool status = true;
	short dbi_value;

	if (!isSane(1)) return false;

	pthread_mutex_lock(connectionMutex);

#ifdef DEBUG
	unsigned short type;
	if (!getFieldType(type, field)) {
		LMSG("getFieldType() failed for field '%s'", field.c_str());
		abort();
	} else if (type != DBI_TYPE_INTEGER) {
		LMSG("requested type %d (DBI_TYPE_INTEGER) != libdbi reported type %d for field '%s' (1 INT, 2 DEC, 3 STR, 4 BIN, 5 DATE)", DBI_TYPE_INTEGER, type, field.c_str());
		abort();
	}
#endif

	dbi_value = dbi_result_get_short(this->resultSet, field.c_str());
	if (isError()) {
		status = false;
	} else {
		value = dbi_value;
	}

	pthread_mutex_unlock(connectionMutex);

	return status;
}

bool StorageData::getUShort(string &value, const string &field) {
	bool status;
	char buf[132];
	unsigned short dbi_value;

	if (status = getUShort(dbi_value, field)) {
		/* h = short, u = unsigned */
		snprintf(buf, 132, "%hu", dbi_value);
		value = buf;
	}
	
	return status;
}

bool StorageData::getUShort(unsigned short &value, const string &field) {
	bool status = true;
	unsigned short dbi_value;

	if (!isSane(1)) return false;

	pthread_mutex_lock(connectionMutex);

#ifdef DEBUG
	unsigned short type;
	if (!getFieldType(type, field)) {
		LMSG("getFieldType() failed for field '%s'", field.c_str());
		abort();
	} else if (type != DBI_TYPE_INTEGER) {
		LMSG("requested type %d (DBI_TYPE_INTEGER) != libdbi reported type %d for field '%s' (1 INT, 2 DEC, 3 STR, 4 BIN, 5 DATE)", DBI_TYPE_INTEGER, type, field.c_str());
		abort();
	}
#endif

	dbi_value = dbi_result_get_ushort(this->resultSet, field.c_str());
	if (isError()) {
		status = false;
	} else {
		value = dbi_value;
	}

	pthread_mutex_unlock(connectionMutex);

	return status;
}

bool StorageData::getLong(string &value, const string &field) {
	bool status;
	char buf[132];
	long tmp;

	if (status = getLong(tmp, field)) {
		snprintf(buf, 132, "%ld", tmp);
		value = buf;
	}
	
	return status;
}

bool StorageData::getLong(long &value, const string &field) {
	bool status = true;
	long dbi_value;

	if (!isSane(1)) return false;

	pthread_mutex_lock(connectionMutex);

#ifdef DEBUG
	unsigned short type;
	if (!getFieldType(type, field)) {
		LMSG("getFieldType() failed for field '%s'", field.c_str());
		abort();
	} else if (type != DBI_TYPE_INTEGER) {
		LMSG("requested type %d (DBI_TYPE_INTEGER) != libdbi reported type %d for field '%s' (1 INT, 2 DEC, 3 STR, 4 BIN, 5 DATE)", DBI_TYPE_INTEGER, type, field.c_str());
		abort();
	}
#endif

	dbi_value = dbi_result_get_long(this->resultSet, field.c_str());
	if (isError()) {
		status = false;
	} else {
		value = dbi_value;
	}

	pthread_mutex_unlock(connectionMutex);

	return status;
}

bool StorageData::getULong(string &value, const string &field) {
	bool status;
	char buf[132];
	unsigned long tmp;

	if (status = getULong(tmp, field)) {
		snprintf(buf, 132, "%lu", tmp);
		value = buf;
	}
	
	return status;
}

bool StorageData::getULong(unsigned long &value, const string &field) {
	bool status = true;
	unsigned long dbi_value;

	if (!isSane(1)) return false;

	pthread_mutex_lock(connectionMutex);

#ifdef DEBUG
	unsigned short type;
	if (!getFieldType(type, field)) {
		LMSG("getFieldType() failed for field '%s'", field.c_str());
		abort();
	} else if (type != DBI_TYPE_INTEGER) {
		LMSG("requested type %d (DBI_TYPE_INTEGER) != libdbi reported type %d for field '%s' (1 INT, 2 DEC, 3 STR, 4 BIN, 5 DATE)", DBI_TYPE_INTEGER, type, field.c_str());
		abort();
	}
#endif

	dbi_value = dbi_result_get_ulong(this->resultSet, field.c_str());
	if (isError()) {
		status = false;
	} else {
		value = dbi_value;
	}

	pthread_mutex_unlock(connectionMutex);

	return status;
}

bool StorageData::getLongLong(string &value, const string &field) {
	bool status;
	char buf[132];
	long long dbi_value;

	if (status = getLongLong(dbi_value, field)) {
		snprintf(buf, 132, "%lld", dbi_value);
		value = buf;
	}
	
	return status;
}

bool StorageData::getLongLong(long long &value, const string &field) {
	bool status = true;
	long long dbi_value;

	if (!isSane(1)) return false;

	pthread_mutex_lock(connectionMutex);

#ifdef DEBUG
	unsigned short type;
	if (!getFieldType(type, field)) {
		LMSG("getFieldType() failed for field '%s'", field.c_str());
		abort();
	} else if (type != DBI_TYPE_INTEGER) {
		LMSG("requested type %d (DBI_TYPE_INTEGER) != libdbi reported type %d for field '%s' (1 INT, 2 DEC, 3 STR, 4 BIN, 5 DATE)", DBI_TYPE_INTEGER, type, field.c_str());
		abort();
	}
#endif

	dbi_value = dbi_result_get_longlong(this->resultSet, field.c_str());
	if (isError()) {
		status = false;
	} else {
		value = dbi_value;
	}

	pthread_mutex_unlock(connectionMutex);

	return status;
}

bool StorageData::getULongLong(string &value, const string &field) {
	bool status;
	char buf[132];
	unsigned long long dbi_value;

	if (status = getULongLong(dbi_value, field)) {
		snprintf(buf, 132, "%llu", dbi_value);
		value = buf;
	}
	
	return status;
}

bool StorageData::getULongLong(unsigned long long &value, const string &field) {
	bool status = true;
	unsigned long long dbi_value;

	if (!isSane(1)) return false;

	pthread_mutex_lock(connectionMutex);

#ifdef DEBUG
	unsigned short type;
	if (!getFieldType(type, field)) {
		LMSG("getFieldType() failed for field '%s'", field.c_str());
		abort();
	} else if (type != DBI_TYPE_INTEGER) {
		LMSG("requested type %d (DBI_TYPE_INTEGER) != libdbi reported type %d for field '%s' (1 INT, 2 DEC, 3 STR, 4 BIN, 5 DATE)", DBI_TYPE_INTEGER, type, field.c_str());
		abort();
	}
#endif

	dbi_value = dbi_result_get_ulonglong(this->resultSet, field.c_str());
	if (isError()) {
		status = false;
	} else {
		value = dbi_value;
	}

	pthread_mutex_unlock(connectionMutex);

	return status;
}

bool StorageData::getFloat(string &value, const string &field) {
	bool status;
	char buf[132];
	float dbi_value;

	if (status = getFloat(dbi_value, field)) {
		snprintf(buf, 132, "%f", dbi_value);
		value = buf;
	}
	
	return status;
}

bool StorageData::getFloat(float &value, const string &field) {
	bool status = true;
	float dbi_value;

	if (!isSane(1)) return false;

	pthread_mutex_lock(connectionMutex);

#ifdef DEBUG
	unsigned short type;
	if (!getFieldType(type, field)) {
		LMSG("getFieldType() failed for field '%s'", field.c_str());
		abort();
	} else if (type != DBI_TYPE_DECIMAL) {
		LMSG("requested type %d (DBI_TYPE_DECIMAL) != libdbi reported type %d for field '%s' (1 INT, 2 DEC, 3 STR, 4 BIN, 5 DATE)", DBI_TYPE_DECIMAL, type, field.c_str());
		abort();
	}
#endif

	dbi_value = dbi_result_get_float(this->resultSet, field.c_str());
	if (isError()) {
		status = false;
	} else {
		value = dbi_value;
	}

	pthread_mutex_unlock(connectionMutex);

	return status;
}

bool StorageData::getDouble(string &value, const string &field) {
	bool status;
	char buf[132];
	double dbi_value;

	if (status = getDouble(dbi_value, field)) {
		snprintf(buf, 132, "%f", dbi_value);
		value = buf;
	}

	return status;
}

bool StorageData::getDouble(double &value, const string &field) {
	bool status = true;
	double dbi_value;

	if (!isSane(1)) return false;

	pthread_mutex_lock(connectionMutex);

#ifdef DEBUG
	unsigned short type;
	if (!getFieldType(type, field)) {
		LMSG("getFieldType() failed for field '%s'", field.c_str());
		abort();
	} else if (type != DBI_TYPE_DECIMAL) {
		LMSG("requested type %d (DBI_TYPE_DECIMAL) != libdbi reported type %d for field '%s' (1 INT, 2 DEC, 3 STR, 4 BIN, 5 DATE)", DBI_TYPE_DECIMAL, type, field.c_str());
		abort();
	}
#endif


	dbi_value = dbi_result_get_double(this->resultSet, field.c_str());
	if (isError()) {
		status = false;
	} else {
		value = dbi_value;
	}

	pthread_mutex_unlock(connectionMutex);

	return status;
}

bool StorageData::getString(string &value, const string &field) {
	bool status = true;
	const char *dbi_value;

	if (!isSane(1)) return false;

	pthread_mutex_lock(connectionMutex);

#ifdef DEBUG
	unsigned short type;
	if (!getFieldType(type, field)) {
		LMSG("getFieldType() failed for field '%s'", field.c_str());
		abort();
	} else if (type != DBI_TYPE_STRING) {
		LMSG("requested type %d (DBI_TYPE_STRING) != libdbi reported type %d for field '%s' (1 INT, 2 DEC, 3 STR, 4 BIN, 5 DATE)", DBI_TYPE_STRING, type, field.c_str());
		abort();
	}
#endif

	dbi_value = dbi_result_get_string(this->resultSet, field.c_str());
	if (isError()) {
		status = false;

	} else {
		if (dbi_value) {
			value = dbi_value;
		} else {
			value.erase();
		}
	}

	pthread_mutex_unlock(connectionMutex);

	return status;
}

bool StorageData::getBinary(string &value, const string &field) {
	bool status;
	const unsigned char *dbi_value;

	if (status = getBinary(dbi_value, field)) {
		if (dbi_value) {
			value = (const char*) dbi_value;
		} else {
			value.erase();
		}
	}
	
	return status;
}

bool StorageData::getBinary(const unsigned char *&value, const string &field) {
	bool status = true;
	const unsigned char *dbi_value;

	if (!isSane(1)) return false;

	pthread_mutex_lock(connectionMutex);

#ifdef DEBUG
	unsigned short type;
	if (!getFieldType(type, field)) {
		LMSG("getFieldType() failed for field '%s'", field.c_str());
		abort();
	} else if (type != DBI_TYPE_BINARY) {
		LMSG("requested type %d (DBI_TYPE_BINARY) != libdbi reported type %d for field '%s' (1 INT, 2 DEC, 3 STR, 4 BIN, 5 DATE)", DBI_TYPE_BINARY, type, field.c_str());
		abort();
	}
#endif

	dbi_value = dbi_result_get_binary(this->resultSet, field.c_str());
	if (isError()) {
		status = false;
	} else {
		value = dbi_value;
	}

	pthread_mutex_unlock(connectionMutex);

	return status;
}

bool StorageData::getStringCopy(string *&value, const string &field) {
	LMSG("DEBUG: StorageData::getStringCopy() not implemented.");
	abort();
}

bool StorageData::getBinaryCopy(unsigned char *&value, const string &field) {
	LMSG("DEBUG: StorageData::getBinaryCopy() not implemented.");
	abort();
}

bool StorageData::getDatetime(string &value, const string &field) {
	bool status;
	char buf[132];
	time_t tmp;

	if (status = getDatetime(tmp, field)) {
		snprintf(buf, 132, "%lu", tmp);
		value = buf;
	}
	
	return status;
}

bool StorageData::getDatetime(time_t &value, const string &field) {
	bool status = true;
	time_t dbi_value = 0;

	if (!isSane(1)) return false;

	pthread_mutex_lock(connectionMutex);

#ifdef DEBUG
	unsigned short type;
	if (!getFieldType(type, field)) {
		LMSG("getFieldType() failed for field '%s'", field.c_str());
		abort();
	} else if (type != DBI_TYPE_DATETIME) {
		LMSG("requested type %d (DBI_TYPE_DATETIME) != libdbi reported type %d for field '%s' (1 INT, 2 DEC, 3 STR, 4 BIN, 5 DATE)", DBI_TYPE_DATETIME, type, field.c_str());
		abort();
	}
#endif

	dbi_value = dbi_result_get_datetime(this->resultSet, field.c_str());
	if (isError()) {
		status = false;
	} else {
		if (dbi_value == 0) {
			LMSG("NOTICE: Please patch your copy of libdbi with the patch located in sella_nms/support.");
		}
		value = dbi_value;
	}

	pthread_mutex_unlock(connectionMutex);

	return status;
}

bool StorageData::getCharIdx(char &value, unsigned int &index) {
	bool status = true;
	char dbi_value;

	if (!isSane(1)) return false;

	pthread_mutex_lock(connectionMutex);

	dbi_value = dbi_result_get_char_idx(this->resultSet, index);
	if (isError()) {
		status = false;
	} else {
		value = dbi_value;
	}

	pthread_mutex_unlock(connectionMutex);

	return status;
}

bool StorageData::getUCharIdx(unsigned char &value, unsigned int &index) {
	bool status = true;
	unsigned char dbi_value;

	if (!isSane(1)) return false;

	pthread_mutex_lock(connectionMutex);

	dbi_value = dbi_result_get_uchar_idx(this->resultSet, index);
	if (isError()) {
		status = false;
	} else {
		value = dbi_value;
	}

	pthread_mutex_unlock(connectionMutex);

	return status;
}

bool StorageData::getShortIdx(short &value, unsigned int &index) {
	bool status = true;
	short dbi_value;

	if (!isSane(1)) return false;

	pthread_mutex_lock(connectionMutex);

	dbi_value = dbi_result_get_short_idx(this->resultSet, index);
	if (isError()) {
		status = false;
	} else {
		value = dbi_value;
	}

	pthread_mutex_unlock(connectionMutex);

	return status;
}

bool StorageData::getUShortIdx(unsigned short &value, unsigned int &index) {
	bool status = true;
	unsigned short dbi_value;

	if (!isSane(1)) return false;

	pthread_mutex_lock(connectionMutex);

	dbi_value = dbi_result_get_ushort_idx(this->resultSet, index);
	if (isError()) {
		status = false;
	} else {
		value = dbi_value;
	}

	pthread_mutex_unlock(connectionMutex);

	return status;
}

bool StorageData::getLongIdx(long &value, unsigned int &index) {
	bool status = true;
	long dbi_value;

	if (!isSane(1)) return false;

	pthread_mutex_lock(connectionMutex);

	dbi_value = dbi_result_get_long_idx(this->resultSet, index);
	if (isError()) {
		status = false;
	} else {
		value = dbi_value;
	}

	pthread_mutex_unlock(connectionMutex);

	return status;
}

bool StorageData::getULongIdx(unsigned long &value, unsigned int &index) {
	bool status = true;
	unsigned long dbi_value;

	if (!isSane(1)) return false;

	pthread_mutex_lock(connectionMutex);

	dbi_value = dbi_result_get_ulong_idx(this->resultSet, index);
	if (isError()) {
		status = false;
	} else {
		value = dbi_value;
	}

	pthread_mutex_unlock(connectionMutex);

	return status;
}

bool StorageData::getLongLongIdx(long long &value, unsigned int &index) {
	bool status = true;
	long long dbi_value;

	if (!isSane(1)) return false;

	pthread_mutex_lock(connectionMutex);

	dbi_value = dbi_result_get_longlong_idx(this->resultSet, index);
	if (isError()) {
		status = false;
	} else {
		value = dbi_value;
	}

	pthread_mutex_unlock(connectionMutex);

	return status;
}

bool StorageData::getULongLongIdx(unsigned long long &value, unsigned int &index) {
	bool status = true;
	unsigned long long dbi_value;

	if (!isSane(1)) return false;

	pthread_mutex_lock(connectionMutex);

	dbi_value = dbi_result_get_ulonglong_idx(this->resultSet, index);
	if (isError()) {
		status = false;
	} else {
		value = dbi_value;
	}

	pthread_mutex_unlock(connectionMutex);

	return status;
}

bool StorageData::getFloatIdx(float &value, unsigned int &index) {
	bool status = true;
	float dbi_value;

	if (!isSane(1)) return false;

	pthread_mutex_lock(connectionMutex);

	dbi_value = dbi_result_get_float_idx(this->resultSet, index);
	if (isError()) {
		status = false;
	} else {
		value = dbi_value;
	}

	pthread_mutex_unlock(connectionMutex);

	return status;
}

bool StorageData::getDoubleIdx(double &value, unsigned int &index) {
	bool status = true;
	double dbi_value;

	if (!isSane(1)) return false;

	pthread_mutex_lock(connectionMutex);

	dbi_value = dbi_result_get_double_idx(this->resultSet, index);
	if (isError()) {
		status = false;
	} else {
		value = dbi_value;
	}

	pthread_mutex_unlock(connectionMutex);

	return status;
}

bool StorageData::getStringIdx(string &value, unsigned int &index) {
	bool status = true;
	const char *dbi_value;

	if (!isSane(1)) return false;

	pthread_mutex_lock(connectionMutex);

	dbi_value = dbi_result_get_string_idx(this->resultSet, index);
	if (isError()) {
		status = false;
	} else {
		value = dbi_value;
	}

	pthread_mutex_unlock(connectionMutex);

	return status;
}

bool StorageData::getBinaryIdx(const unsigned char *&value, unsigned int &index) {
	bool status = true;
	const unsigned char *dbi_value;

	if (!isSane(1)) return false;

	pthread_mutex_lock(connectionMutex);

	dbi_value = dbi_result_get_binary_idx(this->resultSet, index);
	if (isError()) {
		status = false;
	} else {
		value = dbi_value;
	}

	pthread_mutex_unlock(connectionMutex);

	return status;
}

bool StorageData::getStringCopyIdx(string *&value, unsigned int &index) {
	LMSG("DEBUG: StorageData::getStringCopyIdx() not implemented.");
	abort();
}

bool StorageData::getBinaryCopyIdx(unsigned char *&value, unsigned int &index) {
	LMSG("DEBUG: StorageData::getBinaryCopyIdx() not implemented.");
	abort();
}

bool StorageData::getDatetimeIdx(time_t &value, unsigned int &index) {
	bool status = true;
	time_t dbi_value;

	if (!isSane(1)) return false;

	pthread_mutex_lock(connectionMutex);

	dbi_value = dbi_result_get_datetime_idx(this->resultSet, index);
	if (isError()) {
		status = false;
	} else {
		value = dbi_value;
	}

	pthread_mutex_unlock(connectionMutex);

	return status;
}


bool StorageData::empty() const {
	if (this->resultSet == NULL || this->numberRows < 1) {
		return true;
	}

	return false;
}

StorageData const& StorageData::operator=(StorageData const &src) {
	LMSG("DEBUG: StorageData doesn't support operator=(). We can't copy dbi_result.");
	abort();

	return *this;
}

bool StorageData::isSane(bool get) {
	assert(this->resultSet != NULL);
	assert(this->numberRows > 0 || get == 0);
	assert(this->currentRow > 0 || get == 0);

	if (this->resultSet == NULL) {
		return false;
	} else if (get) {
		if (this->numberRows < 1) {
			return false;
		} else if (this->currentRow < 1) {
			return false;
		}
	}

	return true;
}

/*
** Local Variables:
** c-basic-offset: 3
** tab-width: 3
** End:
** vim:
** vim: noet ts=3 sw=3
*/
