/***********************************************************************************************************************
//	New qmgr do compression to blob so we dont have to.
************************************************************************************************************************/

#if !defined(__DATACACHE__)
#define __DATACACHE__

#if defined(__DB_OFFLINE__)
	#include "structifx.hpp"
	#include "normbase.hpp"
#else
	#include <StructIfx/structifx.hpp>
	#include <shlu2/BasicUtils/normbase.hpp>
#endif
#include <vector>
#include <map>

#include <iostream>

//constexpr const char * SIDFIELDDELIMIT = "-";
// -- universal data id structure
//struct TDataKey
//{
//    std::string signature;
//	std::string service_name;
//    std::string data_name;
//    
//    TDataKey(void): signature(k_strEmptyString), service_name(k_strEmptyString), data_name(k_strEmptyString) {};
//    
//    
//	TDataKey(const std::string &sig, const std::string &svc, const std::string &dname=k_strEmptyString):
//		signature(sig), service_name(svc), data_name(dname) {};
//    
//	virtual ~TDataKey(void){};
//	virtual int ParseHandle(const std::string &handle) = 0;	//for future expansion, override this. return number of fields handled
//	
//	void MakeHandle(std::string &handle) const;
//	virtual std::string MakeHandle(void) const = 0;
//	
//	operator std::string (void) const;
//};

class CDataCache
{
public:
    
	static constexpr const size_t BUFFSIZE = 20971520;	//exactly 20MB
	
	enum ECacheError
	{
		eDataOk = 0,
		eInvalidKey,
		eNoData,
        eOutOfBoundary,
        eMemoryError,
        eDataProcessing,
		eModeError,
		eProcessError,	//compress/decompress
        eFailToObtainStorage,
		eFailToStoreData,	// -- fail to transfer blobs to server
        eAbusive,
		eUnknown,
		eCacheErrorStop
	};


	enum ECacheMode
	{
		eRead = 0,
		eWrite = 2
	};

	virtual ~CDataCache(void);
	
	//void Reset(const std::string &handle, int mode = eRead, unsigned int usrip = 0);
	//void Reset(unsigned int usrip = 0, const std::string & svcname = k_strEmptyString);
	
	// -- save current block and reset block for new data
    int Flush(std::string &key);
	int Load(const std::string &key);
	
	void PushData(const void* pData, size_t ulSize);
	void ReadData(void* pData, size_t ulSize);
	
	void PushString(const std::string &rStr);
	void ReadString(std::string& rStr);
	
	void PushCString(const char *pStr);
	char* ReadCString(void);    //caller need to delte the cstring afterwards
    
    
    template<typename T>
    int WriteToBuffer(const T &data);
    
    template<typename T>
    int ReadFromBuffer(const T &data);
    
    template<typename T>
    int CacheData(const T& data, std::string &key);
    
    template<typename T>
    int RetrieveData(const std::string &key, T& data);
    
    
    //virtual std::string GetHandle(void) const = 0;
    
    void ResetData(void);
    void ShrinkMem(void);   //release extra memory
    void ShiftData(void);   //shift off already read data to save memory when load subsequential data.

	/*********** for convenience and abstraction *****************/
	static const char * MsgString(int errCode);
protected:
    
    //CDataCache(void) = default;
	CDataCache();	//default write mode
    
    CDataCache(const CDataCache& src) = delete;
	const CDataCache & operator = (const CDataCache& src) = delete;
    
    char * x_Acquire(size_t n_bytes);
    
	//int m_iMode;
	char *m_pBuf;
	size_t m_ulDataEnd;  //available (to read) bytes in buf
	size_t m_ulReadPos;	//current position -- data pointer
    
    size_t m_TotalCapacity;
    
    
    char * x_CompressData(size_t &n, int &status) const;
    int x_DeCompressData(const std::string &data);

    
    // -- key: in and out.
	virtual int x_SaveBlock(const char *src, size_t n, std::string &key) const = 0;
	virtual int x_RetrieveBlock(const std::string &key, std::string &data) const = 0;
	
	static const char * m_dimStatusLits[eCacheErrorStop];	
};

class Cacheable
{
public:
    virtual ~Cacheable(void) {};
    virtual void SaveToCache(CDataCache &dc) const = 0;
    virtual void RestoreFromCache(CDataCache &dc) = 0;
};

#include "impl/datacache_impl.hpp"

#endif
