///////////////////////////////////////////////////////////////////////////////
/// @file deFile.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_HPP
#define DE_FILE_HPP

#include "deGlobalTypes.hpp"

#if defined(DEFILE_DLL_EXPORTS) || defined(DESTINY3D_EXPORT_ALL)
#	define DEFILE_API extern "C" DEDLL_EXPORT
#elif defined(DESTINY3D_STATIC_LINK)
#	define DEFILE_API extern "C"
#else
#	define DEFILE_API extern "C" DEDLL_IMPORT
#endif

#ifdef USING_DESTINY3D
#ifdef _DEBUG
#	ifdef DESTINY3D_STATIC_LINK
#		pragma comment(lib, "deFile_sd")
#	else
#		pragma comment(lib, "deFiled")
#	endif //DESTINY3D_STATIC_LINK
#else
#	ifdef DESTINY3D_STATIC_LINK
#		pragma comment(lib, "deFile_s")
#	else
#		pragma comment(lib, "deFile")
#	endif //DESTINY3D_STATIC_LINK
#endif //_DEBUG
#endif //USING_DESTINY3D

//-------------------------------------------
// Classes Declared
//-------------------------------------------
class IdeFile;
class IdeFileMemory;
class IdeFilePlugin;
class IdeFileVirtual;
class IdeFileReal;

class IdePlugin;
class IdeFileSystem;

//-------------------------------------------
// Factory functions
//-------------------------------------------
extern "C"
{
	// use IdeFSReal::Open to create IdeFileReal instances
	/// create a "memory file" - a file that exists only in application memory
	DEFILE_API IdeFileMemory*	IdeFile_CreateFileMemory();
	/// create a "plugin file" - one that can perform special plugin actions on other files
	DEFILE_API IdeFilePlugin*	IdeFile_CreateFilePlugin();
}

//-------------------------------------------
// Structures
//-------------------------------------------

/// information about a file's properties
typedef struct deFileProperties
{
	const char *	Filename;	///< filename of the file
	unsigned long	Size;		///< size of the file (note, if a plugin is applied then this will not be accurate)
	s64				Time;		///< date/time of the file (seconds from Jan 01, 1970 of course)
	long			Flags;		///< flags about the file
} deFileProperties;

//-------------------------------------------
// Defines & Constants
//-------------------------------------------

//some defines for easy access to the seeks
#define deFile_Seek_Start		IdeFile::SEEKF_START
#define deFile_Seek_End			IdeFile::SEEKF_END
#define deFile_Seek_Current		IdeFile::SEEKF_CURRENT

//open flags that a file can implemente
const long deFile_Open_Create		=0x00000001;	///<create file, fail if it exists
const long deFile_Open_Existing		=0x00000002;	///<open existing file, fail if it does not exist
const long deFile_Open_Always		=0x00000003;	///<always open, create if it does not exist
const long deFile_Open_CreateAlways	=0x00000004;	///<always create the file, overwrite if it exists

//if the file is read/write
const long deFile_Open_Read			=0x00000010;	///open for reading
const long deFile_Open_Write		=0x00000020;	///open for writing

//property flags for a deFileProperties.Flags entry
const long deFile_Directory		=0x00000001;

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

/// general interface class to allow simple usage of the file returned from a file system.
//class IdeFile
DE3D_INTERFACE_(IdeFile)
{
	protected:
		virtual ~IdeFile() {}

	public:
		enum Seek
		{
			SEEKF_START = 0,		///< start of a file
			SEEKF_END,				///< end of a file
			SEEKF_CURRENT,			///< current file pos
			SEEK_COUNT,
			SEEK_FORCE_32BIT = 0x7FFFFFFF
		};

		enum interface_t
		{
			iface_IdeFile = 0,
			iface_IdeFileReal,
			iface_IdeFileMemory,
			iface_IdeFileVirtual,
			iface_IdeFilePlugin,
			iface_force_32bit = 0x7FFFFFFF
		};
		virtual void* GetInterface(IdeFile::interface_t i) = 0;

		//close a file to release it
		virtual int Release() = 0;

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

		///close an open file
		virtual deBoolean Close() = 0;

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

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

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

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

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

/// interface class for the memory file.
/// Related functions: IdeFile_CreateFileMemory
//class IdeFileMemory : virtual public IdeFile
DE3D_INTERFACE(IdeFileMemory, IdeFile)
{
	protected:
		~IdeFileMemory() {}

	public:
		//open up a new memory file, if they tell us a buffer then it is read-only, otherwise
		//data is read/write
		virtual deBoolean Open() = 0;
		virtual deBoolean Open(long Length) = 0;
		virtual deBoolean Open(void *Buffer, long Length) = 0;
		virtual deBoolean Open(IdeFile *BaseFile) = 0;

		//MSVC requires that if 1 function has the same name here, any other virtual function
		//in the base class with the same name must also be defined
		//note from Assassin: COM classes aren't meant to have virtual functions with same name
		virtual deBoolean Open(IdeFileSystem *BaseFS, char *Filename, long OpenFlags) = 0;
};

/// interface class for the virtual file.
//class IdeFileVirtual : virtual public IdeFile
DE3D_INTERFACE(IdeFileVirtual, IdeFile)
{
	protected:
		~IdeFileVirtual() {}
};

/// interface class for the real (OS) file.
/// Related classes: IdeFSReal
//class IdeFileReal : virtual public IdeFile
DE3D_INTERFACE(IdeFileReal, IdeFile)
{
	protected:
		~IdeFileReal() {}
};

/// interface class for the plugin file.
/// Related functions: IdeFile_CreateFilePlugin
//class IdeFilePlugin : virtual public IdeFile
DE3D_INTERFACE(IdeFilePlugin, IdeFile)
{
	protected:
		~IdeFilePlugin() {}

	public:
		virtual deBoolean Open(IdeFile *BaseFile) = 0;
		
		//MSVC requires that if 1 function has the same name here, any other virtual function
		//in the base class with the same name must also be defined
		//note from Assassin: COM classes aren't meant to have virtual functions with same name
		virtual deBoolean Open(IdeFileSystem *BaseFS, char *Filename, long OpenFlags) = 0;

		virtual deBoolean AddPlugin(IdePlugin *Plugin) = 0;
		virtual deBoolean ReleasePlugin(IdePlugin *Plugin) = 0;
		virtual deBoolean ReleaseAllPlugins() = 0;

		//order all the blocks in the file
		virtual deBoolean DefragFile() = 0;
};

#endif

