#if !defined(_POLISTORAGE_H_)
#define _POLISTORAGE_H_

#include "PoliType.h"

class CFileStorage : public PoliStorage
{
public:
	CFileStorage() : m_fn(NULL), m_bRead(false){}
	explicit CFileStorage(const char* fname, bool bIsRead) {attach_(fname, bIsRead);}
	~CFileStorage() {detach_();}

	virtual size_t read_(void* pOutBuff, const size_t OutBuffSize)
	{
		if (m_fn)
			return fread(pOutBuff, 1, OutBuffSize, m_fn);
			
		return 0;
	}
	virtual size_t write_(const void* pDataBuff, const size_t DataBuffSize)
	{
		if (m_fn)
			return fwrite(pDataBuff, 1, DataBuffSize, m_fn);
		
		return 0;
		
	}

	
	bool attach_(const char* fname, bool bIsRead)
	{
		m_bRead = bIsRead;
		return (m_fn = fopen(fname, bIsRead?"rb":"wb"))!=NULL;
	}

	void detach_()
	{
		if (m_fn)
		{
			fclose(m_fn);
			m_fn = NULL;
		}
	}
	
protected:
	FILE*	m_fn;
	bool		m_bRead;

};

class CMemStorage : public PoliStorage
{
public:
	CMemStorage() 
	{
		m_bRead = false;
#ifdef _REALLOC_MEM_STORAGE
		pMemBasePtr = (char*)malloc(4096);
		m_Size = 4096;
#else
		pMemBasePtr = NULL;
		m_Size = 0;
#endif //_REALLOC_MEM_STORAGE

		pMemCurPtr = pMemBasePtr;
		m_bAutoFree = true;
		
	}

	CMemStorage(const void* pReadBuff, const size_t BuffSize) : m_bRead(true), pMemBasePtr((char*)pReadBuff), m_Size(BuffSize), pMemCurPtr((char*)pReadBuff), m_bAutoFree(false){}

	~CMemStorage()
	{
		if(m_bAutoFree && pMemBasePtr)
			free(pMemBasePtr);
	}
	
	virtual size_t read_(void* pOutBuff, const size_t OutBuffSize)
	{
		if (!m_bRead || (m_Size - (pMemCurPtr - pMemBasePtr))<OutBuffSize)
		{
			POLI_ASSERT_(false);
			return 0;
		}

		memcpy(pOutBuff, pMemCurPtr, OutBuffSize);
		pMemCurPtr+=OutBuffSize;
		return OutBuffSize;
	}

	virtual size_t write_(const void* pDataBuff, const size_t DataBuffSize)
	{
		if (m_bRead)
		{
			POLI_ASSERT_(false);
			return 0;
		}
#ifdef _REALLOC_MEM_STORAGE

#define _COPY_BASIC_TYPE(basic_type)				\
case sizeof(basic_type):					\
*(basic_type*)pMemCurPtr = *(basic_type*)pDataBuff; \
pMemCurPtr+=sizeof(basic_type); \
return sizeof(basic_type)
		
		size_t use_mem = pMemCurPtr - pMemBasePtr;
		if ( (m_Size - use_mem) < DataBuffSize)
		{
			m_Size+=DataBuffSize/4096 + 4096;
			char* pNewMem = (char*)realloc(pMemBasePtr, m_Size);
			if (pNewMem!=pMemBasePtr)
			{
				if (pNewMem == NULL)
					return 0;
				
				pMemCurPtr = pNewMem + use_mem;
				pMemBasePtr = pNewMem;
			}
				
		}
		
		switch(DataBuffSize)
		{
			_COPY_BASIC_TYPE(char);
			_COPY_BASIC_TYPE(short);
			_COPY_BASIC_TYPE(int);
			_COPY_BASIC_TYPE(__int64);
		default:
			memcpy  (pMemCurPtr, pDataBuff, DataBuffSize);
			pMemCurPtr+=DataBuffSize;
			return DataBuffSize;
		}
//Not reach
		return 0;

#else	
		size_t i;
		for (i = 0; i<DataBuffSize; ++i)
			m_WriteStorage.push_back  (((unsigned char*)pDataBuff)[i]);

		return i;
		
#endif //_REALLOC_MEM_STORAGE
	}
	
	size_t size_()
	{
		if (m_bRead)
			return m_Size - (pMemCurPtr - pMemBasePtr);
		
#ifdef _REALLOC_MEM_STORAGE
		return pMemCurPtr - pMemBasePtr;
#else
		return m_WriteStorage.size  ();
#endif //_REALLOC_MEM_STORAGE
		
	}
	
	void* get_lin_space_()
	{
		if (m_bRead)
			return pMemCurPtr;
		
#ifdef _REALLOC_MEM_STORAGE
		return pMemCurPtr;
#else
		
	
		if(pMemBasePtr)
			free(pMemBasePtr);
		
		pMemBasePtr = (char*)malloc(size_  ());
		for (size_t i = 0; i<size_  (); ++i)
			pMemBasePtr[i] = m_WriteStorage[i];
		
		return pMemBasePtr;
#endif //_REALLOC_MEM_STORAGE
	}
	
	void detach_()
	{
		m_bAutoFree = false;
	}
	
protected:
	bool m_bAutoFree;
	bool m_bRead;
	char* pMemBasePtr;
	char* pMemCurPtr;
	size_t m_Size;
#ifndef _REALLOC_MEM_STORAGE
	std::deque<char> m_WriteStorage;
#endif //_REALLOC_MEM_STORAGE
	
};

#endif //_POLISTORAGE_H_
