#ifndef _CEGODBTHREAD_H_INCLUDED_
#define _CEGODBTHREAD_H_INCLUDED_
///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoDbThread.h  
// --------------
// Cego db thread class definition
//                                                        
// Design and Implementation by Bjoern Lemke
//
// (C)opyright 2000-2025 Bjoern Lemke
//
// INTERFACE MODULE
//
// Class: CegoDbThread
// 
// Description: This class implements the functions of a single database thread.
//              It serves a database session dispatched from the database thread pool
//              and handles subsequent requests for this session.
//              Database requests can be request from a native client but also distributed
//              requests from a different cego database node.
//
// Status: CLEAN
//
///////////////////////////////////////////////////////////////////////////////

// LFC INCLUDES
#include <lfcbase/ListT.h>
#include <lfcbase/Thread.h>
#include <lfcbase/NetHandler.h>
#include <lfcbase/NanoTimer.h>

// CEGO INCLUDES
#include "CegoDbHandler.h"
#include "CegoDatabaseManager.h"
#include "CegoQueryManager.h"
#include "CegoAction.h"

class CegoDbThreadPool;

class CegoDbThread : public Thread {
    
public:

    class QueryEntry {
	
    public:
       
	QueryEntry() {}
	QueryEntry(unsigned idx, unsigned long qid, unsigned long long ts, const Chain& query, unsigned long long cost)
	{
	    _idx = idx;
	    _qid = qid;
	    _ts = ts;
	    _query = query;
	    _cost = cost;
	    _order = LAST;
	}
	
	QueryEntry& operator = ( const QueryEntry& qe )
	{
	    _idx = qe._idx;
	    _qid = qe._qid;
	    _ts = qe._ts;
	    _query = qe._query;
	    _cost = qe._cost;
	    _order = qe._order;
	    return (*this);
	}

	void setLastOrder()
	{
	    _order = LAST;
	}

	void setRevLastOrder()
	{
	    _order = REVLAST;
	}

	void setCostOrder()
	{
	    _order = COST;
	}

	void setRevCostOrder()
	{
	    _order = REVCOST;
	}

	bool operator == ( const QueryEntry& qe) const
	{
	    if ( _idx == qe._idx && _qid == qe._qid )
		return true;
	    return false;
	}
	
	bool operator < ( const QueryEntry& qe) const
	{
	    if ( _order == LAST )
	    {
		if ( _ts < qe._ts )
		    return true;
		else if ( _ts == qe._ts && _idx < qe._idx )
		    return true;
		else if ( _ts == qe._ts && _idx == qe._idx && _qid < qe._qid)
		    return true;
		return false;
	    }
	    if ( _order == REVLAST )
	    {
		if ( _ts > qe._ts )
		    return true;
		else if ( _ts == qe._ts && _idx > qe._idx )
		    return true;
		else if ( _ts == qe._ts && _idx == qe._idx && _qid > qe._qid)
		    return true;
		return false;
	    }
	    else if ( _order == COST )
	    {
		if ( _cost < qe._cost )
		    return true;
		else if ( _cost == qe._cost && _idx < qe._idx )
		    return true;
		else if ( _cost == qe._cost && _idx == qe._idx && _qid < qe._qid)
		    return true;
		return false;
	    }
	    else if ( _order == REVCOST )
	    {
		if ( _cost > qe._cost )
		    return true;
		else if ( _cost == qe._cost && _idx > qe._idx )
		    return true;
		else if ( _cost == qe._cost && _idx == qe._idx && _qid > qe._qid)
		    return true;
		return false;
	    }

	    return false;
	}
	
	bool operator > ( const QueryEntry& qe) const
	{
	    if ( _order == LAST )
	    {
		if ( _ts > qe._ts )
		    return true;
		else if ( _ts == qe._ts && _idx > qe._idx )
		    return true;
		else if ( _ts == qe._ts && _idx == qe._idx && _qid > qe._qid)
		    return true;
		return false;
	    }
	    else if ( _order == REVLAST )
	    {
		if ( _ts < qe._ts )
		    return true;
		else if ( _ts == qe._ts && _idx < qe._idx )
		    return true;
		else if ( _ts == qe._ts && _idx == qe._idx && _qid < qe._qid)
		    return true;
		return false;
	    }	    
	    else if ( _order == COST )
	    {
		if ( _cost > qe._cost )
		    return true;
		else if ( _cost == qe._cost && _idx > qe._idx )
		    return true;
		else if ( _cost == qe._cost && _idx == qe._idx && _qid > qe._qid)
		    return true;
		return false;
	    }
	    else if ( _order == REVCOST )
	    {
		if ( _cost < qe._cost )
		    return true;
		else if ( _cost == qe._cost && _idx < qe._idx )
		    return true;
		else if ( _cost == qe._cost && _idx == qe._idx && _qid < qe._qid)
		    return true;
		return false;
	    }

	    return false;
	}

	unsigned long long getIndex()
	{
	    return _idx;
	}

	unsigned long long getTimestamp()
	{
	    return _ts;
	}
	
	const Chain& getQuery()
	{
	    return _query;
	}

	unsigned long long getCost()
	{
	    return _cost;
	}
	
    private:

	enum QueryOrder { LAST, REVLAST, COST, REVCOST };
	
	unsigned _idx;
	unsigned long long _qid;
	unsigned long long _ts;
	Chain _query;
	unsigned long long _cost;

	QueryOrder _order;
    };
    
    CegoDbThread();
    CegoDbThread(CegoDbThreadPool *pPool, CegoDatabaseManager *pDBMng, CegoDbHandler::ProtocolType protType);
    ~CegoDbThread();

    ListT<QueryEntry> getLastQuery() const;
    ListT<QueryEntry> getCostQuery() const;

    Chain lastAction() const;
    unsigned long long allocatedSortArea() const;
    void* job(void* arg);

    bool isTerminated();

    void abortSession();

    void loadObjects(unsigned tabSetId);
    void unloadObjects(unsigned tabSetId);
    void invalidateObject(unsigned tabSetId, const Chain& objName, CegoObject::ObjectType type);
    void addReloadRequest(unsigned tabSetId);
    void checkReloadRequest();

    unsigned getErrorCode() const;
    
private:

    unsigned long long _idx;

    CegoDbHandler::ProtocolType _protType;

    void serveSession(CegoDbHandler *pSH);
    bool serveRequest(CegoDbHandler *pSH, CegoDbHandler::RequestType reqType);
    void addHistory(unsigned long long ts, const Chain& queryString, unsigned long long cost);

    void P() const;
    void V() const;
    
    CegoDbThreadPool* _pPool;
    CegoDatabaseManager* _pDBMng;
    
    CegoQueryManager* _pTabMng;
    CegoAction* _pPA;

    NetHandler* _pRequest;

    ListT<QueryEntry> _queryList;
    TreeT<QueryEntry> _costTree;
    
    unsigned long long _qid;
    
    ListT<unsigned> _loadList;

    unsigned _errorCode;

    NanoTimer* _pTim;
    NanoTimer* _pCost;

    unsigned _numLast;
    unsigned _numCost;

    Chain _lastAction;
    unsigned long _modId;
};
#endif
