#ifndef _CEGOBTREEMANAGER_H_INCLUDED_
#define _CEGOBTREEMANAGER_H_INCLUDED_
///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoBTreeManager.h
// ------------------
// Cego BTree+ manager class definition
//                                                         
// Design and Implementation by Bjoern Lemke               
//     
// (C)opyright 2000-2019 Bjoern Lemke
//
// INTERFACE MODULE
//
// Class: CegoBTreeManager
// 
// Description: This class implements the btree algorithm to be used for table index objects.
//
// Status: CLEAN
//
///////////////////////////////////////////////////////////////////////////////

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

// CEGO INCLUDES
#include "CegoDefs.h"
#include "CegoDataType.h"
#include "CegoField.h"
#include "CegoDataPointer.h"
#include "CegoSystemObject.h"
#include "CegoObjectManager.h"
#include "CegoBTreeNode.h"
#include "CegoBTreeValue.h"

class CegoBTreeManager {

public:
    
    CegoBTreeManager(CegoObjectManager* pObjMng, CegoBTreeObject *pBTO);
    ~CegoBTreeManager();

    void createCache();

    void commit(CegoDataPointer& sysEntry);
    void rollback();
    
    void insertBTreeWithCommit(const CegoDataPointer& dp,
		     const CegoBTreeValue &iv,
		     unsigned long long tid);
    
    void deleteBTree(const CegoBTreeValue &iv,
		     const CegoDataPointer& dp,
		     unsigned long long tid);

    void insertBTree(const CegoDataPointer& dp, 
		      const CegoBTreeValue &iv,
		      unsigned long long tid);

    void deleteBTree(const CegoDataPointer& sysEntry, 
		     const CegoBTreeValue &iv,
		     const CegoDataPointer& dp,
		     unsigned long long tid);

    bool verifyBTree();

    void dumpBTree();

    int getNumPages();
    int freeBTree();

    int traceBTree();
	
private:

    class BTreeCache {
	
    public:
	
	BTreeCache();
	~BTreeCache();

	CegoBufferPage* newCachePage(CegoBufferPage& bp, const CegoBufferPage::PageType pageType, bool copyPage);
	CegoBufferPage* getCachePage(PageIdType pageId);

	CegoBufferPage* getFirst();
	CegoBufferPage* getNext();
	
    private:

	class CacheEntry {

	public:

	    CacheEntry()
	    {
	    }

	    
	    CacheEntry(PageIdType pageId)
	    {
		_pageId = pageId;
	    }
	    
	    CacheEntry(CegoBufferPage* pBP)
	    {
		_pBP = pBP;
		_pageId = pBP->getPageId();
	    }
	    	    
	    ~CacheEntry()
	    {
	    }

	    CegoBufferPage* getPage() const
	    {
		return _pBP;
	    }
	    
	    void setPage(CegoBufferPage* pBP)
	    {
		_pBP = pBP;
		_pageId = pBP->getPageId();
	    }
	    
	    CacheEntry& operator = ( const CacheEntry& e)
	    {
		_pBP = e._pBP;
		_pageId = e._pageId;
		return (*this);
	    }

	    bool operator == ( const CacheEntry& e)
	    {
		if ( _pageId == e._pageId )
		    return true;
		return false;
	    }

	    bool operator < ( const CacheEntry& e)
	    {
		if ( _pageId < e._pageId )
		    return true;		
		return false;
	    }

	    bool operator > ( const CacheEntry& e)
	    {
		if ( _pageId > e._pageId )
		    return true;
		return false;
	    }
	    
	    friend ostream& operator << (ostream& s, const CacheEntry& e)
	    {
		s << "(" << e._pageId << ")";
		return s;
	    }
	    
	private:

	    PageIdType _pageId;
	    CegoBufferPage* _pBP;
	    
	};

	AVLTreeT<CacheEntry> _cache;
    };


    bool checkDuplicate(const CegoBTreeValue &iv, const CegoBTreeNode &leaf, unsigned long long tid);
    
			
    CegoBufferPage* allocPage(CegoBufferPage::PageType type);
    CegoBufferPage* getPage(PageIdType pageId);
    void putPage(CegoBufferPage* pBP);
    
    bool verifyNode(PageIdType pageId);
    void dumpNode(int level, PageIdType pageId);
    
    int countNodePages(PageIdType pageId, PageIdType& firstLeafPageId, bool& isFirst);
    int countLeafPages(PageIdType firstLeafPageId);
    
    int freeNodePages(PageIdType pageId, PageIdType& firstLeafPageId, bool& isFirst);
    int freeLeafPages(PageIdType firstLeafPageId);

    int traceNodePages(PageIdType pageId, PageIdType& firstLeafPageId, bool& isFirst);
    int traceLeafPages(PageIdType firstLeafPageId);

    CegoBTreeObject* _pBTO;
    CegoObjectManager* _pObjMng;
    CegoDatabaseManager* _pDBMng;
    
    CegoObject::ObjectType _btreeType;
    ListT<CegoField> _btreeSchema;
    Chain _btreeName;
    int _keyLen;
    int _tabSetId;

    // CegoBufferPage _rootBP;
    // bool _rootFixed;

    BTreeCache* _pCache;
    
    unsigned long _modId;
};

#endif
