///////////////////////////////////////////////////////////////////////////////
/// @file deFile_priv.hpp
///
/// @brief basic file interface header
///
/// @author Lightning
///
/// This file is the intellectual property of Novus Delta, LLC.. Usage of the
/// contents of this file is subject to the Destiny3D Member License which
/// can be found at http://www.destiny3d.com.  Any other usage is prohibited.
///
/// This file is distributed "AS IS" without warranty of any kind.  Novus
/// Delta, LLC. does not guarantee the fitness of the contents of this file
/// for any particular purpose.
///
/// Copyright (C) 2001-2003 Novus Delta, LLC. All Rights Reserved.
///
/// <hr>
///                                 Change History
/// <hr>
///
/// @date May 2003
/// @author Lightning
/// @remarks Creation
///
///////////////////////////////////////////////////////////////////////////////

#ifndef DE_FILE_PRIV_HPP
#define DE_FILE_PRIV_HPP

#include "deFileSystem_priv.hpp"
#include "deGlobalTypes.hpp"
#include "deFile.hpp"
#include "dePlugins.hpp"

//-------------------------------------------
// Classes defined
//-------------------------------------------
class deFile;
class deFileReal;
class deFileVirtual;
class deFilePlugin;

//-------------------------------------------
// Classes
//-------------------------------------------

//a class to allow simple usage of the file returned from a file system
class deFile : virtual public IdeFile
{
	protected:
		deFile();
		virtual ~deFile();

	public:

		//close/release the file
		int Release();

		//get the interface for a class
		void* GetInterface(IdeFile::interface_t i);

		//open a file
		virtual deBoolean Open(IdeFileSystem *BaseFS, char *Filename, long OpenFlags);
		
		//close an open file
		virtual deBoolean Close();

		//read/write a file
		virtual long Read(void *Buffer, long Length);
		virtual long Write(void *Buffer, long Length);

		//get/set file position
		virtual long GetPosition();
		virtual long SetPosition(long NewPosition, IdeFile::Seek SeekType);

		//get a file's size and set a file's length
		virtual long GetSize();
		virtual deBoolean SetSize(long NewSize);
		
		//get/set a file's date/time
		virtual s64 GetTime();
		virtual deBoolean SetTime(s64 Time);

		//get current file's properties
		virtual deBoolean GetProperties(deFileProperties *Properties);

		//get the open flags
		virtual long GetOpenFlags();
};

//class for the memory FS
class deFileMemory : public deFile, public IdeFileMemory
{
public:
	deFileMemory();
	~deFileMemory();

	//close/release a file
	int Release();

	void* GetInterface(IdeFile::interface_t i);

	//open up a new memory FS, if they tell us a buffer then it is read-only, otherwise
	//data is read/write
	deBoolean Open();
	deBoolean Open(long Length);
	deBoolean Open(void *Buffer, long Length);
	deBoolean Open(IdeFileSystem *BaseFS, char *Filename, long OpenFlags);
	deBoolean Open(IdeFile *BaseFile);

	//close an open file
	deBoolean Close();

	//read/write data
	long Read(void *Buffer, long Length);
	long Write(void *Buffer, long Length);

	//get/set position
	long GetPosition();
	long SetPosition(long NewPosition, IdeFile::Seek SeekType);

	//get a file's size and set a length
	long GetSize();
	deBoolean SetSize(long NewSize);

	//get/set a file's date/time
	s64 GetTime();
	deBoolean SetTime(s64 Time);

	//get current file's properties
	deBoolean GetProperties(deFileProperties *Properties);

	//get the open flags
	long GetOpenFlags();

private:
	BYTE *		priv_Buffer;		//pointer to the data
	deBoolean	priv_OwnBuffer;		//do we own the buffer
	long		priv_AllocSize;		//current size of the memory
	long		priv_KnownSize;		//the known size for the memory (returned on GetSize)
	long		priv_NewAllocSize;	//size of a new chunk to alloc if needed
	long		priv_Position;		//the current position in the memory pool

	IdeFile *		priv_BaseFile;		//base file that is open
	IdeFileSystem *	priv_BaseFS;		//base fs that a file was opened from
	long			priv_OpenFlags;		//flags about the file/data
};

//class for the virtual file
class deFileVirtual : virtual public deFile, public IdeFileVirtual
{
protected:
	deFileVirtual();

	deFSVirtual *						priv_BaseFS;
	deFSVirtual::VirtualFileEntry *		priv_CurrentFile;

	//various properties to store in the file class
	long			priv_FileFlags;
	long			priv_CurrentPosition;

	friend class deFSVirtual;

public:
	~deFileVirtual();

	//close/release a file
	int Release();

	void* GetInterface(IdeFile::interface_t i);

	//open a file
	deBoolean Open(IdeFileSystem *BaseFS, char *Filename, long OpenFlags);

	//close an open file
	deBoolean Close();

	//read/write data
	long Read(void *Buffer, long Length);
	long Write(void *Buffer, long Length);

	//get/set position
	long GetPosition();
	long SetPosition(long NewPosition, IdeFile::Seek SeekType);

	//get a file's size and set a length
	long GetSize();
	deBoolean SetSize(long NewSize);
	DWORD SetSize(long NewSize, deFSPROGRESS *StatusCallback);

	//get/set a file's date/time
	s64 GetTime();
	deBoolean SetTime(s64 Time);

	//get current file's properties
	deBoolean GetProperties(deFileProperties *Properties);

	//get the open flags
	long GetOpenFlags();
};

//class for the real file
class deFileReal : virtual public deFile, public IdeFileReal
{
protected:
	deFileReal();

#ifdef _WIN32
  HANDLE		priv_FileHandle;					//handle to the open file
#elif linux
  int               priv_FileHandle;
  char            priv_FilePath[256];
#else
#error("File Handle not supported for OS");
#endif

	long		priv_OpenFlags;						//flags used on open
	char		priv_Filename[256];					//filename of the current file	

	friend class deFSReal;

public:
	~deFileReal();

	//close/release a file
	int Release();

	void* GetInterface(IdeFile::interface_t i);
	
	//open a file
	deBoolean Open(IdeFileSystem *BaseFS, char *Filename, long OpenFlags);

	//close an open file
	deBoolean Close();

	//read/write data
	long Read(void *Buffer, long Length);
	long Write(void *Buffer, long Length);

	//get/set position
	long GetPosition();
	long SetPosition(long NewPosition, IdeFile::Seek SeekType);

	//get a file's size and set a length
	long GetSize();
	deBoolean SetSize(long NewSize);

	//get/set a file's date/time
	s64 GetTime();
	deBoolean SetTime(s64 Time);

	//get current file's properties
	deBoolean GetProperties(deFileProperties *Properties);

	//get the open flags
	long GetOpenFlags();
};

//class for the plugin file
class deFilePlugin : virtual public deFile, public IdeFilePlugin
{
public:
	deFilePlugin();
	~deFilePlugin();

	//close/release a file
	int Release();

	void* GetInterface(IdeFile::interface_t i);
	
	//open a file
	deBoolean Open(IdeFileSystem *BaseFS, char *Filename, long OpenFlags);
	deBoolean Open(IdeFile *BaseFile);
	
	//close an open file
	deBoolean Close();

	//read/write data
	long Read(void *Buffer, long Length);
	long Write(void *Buffer, long Length);

	//get/set position
	long GetPosition();
	long SetPosition(long NewPosition, IdeFile::Seek SeekType);

	//get a file's size and set a length
	long GetSize();
	deBoolean SetSize(long NewSize);

	//get/set a file's date/time
	s64 GetTime();
	deBoolean SetTime(s64 Time);

	//get current file's properties
	deBoolean GetProperties(deFileProperties *Properties);

	//get the open flags
	long GetOpenFlags();

	deBoolean AddPlugin(IdePlugin *Plugin);
	deBoolean ReleasePlugin(IdePlugin *Plugin);
	deBoolean ReleaseAllPlugins();

	//order all the blocks in the file
	deBoolean DefragFile();

private:
	IdeFile *		priv_BaseFile;			//base file we are attached to
	IdeFileSystem *	priv_BaseFS;			//basefs if any to let go of
	deBoolean		priv_OwnBaseFile;		//do we own the base file
	long			priv_CurrentPosition;	//current position in the file
	long			priv_OpenFlags;			//open flags for files

	//a linked list for the plugins
	typedef struct PluginList
	{
		IdePlugin *				Plugin;		//attached plugin
		struct PluginList *		Next;		//next plugin in the list
		struct PluginList *		Previous;	//previous plugin in the list
	} PluginList;

	//header data about the file
#pragma pack(1)
	typedef struct PluginHeader
	{
		DWORD		ID;				//ID of the file
		DWORD		Version;		//version ID
		long		DataOffset;		//position of PluginFileData entries
		long		LastBlockSize;	//original size of the last block's data
		short		EntryCount;		//number of entries
	} PluginHeader;
#pragma pack()

	//data about the file
	typedef struct PluginFileData
	{
		long		RealFilePos;	//real position the block is at
		long		Size;			//size of the data block
	} PluginFileData;

	//function for getting a block of data from a file
	deBoolean GetFileBlock(long ReadBlock);
	deBoolean WriteCurrentFileBlock();

	//functions to apply plugins to data
	void *ApplyPluginEncode(void *Buffer, long *Length);
	void *ApplyPluginDecode(void *Buffer, long *Length);

	PluginList *	priv_PluginList_First;	//first entry in the list of plugins for the file
	PluginList *	priv_PluginList_Last;	//last entry in the list of plugins for the file
	deBoolean		priv_PluginLocked;		//whether or not plugins can be updated	

	//info about the file itself
	PluginFileData *	priv_FileData;			//array of file data information
	short				priv_FileDataCount;		//number of entries in the array
	long				priv_LastBlockSize;		//size of the last block's data
	
	deBoolean			priv_FileBlockChanged;	//data in the block was changed
	void *				priv_FileBuffer;		//buffer of file data
	long				priv_FileBlock;			//current block that the buffer is from
};

#endif

