#ifndef _RUDATASTORE_DISK_
#define _RUDATASTORE_DISK_

// Base types
#include "../../Core/Collection/RuCollectionsTree.h"
#include "../../Core/DataStore/RuDataStore_Base.h"
#include "../../Core/Stream/RuStreamIO.h"

#pragma unmanaged

// ************************************************************************************************************************************************************

class CRuDataStore_Disk : public CRuDataStore_Base
{
	ruRTTI_DECLARE
	ruHEAP_DECLARE
	ruCLASSGUID_DECLARE

protected:
	struct DataStoreHeader
	{
		INT32									m_tableListPosition;
		INT32									m_tableListSize;
		INT32									m_tableListAllocationSize;
	};

	struct KeyStruct
	{
		const BYTE*								m_key;										//!< Stream key
		INT32									m_keyLength;

		BOOL									operator==(const KeyStruct &key) const;
		BOOL									operator<(const KeyStruct &key) const;
		BOOL									operator>(const KeyStruct &key) const;
	};

	struct StreamHeader
	{
		BYTE*									m_key;										//!< Stream key
		INT32									m_streamPosition;							//!< Stream position
		INT32									m_streamSize;								//!< Used stream size
		INT32									m_allocationSize;							//!< Allocation stream size
	};

	struct TableHeader
	{
		char									m_name[256];								//!< Name of the table
		INT32									m_keyLength;								//!< Length of keys
		INT32									m_tablePosition;							//!< Position of first stream descriptor
		INT32									m_tableSize;								//!< Number of used stream descriptors
		INT32									m_allocationSize;							//!< Number of allocated stream descriptors

		CRuBinaryTree<KeyStruct, StreamHeader>	m_streamHeaders;
	};

	// Settings
	INT32										m_ioBufferSize;
	INT32										m_tableListPageSize;
	INT32										m_tablePageSize;

	// Data source
	BOOL										m_readOnly;
	CRuFileStream*								m_stream;

	// Run-time structure
	DataStoreHeader								m_dataStoreHeader;
	CRuArrayList<TableHeader *>					m_tableHeaders;

	// Workspace
	INT32										m_callbackKeyLength;
	BYTE*										m_ioBuffer;
	CRuMemoryStream								m_tempStream;

public:
												CRuDataStore_Disk();
	virtual										~CRuDataStore_Disk();

	BOOL										Create(const char *dataStoreName);
	BOOL										Open(const char *dataStoreName, BOOL readOnly = FALSE);

	virtual INT32								CreateTable(const char *tableName, INT32 keyLength);
	virtual BOOL								DeleteTable(const char *tableName);
	virtual INT32								GetTableHandle(const char *tableName);
	virtual INT32								GetTableKeyLength(INT32 tableHandle);

	virtual INT32								GetNumRecords(INT32 tableHandle);
	virtual IRuStream*							Retrieve(INT32 tableHandle, const BYTE *key);
	virtual IRuStream*							RetrieveByIndex(INT32 tableHandle, INT32 index);
	virtual BOOL								RetrieveKeyByIndex(INT32 tableHandle, INT32 index, BYTE *keyOut);
	virtual BOOL								Store(INT32 tableHandle, const BYTE *key, IRuStream *stream);
	virtual BOOL								Delete(INT32 tableHandle, const BYTE *key);
	virtual BOOL								DeleteAllRecords(INT32 tableHandle);

	BOOL										Flush();

protected:
	BOOL										DeleteStreamHeadersCallback(const void *key, void *data);

	BOOL										LoadDataStoreHeader(DataStoreHeader *headerOut);
	BOOL										SaveDataStoreHeader(DataStoreHeader *header);

	BOOL										LoadTableHeaders(DataStoreHeader &dsHeader, CRuArrayList<TableHeader *> &tableHeaders);
	BOOL										SaveTableHeaders(DataStoreHeader &dsHeader, CRuArrayList<TableHeader *> &tableHeaders);

	BOOL										LoadStreamHeaders(CRuArrayList<TableHeader *> &tableHeaders, INT32 tableHandle);
	BOOL										SaveStreamHeaders(CRuArrayList<TableHeader *> &tableHeaders, INT32 tableHandle);
	BOOL										SaveStreamHeadersCallback(const void *key, void *data);
};

// ************************************************************************************************************************************************************

#pragma managed

#endif
