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

#include "StdAfx.h"
//#include "VWMManager.h"

#ifndef _VWFC_FOR_VW125x
# include "VectorWorks/Debug/IVWMemoryManager.h"
# include "VectorWorks/Debug/IMemoryCollector.h"
#endif

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


//////////////////////////////////////////////////////////////////////////////////////////////////
static VWFC::MemoryManager::MManager*	g_pMManager		= NULL;
static VWFC::MemoryManager::MManager*	g_pVWMManager	= NULL;

namespace VWFC
{
	bool		HasAllocatedMemroyManagers()
	{
		return g_pMManager || g_pVWMManager;
	}

	void		AllocateMemoryManagers(VWFC::MemoryManager::MManager** ppOutOldManager, VWFC::MemoryManager::MManager** ppOutOldVWManager)
	{
		using namespace MemoryManager;

		if ( ppOutOldManager )		*ppOutOldManager	= g_pMManager;
		if ( ppOutOldVWManager )	*ppOutOldVWManager	= g_pVWMManager;

#ifdef _DEBUG_MEMORY
		g_pMManager			= new ( malloc( sizeof(MManager) ) ) MManager( false, true );
		g_pVWMManager		= new ( malloc( sizeof(MManager) ) ) MManager( true, true );
#else
		g_pMManager			= new ( malloc( sizeof(MManager) ) ) MManager( false, false );
		g_pVWMManager		= new ( malloc( sizeof(MManager) ) ) MManager( true, false );
#endif
	}
	
	void		FreeMemoryManagers(VWFC::MemoryManager::MManager* pOldManager, VWFC::MemoryManager::MManager* pOldVWManager)
	{
		using namespace MemoryManager;
		VWFC_ASSERT( g_pMManager != NULL );
		VWFC_ASSERT( g_pVWMManager != NULL );
		
		if ( g_pMManager ) {
			g_pMManager->~MManager();
			free( g_pMManager );
		}
		
		if ( g_pVWMManager ) {
			g_pVWMManager->~MManager();
			free( g_pVWMManager );
		}

		g_pMManager			= pOldManager;
		g_pVWMManager		= pOldVWManager;
	}

	MManager*	GetMManager()
	{
		VWFC_ASSERT( g_pMManager != NULL );
		return g_pMManager;
	}


	MManager*	GetVWMManager()
	{
		VWFC_ASSERT( g_pVWMManager != NULL );
		return g_pVWMManager;
	}

}

//////////////////////////////////////////////////////////////////////////////////////////////////

MManager::MManager(bool bVWMemManager, bool bCollectMemoryData)
{
#ifndef _VWFC_FOR_VW125x
	fpVWMemoryManager		= NULL;
	fpVWMemoryCollector		= NULL;
	fpMemoryCollector		= NULL;
	
	::GS_VWQueryInterface( IID_VWMemoryManager, (IVWUnknown**) & fpVWMemoryManager );

	if ( bCollectMemoryData ) {
		if ( bVWMemManager ) {
			if ( fpVWMemoryManager ) {
				fpVWMemoryManager->GetVWMemoryCollector( & fpVWMemoryCollector );
			}
		}
		else {
			::GS_VWQueryInterface( IID_MemoryCollector, (IVWUnknown**) & fpMemoryCollector );
		}
	}
#else
	fbVWMemory		= bVWMemManager;
#endif
}

MManager::~MManager()
{
#ifndef _VWFC_FOR_VW125x
	// these are unique interfaces -- single instances per VW
	if ( fpVWMemoryManager )
		fpVWMemoryManager->Release();
	fpVWMemoryManager		= NULL;

	if ( fpVWMemoryCollector )
		fpVWMemoryCollector->Release();
	fpVWMemoryCollector		= NULL;

	if ( fpMemoryCollector )
		fpMemoryCollector->Release();
	fpMemoryCollector		= NULL;
#endif
}

void* MManager::AllocateMemory(size_t size, const char* szFile, long lineNum)
{
	void*	pMemory		= NULL;
	
#ifdef _VWFC_FOR_VW125x
	if ( fbVWMemory ) {
		pMemory = ::GS_NewPtr( gCBP, size );
	}
	else {
		pMemory	= malloc( size );
	}
#else
	if ( fpVWMemoryManager ) {
		VERIFYN( kVStanev, VCOM_SUCCEEDED( fpVWMemoryManager->Allocate( size, & pMemory ) ) );
		if ( fpVWMemoryCollector ) {
			VERIFYN( kVStanev, VCOM_SUCCEEDED( fpVWMemoryCollector->RegisterMemory( eMemoryType_VectorWorks, pMemory, size, szFile, lineNum ) ) );
		}
	}
	else {
		pMemory		= malloc( size );
		if ( fpMemoryCollector ) {
			VERIFYN( kVStanev, VCOM_SUCCEEDED( fpMemoryCollector->RegisterMemory( eMemoryType_DLL, pMemory, size, szFile, lineNum ) ) );
		}
	}
#endif
	
	return pMemory;
}

void MManager::FreeMemory(void* ptr)
{
	if ( ptr == NULL )
		return;

#ifdef _VWFC_FOR_VW125x
	if ( fbVWMemory ) {
		if ( ptr )
			::GS_DisposePtr( gCBP, ptr );
	}
	else {
		if ( ptr )
			free( ptr );
	}
#else
	if ( fpVWMemoryManager ) {
		VERIFYN( kVStanev, VCOM_SUCCEEDED( fpVWMemoryManager->Free( ptr ) ) );
		if ( fpVWMemoryCollector ) {
			VERIFYN( kVStanev, VCOM_SUCCEEDED( fpVWMemoryCollector->UnRegisterMemory( eMemoryType_VectorWorks, ptr ) ) );
		}
	}
	else {
		free( ptr );
		if ( fpMemoryCollector ) {
			VERIFYN( kVStanev, VCOM_SUCCEEDED( fpMemoryCollector->UnRegisterMemory( eMemoryType_DLL, ptr ) ) );
		}
	}
#endif
}

bool MManager::VerifyPointer(void* ptr, size_t size)
{
#ifdef _VWFC_FOR_VW125x
	return true;
#else
	ASSERTN( kVStanev, ptr );
	ASSERTN( kVStanev, size > 0 );

	bool	bMemOk		= true;
	if ( fpVWMemoryCollector ) {
		VERIFYN( kVStanev, VCOM_SUCCEEDED( fpVWMemoryCollector->VerifyPointer( eMemoryType_VectorWorks, ptr, size, bMemOk ) ) );
	}
	else if ( fpMemoryCollector ) {
		VERIFYN( kVStanev, VCOM_SUCCEEDED( fpMemoryCollector->VerifyPointer( eMemoryType_DLL, ptr, size, bMemOk ) ) );
	}
	
	return bMemOk;
#endif
}

void MManager::DumpMemory(const char* szObjName)
{
#ifndef _VWFC_FOR_VW125x
	if ( fpVWMemoryCollector ) {
		VERIFYN( kVStanev, VCOM_SUCCEEDED( fpVWMemoryCollector->ReportMemory( szObjName ) ) );
	}
	else if ( fpMemoryCollector ) {
		VERIFYN( kVStanev, VCOM_SUCCEEDED( fpMemoryCollector->ReportMemory( szObjName ) ) );
	}
#endif
}

// set a string marker to the specified memory pointer
// ASSERT(false) is executed when this memroy is being released
// NOTE! Works only when _DEBUG_MEMORY is defined
void MManager::SetMemoryMark(void* ptr, const char* szMarker)
{
#ifndef _VWFC_FOR_VW125x
	if ( fpVWMemoryCollector ) {
		VERIFYN( kVStanev, VCOM_SUCCEEDED( fpVWMemoryCollector->SetMemoryMarker( ptr, szMarker ) ) );
	}
	else if ( fpMemoryCollector ) {
		VERIFYN( kVStanev, VCOM_SUCCEEDED( fpMemoryCollector->SetMemoryMarker( ptr, szMarker ) ) );
	}
#endif
}

