#include <WSCdb.h>
#include <WSCdbDrv.h>
#include <WSCvdb.h>

#ifndef FACTORY_METHOD
#include <WSCdbPgsql.h>
#include <WSCdbOdbc.h>
#include <WSCdbMysql.h>
#else
#include <WSDexternal.h>
#endif

WSCindexData* _lib_name_list = NULL;
void libname_init()
{
#ifdef FACTORY_METHOD
	_lib_name_list = new WSCindexData();
#ifndef MSW
	_lib_name_list->setData("ODBC",(void*)"libwsodbc.so");
	_lib_name_list->setData("PGSQL",(void*)"libwspostgres.so");
	_lib_name_list->setData("MYSQL",(void*)"libwsmysql.so");
#else //MSW
	_lib_name_list->setData("ODBC",(void*)ODBCLIBNAME);
	_lib_name_list->setData("PGSQL",(void*)PGLIBNAME);
	_lib_name_list->setData("MYSQL",(void*)MYSQLLIBNAME);
#endif //MSW
#endif // FACTORY_METHOD
}

WSCdbDatabase::WSCdbDatabase()
{
	if (_lib_name_list == NULL){
		libname_init();
	}
	_db = NULL;
        _err_msg = NULL;
	memset(_driver, '\0', sizeof(_driver));
	_rscount = 0;
	_rs = NULL;
}
WSCdbDatabase::~WSCdbDatabase()
{
	if (_err_msg != NULL){
		delete _err_msg;
		_err_msg = NULL;
	}
	close();
}
long WSCdbDatabase::setDatabase(const char* drvName)
{
	if(drvName == NULL) {
		return WS_ERR;
	}
	strcpy(_driver, (char*)drvName);
	return WS_NO_ERR;
}
#ifdef FACTORY_METHOD
WSCindexData* WSCdbDatabase::_factory_list = NULL;
void WSCdbDatabase::setCreateHandler(void* hd,char* drvname){
	if (_factory_list == NULL){
		_factory_list = new WSCindexData();
	}
	_factory_list->setData(drvname,hd);
}

WSCindexData* WSCdbRecord::_record_factory_list = NULL;
void WSCdbRecord::setCreateHandler(void* hd,char* drvname){
	if (_record_factory_list == NULL){
		_record_factory_list = new WSCindexData();
	}
	_record_factory_list->setData(drvname,hd);
}
#endif // FACTORY_METHOD

long WSCdbDatabase::open(char* host, char* uid, char* pwd, char* dbname, char* port)
{
	long ret = WS_ERR;
	close();

#ifdef FACTORY_METHOD /* factory method handler..*/
//printf("WSCdbDatabase::open here1\n");
	if (_factory_list == NULL){
		_factory_list = new WSCindexData();
	}
        WSCdbDrvDatabase* (*hd)() =
		(WSCdbDrvDatabase* (*)())(*_factory_list)[_driver];
	if (hd == NULL){
		if (_lib_name_list == NULL){
			libname_init();
		}
		char* libname = (char*)(*_lib_name_list)[_driver];
//printf("WSCdbDatabase::open lib=%s\n",libname);
		if (libname == NULL){
//printf("WSCdbDatabase::open ret1\n");
                        if (_err_msg != NULL){
                          delete _err_msg;
                          _err_msg = NULL;
                        }
                        WSCstring tmp;
                        tmp << "Driver: " << _driver << " not fund.";
                        _err_msg = WSGFstrdup((char*)tmp);
                        return WS_ERR;
		}
		WSDexternal* ext = WSDexternal::getNewInstance();
		long ret = ext->open(libname);
		if (ret != WS_NO_ERR){
//printf("WSCdbDatabase::open ret2 lib=%s\n",libname);
			delete ext;
                        if (_err_msg != NULL){
                          delete _err_msg;
                          _err_msg = NULL;
                        }
                        WSCstring tmp;
                        tmp << "library: " << libname << " not fund.";
                        _err_msg = WSGFstrdup((char*)tmp);
			return WS_ERR;
		}
        	hd = (WSCdbDrvDatabase* (*)())(*_factory_list)[_driver];
//printf("WSCdbDatabase::open hd=0x%x driver=%s\n",hd,_driver);
		if (hd == NULL){
//printf("WSCdbDatabase::open ret3\n");
                        delete ext;
                        if (_err_msg != NULL){
                          delete _err_msg;
                          _err_msg = NULL;
                        }
                        WSCstring tmp;
                        tmp << "library: " << libname << " invalid library.";
                        _err_msg = WSGFstrdup((char*)tmp);
			return WS_ERR;
		}
	}
	_db = hd();
	if (_db == NULL){
//printf("WSCdbDatabase::open ret4\n");
		return WS_ERR;
	}
#else /* factory method handler..*/
	if(WSGFstricmp((char*)_driver, "PGSQL") == 0) {
		_db = new WSCdbPgsqlDatabase();
	} else 
	if(WSGFstricmp((char*)_driver, "MYSQL") == 0) {
		_db = new WSCdbMysqlDatabase();
	} else 
	if(WSGFstricmp((char*)_driver, "ODBC") == 0) {
		_db = new WSCdbOdbcDatabase();
	} else {
		return WS_ERR;
	}
#endif /* factory method handler..*/

	if(_db) {
		ret = _db->open(host, uid, pwd, dbname, port);
	}
	return ret;
}
long WSCdbDatabase::close()
{
	long ret = WS_ERR;
	WSCdbRecord* rs;
	if(_rs != NULL) {
		for(int i = 0; i < _rscount; i++) {
			if(_rs[i] != (WSCulong)NULL) {
				rs = (WSCdbRecord*)_rs[i];
				rs->close();
			}
		}
		delete[] _rs;
		_rs = NULL;
	}
	_rscount = 0;
	if(_db) {
		ret = _db->close();
		delete _db;
		_db = NULL;
	}
	return ret;
}
long WSCdbDatabase::beginTran()
{
	long ret = WS_ERR;
	if(_db) {
		ret = _db->beginTran();
	}
	return ret;
}
long WSCdbDatabase::commitTran()
{
	long ret = WS_ERR;
	if(_db) {
		ret = _db->commitTran();
	}
	return ret;
}
long WSCdbDatabase::abortTran()
{
	long ret = WS_ERR;
	if(_db) {
		ret = _db->abortTran();
	}
	return ret;
}
long WSCdbDatabase::sqlExecute(const char* stmt)
{
	long ret = WS_ERR;
	if(_db) {
		ret = _db->sqlExecute(stmt);
	}
	return ret;
}
WSCbool WSCdbDatabase::isOpen()
{
	if(_db) {
		return _db->isOpen();
	}
	return False;
}
void WSCdbDatabase::getErrorMsg(char* szState, char* szMsg)
{
	if(_db) {
		_db->getErrorMsg(szState, szMsg);
	}else{
           strcpy(szState,"");
           if (_err_msg != NULL){
             strcpy(szMsg,_err_msg);
           }else{
             strcpy(szMsg,"None.");
           }
        }
}

void WSCdbDatabase::getErrorMsg(char* szMsg,long size)
{
	if(_db) {
		_db->getErrorMsg(szMsg, size);
	}else{
           if (_err_msg != NULL){
             strncpy(szMsg,_err_msg,size -1);
             szMsg[size-1] = 0;
           }else{
             strncpy(szMsg,"None.",size -1);
             szMsg[size-1] = 0;
           }
        }
}

char* WSCdbDatabase::getDriverName()
{
	return _driver;
}
void WSCdbDatabase::addRecord(WSCdbRecord* pDb)
{
	for(int i = 0; i < _rscount; i++) {
		if(_rs[i] == (WSCulong)NULL) {
			_rs[i] = (WSCulong)pDb;
			return;
		}
	}
	_rscount++;
	WSCulong* p = new WSCulong[_rscount];
	if(_rscount > 1) {
		memcpy(p, _rs, sizeof(WSCulong*) * (_rscount-1));
		delete[] _rs;
	}
	p[_rscount-1] = (WSCulong)pDb;
	_rs = p;
}
void WSCdbDatabase::removeRecord(WSCdbRecord* pDb)
{
	if(_rs == NULL) {
		return;
	}
	for(int i = 0; i < _rscount; i++) {
		if(_rs[i] == (WSCulong)pDb) {
			_rs[i] = (WSCulong)NULL;
			return;
		}
	}
}
void WSCdbDatabase::setEncode(long code)
{
	if(_db) {
		_db->setEncode(code);
	}
}
long WSCdbDatabase::getEncode()
{
	if(_db) {
		return _db->getEncode();
	}
	return -1;
}

/////
WSCdbRecord::WSCdbRecord(WSCdbDatabase* pDatabase)
{
	if (_lib_name_list == NULL){
		libname_init();
	}
	Cleanup(pDatabase);
}
WSCdbRecord::WSCdbRecord(WSCvdb* inst)
{
	Cleanup(inst->getDBDatabase());
}

void WSCdbRecord::Cleanup(WSCdbDatabase* pDatabase)
{
	_pDB = pDatabase;
	_rs = NULL;
}

WSCdbRecord::~WSCdbRecord()
{
	if(_rs) {
		_rs->close();
		delete _rs;
	}
	_rs = NULL;
	if(_pDB) {
		_pDB->removeRecord(this);
	}
	_pDB = NULL;
}
long WSCdbRecord::open(const char* stmt)
{
	return open(stmt, WSCDB_SQL_CURSOR_STATIC, WSCDB_SQL_CONCUR_LOCK);
}
long WSCdbRecord::open(const char* stmt, short eCousor, short eAccess)
{
	long ret = WS_ERR;
	close();

#ifdef FACTORY_METHOD /* factory method handler..*/
    WSCdbDrvRecord* (*hd)(WSCdbDrvDatabase*) =
            (WSCdbDrvRecord* (*)(WSCdbDrvDatabase*))(*_record_factory_list)[_pDB->_driver];
    if (hd == NULL){
        char* libname = (char*)(*_lib_name_list)[_pDB->_driver];
        if (libname == NULL){
            return WS_ERR;
        }
        WSDexternal* ext = WSDexternal::getNewInstance();
        long ret = ext->open(libname);
        if (ret != WS_NO_ERR){
            delete ext;
            return WS_ERR;
        }
        hd = (WSCdbDrvRecord* (*)(WSCdbDrvDatabase*))(*_record_factory_list)[_pDB->_driver];
        if (hd == NULL){
            delete ext;
            return WS_ERR;
        }
    }
    _rs = hd(_pDB->_db);
    if (_rs == NULL){
        return WS_ERR;
    }
#else /* factory method handler..*/
	if(WSGFstricmp(_pDB->_driver, "PGSQL") == 0) {
		_rs = new WSCdbPgsqlRecord((WSCdbPgsqlDatabase*)_pDB->_db);
	} else 
	if(WSGFstricmp(_pDB->getDriverName(), "MYSQL") == 0) {
		_rs = new WSCdbMysqlRecord((WSCdbMysqlDatabase*)_pDB->_db);
	} else 
	if(WSGFstricmp(_pDB->getDriverName(), "ODBC") == 0) {
		_rs = new WSCdbOdbcRecord((WSCdbOdbcDatabase*)_pDB->_db);
	} else {
		return ret;
	}
#endif /* factory method handler..*/
	if(_rs) {
		_pDB->addRecord(this);
		ret = _rs->open(stmt, eCousor, eAccess);
	}
	return ret;
}
long WSCdbRecord::close()
{
	long ret = WS_ERR;
	if(_rs) {
		ret = _rs->close();
		delete _rs;
		_rs = NULL;
	}
	return ret;
}
WSCbool WSCdbRecord::isEOF()
{
	if(_rs) {
		return _rs->isEOF();
	}
	return False;
}
WSCbool WSCdbRecord::isOpen()
{
	if(_rs) {
		return _rs->isOpen();
	}
	return False;
}
long WSCdbRecord::getColValue(long index, WSCvariant* var)
{
	long ret = WS_ERR;
	if(_rs) {
		ret = _rs->getColValue(index, var);
	}
	return ret;
}
long WSCdbRecord::getColValue(const char* name, WSCvariant* var)
{
	long ret = WS_ERR;
	if(_rs) {
		ret = _rs->getColValue(name, var);
	}
	return ret;
}
long WSCdbRecord::getColStringValue(long index, char* var)
{
	long ret = WS_ERR;
	if(_rs) {
		ret = _rs->getColStringValue(index, var);
	}
	return ret;
}
long WSCdbRecord::getColStringValue(const char* name, char* var)
{
	long ret = WS_ERR;
	if(_rs) {
		ret = _rs->getColStringValue(name, var);
	}
	return ret;
}
long WSCdbRecord::setColValue(long index, WSCvariant var)
{
	long ret = WS_ERR;
	if(_rs) {
		ret = _rs->setColValue(index, var);
	}
	return ret;
}
long WSCdbRecord::setColValue(const char* name, WSCvariant var)
{
	long ret = WS_ERR;
	if(_rs) {
		ret = _rs->setColValue(name, var);
	}
	return ret;
}
long WSCdbRecord::edit()
{
	long ret = WS_ERR;
	if(_rs) {
		ret = _rs->edit();
	}
	return ret;
}
long WSCdbRecord::addnew()
{
	long ret = WS_ERR;
	if(_rs) {
		ret = _rs->addnew();
	}
	return ret;
}
long WSCdbRecord::update()
{
	long ret = WS_ERR;
	if(_rs) {
		ret = _rs->update();
	}
	return ret;
}
long WSCdbRecord::deleterow()
{
	long ret = WS_ERR;
	if(_rs) {
		ret = _rs->deleterow();
	}
	return ret;
}
long WSCdbRecord::moveNext()
{
	long ret = WS_ERR;
	if(_rs) {
		ret = _rs->moveNext();
	}
	return ret;
}
long WSCdbRecord::movePrevious()
{
	long ret = WS_ERR;
	if(_rs) {
		ret = _rs->movePrevious();
	}
	return ret;
}
long WSCdbRecord::moveFirst()
{
	long ret = WS_ERR;
	if(_rs) {
		ret = _rs->moveFirst();
	}
	return ret;
}
long WSCdbRecord::moveLast()
{
	long ret = WS_ERR;
	if(_rs) {
		ret = _rs->moveLast();
	}
	return ret;
}
long WSCdbRecord::getColName(long index, char* name)
{
	long ret = WS_ERR;
	if(_rs) {
		ret = _rs->getColName(index, name);
	}
	return ret;
}
long WSCdbRecord::getColIndex(const char* name)
{
	long ret = WS_ERR;
	if(_rs) {
		ret = _rs->getColIndex(name);
	}
	return ret;
}
long WSCdbRecord::getColType(long index)
{
	long ret = WS_ERR;
	if(_rs) {
		ret = _rs->getColType(index);
	}
	return ret;
}
long WSCdbRecord::getColType(const char* name)
{
	long ret = WS_ERR;
	if(_rs) {
		ret = _rs->getColType(name);
	}
	return ret;
}
long WSCdbRecord::getColLength(long index)
{
	long ret = WS_ERR;
	if(_rs) {
		ret = _rs->getColLength(index);
	}
	return ret;
}
long WSCdbRecord::getColLength(const char* name)
{
	long ret = WS_ERR;
	if(_rs) {
		ret = _rs->getColLength(name);
	}
	return ret;
}

long WSCdbRecord::getRowCount()
{
	long ret = 0;
	if(_rs) {
		ret = _rs->getRowCount();
	}
	return ret;
}
long WSCdbRecord::getColCount()
{
	long ret = 0;
	if(_rs) {
		ret = _rs->getColCount();
	}
	return ret;
}
void WSCdbRecord::getErrorMsg(char* szState, char* szMsg)
{
	if(_rs) {
		_rs->getErrorMsg(szState, szMsg);
	}
}
WSCstring WSCdbRecord::getErrorMessage()
{
	WSCstring str;
	if(_rs) {
		str = _rs->getErrorMessage();
	}
	return str;
}
