///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoNet.cc
// ----------
// Cego net client interface
//      
// Design and Implementation by Bjoern Lemke
//     
// (C)opyright 2010-2025 Bjoern Lemke
//
// IMPLEMENTATION MODULE
//
// Class: CegoNet
// 
// Description: SQL Client API 
//
// Status: CLEAN
//
///////////////////////////////////////////////////////////////////////////////

// POSIX INCLUDES
#include <locale.h>
#include <stdlib.h>

// CEGO INCLUDES
#include "CegoNet.h"
#include "CegoDefs.h"

// LFC INCLUDES
#include <lfcbase/Net.h>

#define LANGUAGE_ENV "LANG"
#define LOCALE_CATEGORY LC_ALL

extern Chain __dateTimeFormat;
extern char __currencySymbol;
extern char __decimalPoint;
extern char __quoteEscapeFlag;

CegoNet::CegoNet(CegoDbHandler::ProtocolType protType, const Chain& logFile, const Chain& progName, const Chain& logMode)
{
    _protType = protType;
    _logFile = logFile;
    _progName = progName;
    _logMode = logMode;
    _pN = 0;
    _pSH = 0;
    _pModule = 0;
    _isFetchable = false;
    _isValid = true;
    
    // for localization
    char* lang = 0;
    if ( ( lang = getenv(LANGUAGE_ENV) ) != 0)
    {
	if ( setlocale(LOCALE_CATEGORY, lang) == 0)
	{
	    Chain msg = Chain("Cannot set locale ") + Chain(lang);
	    throw Exception(EXLOC, msg);
	}
    }
}

CegoNet::~CegoNet()
{
    if ( _pSH )
	delete _pSH;
    if ( _pN ) 
	delete _pN;
    if ( _pModule )
	delete _pModule;
}

void CegoNet::connect(const Chain& serverName, unsigned port, const Chain& tableSet, const Chain& user, const Chain& pwd, unsigned maxSendLen)
{
    Net n (  NETMNG_MSG_BUFLEN, NETMNG_SIZEBUFLEN, maxSendLen );

    _pN = n.connect(serverName, port);

    if ( _logFile.length() > 1 )
	_pModule = new CegoModule(_logFile, _progName);
    else
	_pModule = new CegoModule;

    int modId = 100;

    if ( _logMode == Chain("notice"))
	_pModule->logModule(modId, "cegonet", Logger::NOTICE);
    else if ( _logMode == Chain("error"))
	_pModule->logModule(modId, "cegonet", Logger::LOGERR);
    else if ( _logMode == Chain("debug"))
	_pModule->logModule(modId, "cegonet", Logger::DEBUG);
    else
	_pModule->logModule(modId, "cegonet", Logger::NONE);

    _pSH = new CegoDbHandler(_pN, _protType, _pModule);

    CegoDbHandler::ResultType res = _pSH->requestSession(tableSet, user, pwd);
    if ( res != CegoDbHandler::DB_OK )
    {
	Chain msg = _pSH->getMsg();
	throw Exception(EXLOC, msg);
    }

    __dateTimeFormat = _pSH->getDateFormat();
    __quoteEscapeFlag = _pSH->getQuoteEscapeFlag();
    
    const struct lconv * const currentlocale = localeconv();

    __currencySymbol = *currentlocale->currency_symbol;
    __decimalPoint = *currentlocale->decimal_point;    
}
   
unsigned long long CegoNet::doQuery(const Chain& query)
{        
    _isFetchable=false;

    CegoDbHandler::ResultType res;
    
    try
    {
	res = _pSH->reqQueryOp(query);
    }
    catch ( Exception e )
    {
	_isValid = false;
	Chain msg = Chain("Fatal protocol error");
	throw Exception(EXLOC, msg);
    }
	
    if ( res == CegoDbHandler::DB_OK )
    {
	Chain msg = _pSH->getMsg();
	return _pSH->getAffected();
    }
    else if ( res == CegoDbHandler::DB_DATA )
    {
	_isFetchable=true;
	return 0;
    }
    else if ( res == CegoDbHandler::DB_FIN )
    {	
	_isFetchable=false;
	    return 0;
    }
    else if ( res == CegoDbHandler::DB_ERROR )
    {
	Chain msg = _pSH->getMsg();
	throw Exception(EXLOC, msg);      
    }
    return 0;
    
}

void CegoNet::putBlob(CegoBlob& blob)
{   
    if ( _pSH->putBlob(blob) != CegoDbHandler::DB_OK)
	throw Exception(EXLOC, Chain("Cannot put blob"));
}

void CegoNet::putClob(CegoClob& clob)
{   
    if ( _pSH->putClob(clob) != CegoDbHandler::DB_OK)
	throw Exception(EXLOC, Chain("Cannot put clob"));
}

void CegoNet::getBlob(CegoBlob& blob)
{   
    if ( _pSH->getBlob(blob) != CegoDbHandler::DB_OK)
	throw Exception(EXLOC, Chain("Cannot get blob"));
}

void CegoNet::getClob(CegoClob& clob)
{   
    if ( _pSH->getClob(clob) != CegoDbHandler::DB_OK)
	throw Exception(EXLOC, Chain("Cannot get clob"));
}

void CegoNet::deleteBlob(CegoBlob& blob)
{   
    if ( _pSH->delBlob(blob) != CegoDbHandler::DB_OK)
	throw Exception(EXLOC, Chain("Cannot delete blob"));
}

void CegoNet::deleteClob(CegoClob& clob)
{   
    if ( _pSH->delClob(clob) != CegoDbHandler::DB_OK)
	throw Exception(EXLOC, Chain("Cannot delete clob"));
}

bool CegoNet::fetchData(const ListT<CegoField>& schema, ListT<CegoFieldValue>& fvl)
{
    if ( _isFetchable == true )
    {
	CegoDbHandler::ResultType res;

	res = _pSH->receiveTableData(schema, fvl);
	
	if ( res == CegoDbHandler::DB_DATA )
	{
	    _isFetchable = true;
	}
	else
	{
	    _isFetchable = false;
	}
    }
    return _isFetchable;
}

bool CegoNet::isFetchable()
{        
    return _isFetchable;
}

bool CegoNet::isValid()
{        
    return _isValid;
}

void CegoNet::abortQuery()
{        
    _pSH->abortQuery();
}

void CegoNet::resetQuery()
{        
    _pSH->resetQuery();
}

bool CegoNet::wasReset()
{        
    return _pSH->wasReset();
}

unsigned long long CegoNet::getTid() const
{
    return _pSH->getTid();
}

const Chain& CegoNet::getDbName() const
{
    return _pSH->getDbName();
}

const Chain& CegoNet::getDbVersion() const
{
    return _pSH->getDbVersion();
}

void CegoNet::reqAbortQuery(unsigned long long tid)
{
    _pSH->reqQueryAbort(tid);	    	    
}

const Chain& CegoNet::getMsg()
{
    return _pSH->getMsg();
}

long CegoNet::getAffected()
{
    return _pSH->getAffected();
}

void CegoNet::getSchema(ListT<CegoField>& schema)
{
    schema = _pSH->getSchema();
}

void CegoNet::getFormat(Chain& format)
{
    format = _pSH->getFormat();
}

void CegoNet::getProcResult(ListT<CegoProcVar>& outParamList, CegoFieldValue& retValue)
{
    _pSH->getProcResult(outParamList, retValue);
}
   
void CegoNet::disconnect()
{
    if ( _isValid )
	_pSH->closeSession();
}
