//
//	Copyright © 2005 Nemetschek North America 
//	All Rights Reserved.
//
// Created by Vladislav Stanev

#pragma once

namespace VectorWorks
{
	namespace Debug
	{
		////////////////////////////////////////////////////////////////////////////////////
		// predefines from VCOM
		// this may produce link errors
		class IVWMemoryManager;
		class IMemoryCollector;
	}
}

namespace VWFC
{
	namespace MemoryManager
	{
		using namespace VectorWorks::Debug;

		////////////////////////////////////////////////////////////////////////////////////
		// Memory Manager class
		// when '_DEBUG_MEMORY' is defined this class stores all given memroy and keep track of the memory
		// 'DumpMemory' prints all unreleased memory
		class MManager
		{
		public:
										MManager(bool bVWMemManager, bool bCollectMemoryData);
			virtual						~MManager();
			
		public:
			void*						AllocateMemory(size_t size, const char* szFile, long lineNum);
			void						FreeMemory(void* ptr);
			bool						VerifyPointer(void* ptr, size_t size);
		
			template<class TYPE> void*	AllocateObjectArray(size_t count, const char* szFile, long lineNum);
			template<class TYPE> void	FreeObjctArray(void* p);
		
			void						DumpMemory(const char* szObjName);
		
			// set a string marker to the specified memory pointer
			// ASSERT(false) is executed when this memroy is being released
			void						SetMemoryMark(void* ptr, const char* szMarker=NULL);
			
		private:
#ifndef _VWFC_FOR_VW125x
			IVWMemoryManager*			fpVWMemoryManager;
			IMemoryCollector*			fpVWMemoryCollector;
			IMemoryCollector*			fpMemoryCollector;
#else
			bool						fbVWMemory;
#endif
		};
	}
	
	// access the memroy manager
	MemoryManager::MManager*				GetMManager();
	MemoryManager::MManager*				GetVWMManager();
}

# define NEW_VW_OBJECT(T)				(T*) new( VWFC::GetVWMManager()->AllocateMemory(sizeof(T), __FILE__, __LINE__)) T
# define DELETE_VW_OBJECT(T, p)			if ( p ) { p->~T(); VWFC::GetVWMManager()->FreeMemory(p); p = NULL; }
# define NEW_OBJECT(T)					(T*) new( VWFC::GetMManager()->AllocateMemory(sizeof(T), __FILE__, __LINE__)) T
# define DELETE_OBJECT(T, p)			if ( p ) { p->~T(); VWFC::GetMManager()->FreeMemory(p); p = NULL; }
# define NEW_DATA(size)					VWFC::GetMManager()->AllocateMemory( size, __FILE__, __LINE__ );
# define DELETE_DATA(p)					if ( p ) { VWFC::GetMManager()->FreeMemory(p); p = NULL; }
# define NEW_VW_DATA(size)				VWFC::GetVWMManager()->AllocateMemory( size, __FILE__, __LINE__ );
# define DELETE_VW_DATA(p)				if ( p ) { VWFC::GetVWMManager()->FreeMemory(p); p = NULL; }
# define NEW_OBJECTS_ARRAY(T, count)	(T*) VWFC::GetMManager()->AllocateObjectArray<T>( count, __FILE__, __LINE__ );
# define DELETE_OBJECTS_ARRAY(T, p)		if ( p ) { VWFC::GetMManager()->FreeObjctArray<T>( p ); p = NULL; }
# define NEW_VW_OBJECST_ARRAY(T, count)	(T*) VWFC::GetVWMManager()->AllocateObjectArray<T>( count, __FILE__, __LINE__ );
# define DELETE_VW_OBJECTS_ARRAY(T, p)	if ( p ) { VWFC::GetVWMManager()->FreeObjctArray<T>( p ); p = NULL; }

# define VERIFY_VWPOINTER(p, T)			ASSERTN( kVStanev, VWFC::GetVWMManager()->VerifyPointer( p, sizeof(T) ) )

// memory macros for the standard dynamic structures
# define DYN_ARRAY_NEW(size)			VWFC::GetMManager()->AllocateMemory( size, __FILE__, __LINE__)
# define DYN_ARRAY_DELETE(p)			VWFC::GetMManager()->FreeMemory( p );
# define DYN_QUEUE_NEW(size)			VWFC::GetMManager()->AllocateMemory( size, __FILE__, __LINE__)
# define DYN_QUEUE_DELETE(p)			VWFC::GetMManager()->FreeMemory( p );
# define DYN_MAP_NEW(size)				VWFC::GetMManager()->AllocateMemory( size, __FILE__, __LINE__)
# define DYN_MAP_DELETE(p)				VWFC::GetMManager()->FreeMemory( p );
# define DYN_CHUNK_ARRAY_NEW(size)		VWFC::GetMManager()->AllocateMemory( size, __FILE__, __LINE__)
# define DYN_CHUNK_ARRAY_DELETE(p)		VWFC::GetMManager()->FreeMemory( p );
# define VWDYN_ARRAY_NEW(size)			VWFC::GetVWMManager()->AllocateMemory( size, __FILE__, __LINE__)
# define VWDYN_ARRAY_DELETE(p)			VWFC::GetVWMManager()->FreeMemory( p );
# define VWDYN_QUEUE_NEW(size)			VWFC::GetVWMManager()->AllocateMemory( size, __FILE__, __LINE__)
# define VWDYN_QUEUE_DELETE(p)			VWFC::GetVWMManager()->FreeMemory( p );
# define VWDYN_MAP_NEW(size)			VWFC::GetVWMManager()->AllocateMemory( size, __FILE__, __LINE__)
# define VWDYN_MAP_DELETE(p)			VWFC::GetVWMManager()->FreeMemory( p );
# define VWDYN_CHUNK_ARRAY_NEW(size)	VWFC::GetVWMManager()->AllocateMemory( size, __FILE__, __LINE__)
# define VWDYN_CHUNK_ARRAY_DELETE(p)	VWFC::GetVWMManager()->FreeMemory( p );



// provide STL memory allocator for VW type memory for the plug-ins
namespace std
{
	// vw memory allocatorfor objects of class _Ty
	template<class _Ty> class vwallocator
	{
	public:
		typedef _Ty 				value_type;


		typedef value_type*			pointer;
		typedef value_type& 		reference;
		typedef const value_type*	const_pointer;
		typedef const value_type& 	const_reference;

		typedef size_t				size_type;
		typedef ptrdiff_t			difference_type;

		template<class _Other> struct rebind {	// convert an vwallocator<_Ty> to an vwallocator <_Other>
			typedef vwallocator<_Other> other;
 		};

		pointer address(reference _Val) const {	// return address of mutable _Val
			return (&_Val);
		}

		const_pointer address(const_reference _Val) const {	// return address of nonmutable _Val
			return (&_Val);
		}

		vwallocator() {	// construct default vwallocator (do nothing)
		}

		vwallocator(const vwallocator<_Ty>&) {	// construct by copying (do nothing)
		}

		template<class _Other> vwallocator(const vwallocator<_Other>&) {	// construct from a related vwallocator (do nothing)
		}

		template<class _Other> vwallocator<_Ty>& operator=(const vwallocator<_Other>&) {	// assign from a related vwallocator (do nothing)
			return (*this);
		}

		void deallocate(pointer _Ptr, size_type) {	// deallocate object at _Ptr, ignore size
			//operator delete(_Ptr);
			::GS_DisposePtr( gCBP, _Ptr );
		}

		pointer allocate(size_type _Count) {	// allocate array of _Count elements
			//return (_Allocate(_Count, (pointer)0));
			return (pointer) ::GS_NewPtr( gCBP, _Count * sizeof (_Ty) );
		}

		pointer allocate(size_type _Count, const void*) {	// allocate array of _Count elements, ignore hint
			return (allocate(_Count));
		}

		void construct(pointer _Ptr, const _Ty& _Val) {	// construct object at _Ptr with value _Val
			_Construct(_Ptr, _Val);
		}

		void destroy(pointer _Ptr)	{	// destroy object at _Ptr
			_Destroy(_Ptr);
		}

		size_type max_size() const	{	// estimate maximum array size
			size_type _Count = (size_type)(-1) / sizeof (_Ty);
			return (0 < _Count ? _Count : 1);
		}
	};
}

//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
namespace VWFC
{
	namespace MemoryManager
	{
		
		template<class TYPE> void*	MManager::AllocateObjectArray(size_t count, const char* szFile, long lineNum)
		{
			void*	pRawData	= this->AllocateMemory( count * sizeof(TYPE) + sizeof(size_t), szFile, lineNum );
			size_t*	pCount		= (size_t*) pRawData;
			TYPE*	pData		= (TYPE*) (pCount + 1);
			
			*pCount				= count;
			for(size_t i=0; i<count; i++) {
				TYPE*	pElement	= & pData[i];
				// call default constructor
				new(pElement) TYPE;
			}
			
			return pData;
		}

		template<class TYPE> void	MManager::FreeObjctArray(void* p)
		{
			if ( p ) {
				TYPE*	pData		= (TYPE*) p;
				size_t*	pCount		= ((size_t*) p) - 1;
				for(size_t i=0; i<*pCount; i++) {
					TYPE*	pElement	= & pData[i];
					pElement->~TYPE();
				}
				
				this->FreeMemory(pCount);
			}
		}
	}
}
