///////////////////////////////////////////////////////////////////////////////
/// @file deMemory.hpp
///
/// @brief Destiny3D Memory Manager
///
/// @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 Feb 2001
/// @author Lightning
/// @remarks Creation
///
/// @date Oct 2001
/// @author Hootie
/// @remarks Started Conversion to C++
///
/// @date Oct 2002
/// @author Lightning
/// @remarks Scrapped old, started from scratch
///
///////////////////////////////////////////////////////////////////////////////

#ifndef DEMEMORY_HPP
#define DEMEMORY_HPP

//include the headers
#include "deGlobalTypes.hpp"
#include "deMemory.hpp"

#if defined(DEMEMORY_DLL_EXPORTS) || defined(DESTINY3D_EXPORT_ALL)
#	define DEMEMORY_API DEDLL_EXPORT
#elif defined(DESTINY3D_STATIC_LINK)
#	define DEMEMORY_API
#else
#	define DEMEMORY_API DEDLL_IMPORT
#endif

//class IdeMemoryManager
DE3D_INTERFACE_(IdeMemoryManager)
{
	protected:
		~IdeMemoryManager() {}

	public:
		enum MallocType
		{
			RegMalloc = 1,
			Calloc,
			New,
			NewArray
		};

		enum FreeType
		{
			RegFree = 1,
			Delete,
			DeleteArray
		};

		///function to see if we initialized properly
		virtual deBoolean IsInitialized() = 0;

		//all the functions that are used for overridding
		virtual void * Malloc(unsigned int Size, MallocType Type, const char *File, long Line) = 0;
		virtual void Free(void *Ptr, FreeType Type, const char *File, long Line) = 0;
		virtual void * MemCpy(void *To, const void *From, unsigned int Size, const char *File, long Line) = 0;
		virtual void * MemSet(void *To, int Value, unsigned int Size, const char *File, long Line) = 0;
};

//export our function for getting a copy
extern "C"
{
	DEMEMORY_API IdeMemoryManager *IdeMemory_GetManager(char *ConfigFile);
}

//our static variable for the class that dicates the functions
#if defined(DEMEMORY_DLL_EXPORTS) || defined(DESTINY3D_EXPORT_ALL)
	//if building the memory manager, init it to null
	static IdeMemoryManager *deMemory = NULL;
#else
	static IdeMemoryManager *deMemory = IdeMemory_GetManager(NULL);
#endif

/*
//all the override functions
#undef malloc
#define malloc(Size) deMemory->Malloc(Size, IdeMemoryManager::RegMalloc, __FILE__, __LINE__);

#undef calloc
#define calloc(Size, Count) deMemory->Malloc(Size*Count, IdeMemoryManager::Calloc, __FILE__, __LINE__);

#undef free
#define free(Ptr) deMemory->Free(Ptr, IdeMemoryManager::RegFree, __FILE__, __LINE__);

#undef memcpy
#define memcpy(To, From, Size) deMemory->MemCpy(To, From, Size, __FILE__, __LINE__);

#undef memset
#define memset(To, Value, Size) deMemory->MemSet(To, Value, Size, __FILE__, __LINE__);

//the functions to override new, new[]
static inline void* operator new(unsigned int Size, const char *File, long Line){ return deMemory->Malloc(Size, IdeMemoryManager::New, File, Line); }
static inline void* operator new[](unsigned int Size, const char *File, long Line){ return deMemory->Malloc(Size, IdeMemoryManager::NewArray, File, Line); }

//redefine new so we get file and line
#define new new(__FILE__, __LINE__)

//now, due to being unable to overwride delete[] the same way you can with new[], delete and delete[] have to be done differently to allow
//the file and line to be obtained upon a delete and still have delete[] work when compiling
#ifdef _DEBUG
	//debug version. Debug does stack checking so we cant just push/pop values
	static inline void operator delete(void *Pointer)
	{
		char *File; long Line;
		__asm
		{
			mov ebx, [esp-4]
			mov [File], ebx
			mov ebx, [esp-8]
			mov [Line], ebx
		}
		deMemory->Free(Pointer, IdeMemoryManager::Delete, File, Line);
	}

	static inline void operator delete[](void *Pointer)
	{
		char *File; long Line;
		__asm
		{
			//retrieve the values
			mov ebx, [esp-4]
			mov [File], ebx
			mov ebx, [esp-8]
			mov [Line], ebx
		}
		deMemory->Free(Pointer, IdeMemoryManager::DeleteArray, File, Line);
	}

	static inline void PushDelStack(const char *File, long Line)
	{
		__asm
		{
			//move the values higher into the stack
			mov ebx, [File]
			mov [esp-8], ebx
			mov ebx, [Line]
			mov [esp-12], ebx
		}
		return;
	}
#else
	//release mode version
	static inline void operator delete(void *Ptr)
	{
		char *File; long Line;
		//a better/faster way would be just to move the other 2 params so they go into the File and Line
		//but then you risk release not actually creating a stack for them and throwing a warning
		__asm
		{
			//take them off the stack
			pop File;
			pop Line;
		}
		deMemory->Free(Ptr, IdeMemoryManager::Delete, File, Line);
	}

	static inline void operator delete[](void *Ptr)
	{
		char *File; long Line;
		//a better/faster way would be just to move the other 2 params so they go into the File and Line
		//but then you risk release not actually creating a stack for them and throwing a warning
		__asm
		{
			//take them off the stack
			pop File;
			pop Line;
		}
		deMemory->Free(Ptr, IdeMemoryManager::DeleteArray, File, Line);
	}

	//the function to allow delete[] to work
	static inline void PushDelStack(const char *File, long Line)
	{
		__asm
		{
			//put them on the stack
			push Line;
			push File;
		}
		return;
	}

#endif

//the special define of delete so we can obtain file and line
#define delete PushDelStack(__FILE__, __LINE__); delete
*/

#endif
