#ifndef _CEGODATABASEMANAGER_H_INCLUDED_
#define _CEGODATABASEMANAGER_H_INCLUDED_
///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoDatabaseManager.h
// ---------------------
// Cego database manager
//     
// Design and Implementation by Bjoern Lemke
//
// (C)opyright 2000-2019 Bjoern Lemke
//
// INTERFACE MODULE
//
// Class: CegoDatabaseManager 
// 
// Description: General database manager
//
// Status: CLEAN
//
///////////////////////////////////////////////////////////////////////////////

// LFC INCLUDES
#include <lfcbase/ListT.h>
#include <lfcbase/Chain.h>

// CEGO INCLUDES
#include "CegoBufferPool.h"
#include "CegoDistDbHandler.h"
#include "CegoQueryCache.h"
#include "CegoTableCache.h"
#include "CegoDefs.h"

class CegoDatabaseManager : public CegoBufferPool {
    
 public:

    enum RecoveryMode { REQOFF, OFF, ON};

    enum ObjectUseMode { SHARED, EXCLUSIVE_WRITE };

    CegoDatabaseManager(const Chain& xmlDef, const Chain& lckFileName, const Chain& logFile, const Chain& progName, CegoDbHandler::ProtocolType protType = CegoDbHandler::SERIAL);
    ~CegoDatabaseManager();

    void allocateQueryCache(const Chain& tableSet);
    void allocateTableCache(const Chain& tableSet);
    void releaseQueryCache(const Chain& tableSet);
    void releaseTableCache(const Chain& tableSet);

    CegoQueryCache* getQueryCache(const Chain& tableSet) const;
    CegoQueryCache* getQueryCache(int tabSetId) const;
    CegoTableCache* getTableCache(const Chain& tableSet) const;
    CegoTableCache* getTableCache(int tabSetId) const;

    void cleanCache(int tabSetId, CegoObject::ObjectType objType, const Chain& objName);
    
    void beat();

    void checkTableSetRunState(int tabSetId);
    
    void startRecovery(const Chain& tableSet);

    void startCopy(const Chain& tableSet, 
		   const Chain& targetHost, 
		   const Chain& mediatorHost, 
		   const Chain& user, 
		   const Chain& passwd,
		   const Chain& msg);

    RecoveryMode getRecoveryMode(int tabSetId);
    void setRecoveryMode(int tabSetId, RecoveryMode m);

    void setAllRecoveryOff();

    bool nextRecovery(Chain& tableSet);
    bool nextCopy(int &id, Chain& tableSet, Chain& targetHost, Chain& mediatorHost, Chain& user, Chain& passwd);
    void setCopyStatus(int id, const Chain& msg);

    void addObject(int tabSetId, const Chain& objName, CegoObject::ObjectType type);
    void useObject(int tabSetId, const Chain& objName, CegoObject::ObjectType type, ObjectUseMode mode, unsigned long long tid = 0 );

    void unuseObject(int tabSetId, const Chain& objName, CegoObject::ObjectType type, unsigned long long tid = 0 );
    void removeObject(int tabSetId, const Chain& objName, CegoObject::ObjectType type);
    void removeAllObjects(int tabSetId);
    
    bool objectExists(int tabSetId, const Chain& objName, CegoObject::ObjectType type);
    
    void printObjectList();

    void setThreadInfo(int numDbThread, int numAdmThread, int numLogThread);
    void getThreadInfo(int& numDbThread, int& numAdmThread, int& numLogThread,
		       int& activeDbThread, int& activeAdmThread, int& activeLogThread);
    
    void increaseActiveAdmThread();
    void decreaseActiveAdmThread();

    void increaseActiveDbThread();
    void decreaseActiveDbThread();

    void increaseActiveLogThread();
    void decreaseActiveLogThread();

    void getDBMLockStat(Chain& lockName, int& lockCount, unsigned long long &numRdLock, unsigned long long &numWrLock, unsigned long long &sumRdDelay, unsigned long long &sumWrDelay);

    CegoDistDbHandler* allocateSession(const Chain& hostName, const Chain& tableSet, 
				       const Chain& userName, const Chain& password);
    void releaseSession(CegoDistDbHandler* pSH);
    void cleanSession(int lifetime);
    
    Element* getSessionInfo(int lifetime);
    Element* getCopyInfo();

    void configureLogger();
    void configureLogger(Logger::LogLevel level);
    bool isLoggerConfigured();

    bool verifyJDBC(const Chain& user);
    bool verifyAccess(const int tabSetId, const Chain& objName, CegoObject::ObjectType type, CegoXMLSpace::AccessMode mode, const Chain& user);

    void initLogFiles(const Chain& tableSet, bool overwrite);
    void releaseLogFiles(const Chain& tableSet, bool waitForArchive);

    CegoDbHandler::ProtocolType getProtType() const;
    
private:

    CegoDistDbHandler* createSession(const Chain& hostName, const Chain& tableSet,
				     const Chain& userName, const Chain& password);

    void closeSession(CegoDistDbHandler* pSH);

    void PR();
    void PW();
    void V();

    class ObjectRecord {
	
    public:
	
	ObjectRecord();
	ObjectRecord(const int tabSetId, const Chain& objName, CegoObject::ObjectType type);

	~ObjectRecord();

	const int getTabSetId() const;

	const Chain& getName() const;
	const CegoObject::ObjectType getType() const;

	void incUsed();
	void decUsed();
	int numUsed() const;

	void setMode(ObjectUseMode mode); 
	ObjectUseMode getMode() const;

	void setTid(unsigned long long tid);	
	unsigned long long getTid() const;

	ObjectRecord& operator = ( const ObjectRecord& t);
        bool operator == ( const ObjectRecord& t);
	
	friend ostream& operator << (ostream& s, const ObjectRecord& t)
	{
	    s << "(" << t._objName << "," << t._tabSetId << ")";
	    return s;
	}

    private:

	Chain _objName;
	CegoObject::ObjectType _type;
	int _tabSetId;
	int _numUsed;
	ObjectUseMode _mode;
	unsigned long long _tid;
    };

    class CopyRecord {
	
    public:
	
	CopyRecord();
	CopyRecord(const Chain& tableSet, const Chain& targetHost, const Chain& mediatorHost, const Chain& user, const Chain& passwd, const Chain& msg);
	~CopyRecord();

	int getId() const;
	void setId(int id);

	const Chain& getTableSet() const;
	const Chain& getTargetHost() const;
	const Chain& getMediatorHost() const;
	
	const Chain& getUser() const;
	const Chain& getPasswd() const;
	
	void setMsg(const Chain& msg);
	const Chain& getMsg() const;

	CopyRecord& operator = ( const CopyRecord& cr);
        bool operator == ( const CopyRecord& cr);
	
	friend ostream& operator << (ostream& s, const CopyRecord& cr)
	{
	    s << "(" << cr._tableSet << "," << cr._targetHost << "," << cr._mediatorHost << ","  << cr._user << "," << cr._passwd << ")";
	    return s;
	}

    private:

	int _id;
	Chain _tableSet;
	Chain _targetHost;
	Chain _mediatorHost;

	Chain _user;
	Chain _passwd;	
	Chain _msg;
    };

    class DbSessionRecord {
	
    public:
	
	DbSessionRecord();
	DbSessionRecord(CegoDistDbHandler* pHandler);
	DbSessionRecord(const Chain& hostName, const Chain& tableSet, const Chain& userName, CegoDistDbHandler* pHandler);
	~DbSessionRecord();

	const Chain& getHostName() const;
	const Chain& getTableSet() const;
	const Chain& getUserName() const;

	bool isUsed() const;
	void setUsed(bool isUsed);
	unsigned long long getTSLastUsed();
	void setTSLastUsed(unsigned long long ts);

	CegoDistDbHandler* getDbHandler() const;


	DbSessionRecord& operator = ( const DbSessionRecord& sr);
        bool operator == ( const DbSessionRecord& sr);
	
	friend ostream& operator << (ostream& s, const DbSessionRecord& sr)
	{
	    s << "(" << sr._tableSet << "," << sr._hostName << ")";
	    return s;
	}

    private:

	Chain _hostName;
	Chain _tableSet;
	Chain _userName;
	unsigned long long _lastUsed;
	bool _isUsed;
	CegoDistDbHandler* _pHandler;
    };

    ListT<ObjectRecord> _objList;
    ListT<CopyRecord> _copyList;
    ListT<DbSessionRecord> _dbSessionList;

    RecoveryMode _recoveryMode[TABMNG_MAXTABSET];
    ListT<Chain> _recoveryList;
    
    int _numDbThread;
    int _numAdmThread;
    int _numLogThread;

    int _activeDbThread;
    int _activeAdmThread;
    int _activeLogThread;

    int _nextCopyId;

    unsigned long long _nextBeat;

    CegoDbHandler::ProtocolType _protType;

    Chain _lckFileName;
    bool _logConfigured;

    CegoQueryCache* _pQueryCache[TABMNG_MAXTABSET];
    CegoTableCache* _pTableCache[TABMNG_MAXTABSET];
    
    unsigned long _modId;
};

#endif




