///////////////////////////////////////////////////////////////////////////////
/// @file deFileSystem.hpp
///
/// @brief private base file system 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 Nov 2001
/// @author Lightning
/// @remarks Creation
///
/// @date Dec 2002
/// @author kurifu
/// @remarks File finding handles
///
///////////////////////////////////////////////////////////////////////////////

#ifndef DE_FILESYSTEM_PRIV_HPP
#define DE_FILESYSTEM_PRIV_HPP

#ifdef _WIN32
#include <windows.h>
#elif linux
#include <dirent.h>
#endif

#include "deFileSystem.hpp"

class deFileSystem;
class deFSReal;
class deFSVirtual;

//base class for all filesystems
class deFileSystem : virtual public IdeFileSystem, public deRefCountBase
{
protected:
	deFileSystem();
	virtual ~deFileSystem();
public:

	void* GetInterface(IdeFileSystem::interface_t i);

	virtual IdeFile* Open(const char *Filename, long OpenFlags);

	//get/set the current directory
	virtual const char *GetDirectory();
	virtual deBoolean SetDirectory(const char *Directory);
	
	//allow for renaming, deleting, moving, and copying of files
	virtual	deBoolean Rename(const char *OldFilename, const char *NewFilename);
	virtual deBoolean Delete(const char *Filename, deFSPROGRESS StatusCallback);
	virtual deBoolean Move(const char *OldFilename, const char *NewFilename, deFSPROGRESS StatusCallback);
	virtual deBoolean Copy(const char *OldFilename, const char *NewFilename, deFSPROGRESS StatusCallback);

	//create and delete directories
	virtual deBoolean AddDirectory(const char *Directory);
	virtual deBoolean DeleteDirectory(const char *Directory, deFSPROGRESS StatusCallback);

	//allow finding of files
	void* FindFirst(const char *Pattern, deFileProperties *Properties);
	deBoolean FindNext(void* Handle, deFileProperties *Properties);
	deBoolean FindEnd(void* Handle);
};

//class for the real FS
class deFSReal : public deFileSystem, public IdeFSReal
{
protected:
	//allow the real class to call the open
	friend class deFileReal;

	//allow opening a file from deFileReal
	deBoolean deFSReal::Open(deFileReal *RealFile, const char *Filename, long OpenFlags);

public:
	deFSReal();
	~deFSReal();

	void* GetInterface(IdeFileSystem::interface_t i);

	IdeFile* Open(const char *Filename, long OpenFlags);

	//get/set the current directory
	const char *GetDirectory();
	deBoolean SetDirectory(const char *Directory);
	
	//allow for renaming, deleting, moving, and copying of files
	deBoolean Rename(const char *OldFilename, const char *NewFilename);
	deBoolean Delete(const char *Filename, deFSPROGRESS StatusCallback);
	deBoolean Move(const char *OldFilename, const char *NewFilename, deFSPROGRESS StatusCallback);
	deBoolean Copy(const char *OldFilename, const char *NewFilename, deFSPROGRESS StatusCallback);

	//create and delete directories
	deBoolean AddDirectory(const char *Directory);
	deBoolean DeleteDirectory(const char *Directory, deFSPROGRESS StatusCallback);
	
	//allow finding of files
	void* FindFirst(const char *Pattern, deFileProperties *Properties);
	deBoolean FindNext(void* Handle, deFileProperties *Properties);
	deBoolean FindEnd(void* Handle);

private:
	char			priv_CurrentDirectory[1024];		//current directory
	char			priv_TempCurrentDirectory[1024];	//tempory place for directory changing

	#define			RealFindID			0x44494652		//'RFID', id for search handles

	typedef struct FindInfoReal
	{
		DWORD				FindID;						//stucture ID
#ifdef WIN32
		HANDLE				FindHandle;					//handle to the data
		WIN32_FIND_DATA		FindData;					//dos returned find data
		
#elif linux
      DIR * FindDir;
      char * Pattern;
#else
#error FindData not implemented for OS
#endif
	} FindInfoReal;
};

//class for the virtual fs
class deFSVirtual : public deFileSystem, public IdeFSVirtual
{
public:
	deFSVirtual();
	~deFSVirtual();

	void* GetInterface(IdeFileSystem::interface_t i);

	//functions to open/close the base file
	deBoolean OpenBaseFile(IdeFile *BaseFile, long OpenFlags);
	deBoolean OpenBaseFilename(const char *Filename, long OpenFlags);
	deBoolean CloseBaseFile();

	//functions to open a virtual file
	IdeFile* Open(const char *Filename, long OpenFlags);

	//get/set the current directory
	const char *GetDirectory();
	deBoolean SetDirectory(const char *Directory);
	
	//allow for renaming, deleting, moving, and copying of files
	deBoolean Rename(const char *OldFilename, const char *NewFilename);
	deBoolean Delete(const char *Filename, deFSPROGRESS StatusCallback);
	deBoolean Move(const char *OldFilename, const char *NewFilename, deFSPROGRESS StatusCallback);
	deBoolean Copy(const char *OldFilename, const char *NewFilename, deFSPROGRESS StatusCallback);

	//create and delete directories
	deBoolean AddDirectory(const char *Directory);
	deBoolean DeleteDirectory(const char *Directory, deFSPROGRESS StatusCallback);
	
	//allow finding of files
	void* FindFirst(const char *Pattern, deFileProperties *Properties);
	deBoolean FindNext(void* Handle, deFileProperties *Properties);
	deBoolean FindEnd(void* Handle);

protected:
	friend class deFileVirtual;

	//structure containing information about the files in the VFS
	#pragma pack(push,4)		//Because of how the file is read, we need 4 byte packing instead of 8
	typedef struct VirtualFileEntry
	{
		char *		FileName;							//file's name
		union
		{
			long						Position;		//position in the VFS that the file exists
			struct VirtualFileEntry *	NextDirectory;	//next sub directory for the parent directory
		};
		union
		{
			long						Size;			//size of the file
			struct VirtualFileEntry *	SubDirectory;	//pointer to the sub directories for the current directory

		};
		s64							Time;				//time of the file
		struct VirtualFileEntry *	NextFile;			//pointer to the next file for the current directory
		struct VirtualFileEntry *	ParentDirectory;	//pointer to the parent of the file or directory
		deFileVirtual *				OpenedFile;			//pointer to the class that has the file if it is open
	} VirtualFileEntry;
	#pragma pack(pop)			//restore the packing
	
	//function to open up a virtual file from IdeFileVirtual
	deBoolean Open(deFileVirtual *BaseFile, const char *Filename, long OpenFlags);

	//all the private functions that deFileVirtual will call
	deBoolean Close(deFileVirtual *FileEntry);
	
	//read/write data
	long Read(deFileVirtual *FileEntry, void *Buffer, long Length);
	long Write(deFileVirtual *FileEntry, void *Buffer, long Length);

	//set a file's length
	DWORD deFSVirtual::SetSize(deFileVirtual *FileEntry, long NewSize, deFSPROGRESS *StatusCallback);

private:
	//private functions to read and write directories to the file
	deBoolean ReadDirectoryTree();
	deBoolean WriteDirectoryTree();
	deBoolean DestroyDirectoryTree();

	//private function for moving data around in the VFS
	DWORD AdjustFile(deFileVirtual *FileEntry,long WriteSize, deBoolean MakeCopy, deFSPROGRESS *StatusCallback);
	DWORD MoveData(long StartPosition, long ByteShift, deFSPROGRESS *StatusCallback);

	//pattern matching function
	deBoolean MatchPattern(const char *Pattern, const char *Filename);
	deBoolean IsPattern(const char *Pattern);

	//internal DeleteDirectory that has a pointer to the function pointer
	DWORD deFSVirtual::DeleteDirectory(const char *Directory, deFSPROGRESS *StatusCallback);

	#define VirtualFindID		0x44494656		//'VFID', id for search handles
	
	//header structure in the file
	typedef struct VirtualHeader
	{
		DWORD	ID;					//ID verifying this is our file
		DWORD	Version;			//Version of the file
		long	DirectoryOffset;	//offset to the list of directories and files
	} VirtualHeader;

	//a struct to keep all the find information together
	typedef struct FindInfoVirtual
	{
		DWORD				FindID;				//so we know we have the right struct
		char *				FindPattern;		//the pattern currently being looked for
		VirtualFileEntry *	FindLastEntry;		//last entry find returned
		VirtualFileEntry *	FindDirectory;		//the directory we are doing the find in
		deBoolean			FindDirSearched;	//where directories searched yet
	} FindInfoVirtual;

	//directory parsing/navigating function
	//I am unsure why, but a typedef struct for VirtualFileEntry was causing compile errors so the function
	//is defined here to stop the errors
	VirtualFileEntry *ParseDirectory(const char *Directory, deBoolean FileAttached, long *FileNameStart);
	deBoolean NameInUse(VirtualFileEntry *Directory, const char *Name, deBoolean *IsDirectory);
	deBoolean AdjustFilePositions(VirtualFileEntry *Directory, long StartPosition, long ByteShift);

	//data about the base fs used to read/write files
	IdeFSReal *			BaseFS;			//a base FS if we opened up a real fs
	IdeFile *			BaseFile;		//the file to use to read/write the virtual fs data
	deBoolean			BaseFileOwner;	//did we open/create the base file
	long				BaseFlags;		//flags for the base file system to know if we can write files

	//storage of the directory tree
	VirtualFileEntry *	RootDirectory;		//pointer to the root directory
	VirtualFileEntry *	CurrentDirectory;	//pointer to the current directory entry

	//a temporary variable storing the current directory name
	char *				CurDirectoryName;
};

#endif

