/****************************************************************************************************

		COMSafeUtilities.cpp
		Copyright: (c) 2001 Eovia Corp. All rights reserved.

		Author:	Arnaud
		Date:	3/17/2005

****************************************************************************************************/

#include "COMSafeUtilities.h"

#include "IShUtilities.h"
#include "IShDebugUtilities.h"
#include "IShMemoryUtilities.h"
#include "IShSafeUtilities.h"
#include "IShSMP.h"
#include "IShPartUtilities.h"
#include "IShthreadUtilities.h"
#include "IShParamUtilities.h"
#include "IChangeManagement.h"
#include "MCCountedPtr.h"

// -- projects that are defining qBrokenIncludeInCOMSUPPORT :
//              Kodak
//              PSHost
// -- end of list
#ifndef qBrokenIncludeInCOMSUPPORT
#include "IMFClipboard.h"
#endif


#include <assert.h>

#if WIN
#include "WIN_MCGlobals.h"
HINSTANCE       TWIN_MCGlobals::ghInstance				= NULL;
HWND            TWIN_MCGlobals::ghMainFrame				= NULL;

boolean         TWIN_MCGlobals::gMMX					= false;
boolean         TWIN_MCGlobals::gIsPentiumProcessor		= false;
boolean         TWIN_MCGlobals::gIsPentiumIIProcessor	= false;
boolean         TWIN_MCGlobals::gIsPentiumIIIProcessor	= false;
#endif


IShUtilities*				gShellUtilities				= NULL;
IShMemoryUtilities*			gMemoryUtilities			= NULL;
IShDebugUtilities*			gDebugUtilities				= NULL;
IShSafeUtilities*			gShSafeUtilities			= NULL;
IShSMPUtilities*			gShellSMPUtilities			= NULL;
IShResourceUtilities*		gResourceUtilities			= NULL;
IShFileUtilities*			gFileUtilities				= NULL;
IShFileFormatUtilities*		gFileFormatUtilities		= NULL;
IShComponentUtilities*		gComponentUtilities			= NULL;
IShThreadUtilities*			gShellThreadUtilities		= NULL;
IShMenuUtilities*			gMenuUtilities				= NULL;
IShActionManager*			gActionManager				= NULL;
IShPartUtilities*			gPartUtilities				= NULL;
IShPersonalityUtilities*	gPersonalityUtilities		= NULL;
IShDragAndDropUtilities*	gDragAndDropUtilities		= NULL;
IChangeManager*				gChangeManager				= NULL;
IShMouseUtilities*			gMouseUtilities				= NULL;
IShSoundUtilities*			gSoundUtilities				= NULL;
IShParamUtilities*			gParamUtilities				= NULL;

TMCCountedPtr<IShNetworkUtilities>	gNetworkUtilities;

#ifndef qBrokenIncludeInCOMSUPPORT
IMFClipboard*				gClipboardUtilities			= NULL;
#endif

#if Debug_  && qRecordCountedPtrRefs
TMCLocalStorage* TMCStackRecorder::gIsInStackReference;
boolean* TMCStackRecorder::gIsReferencingOn;
#endif

#if Debug_
void InitMCCountedObject(TMCCountedObject** first, TMCCountedObject** last,
                         TMCSMPCountedObject** firstSMP, TMCSMPCountedObject** lastSMP,
                         TMCAtomicCounterHolder* curent, TMCAtomicCounterHolder* total);

//Because we can't use MCVerify before the statics have been initialized
//This way we can see when @&$^@ people do a new in their statics.

//On the mac, assert doesn't work when initializing the statics => use DebugStr that breaks in the debugger
	#if WIN
		#define MCVerify2(e)		( (e) ? 1 : (assert(e), 0))
	#elif MAC
		#ifdef qMacho
			#include <Carbon/Carbon.h>
		#endif
		#define MCVerify2(e)		( (e) ? 1 : (::DebugStr("\pBug"), 0))
	#else
		#error unknown platform
	#endif

#else
  
#define MCVerify2(e)		(e)

#endif


//------------------------------------------------------------------------
void CleanUpSafeUtilities()
//------------------------------------------------------------------------
{
	ReleaseIfNotNull(&gComponentUtilities);
	ReleaseIfNotNull(&gShellSMPUtilities);
	ReleaseIfNotNull(&gMemoryUtilities);
	ReleaseIfNotNull(&gDebugUtilities);
	ReleaseIfNotNull(&gShSafeUtilities);
	ReleaseIfNotNull(&gResourceUtilities);
	ReleaseIfNotNull(&gFileUtilities);
	ReleaseIfNotNull(&gFileFormatUtilities);
	ReleaseIfNotNull(&gShellUtilities);
	ReleaseIfNotNull(&gNetworkUtilities);
	ReleaseIfNotNull(&gShellThreadUtilities);
	ReleaseIfNotNull(&gActionManager);
	ReleaseIfNotNull(&gMenuUtilities);
	ReleaseIfNotNull(&gPartUtilities);
	ReleaseIfNotNull(&gPersonalityUtilities);
	ReleaseIfNotNull(&gDragAndDropUtilities);
	ReleaseIfNotNull(&gChangeManager);
#ifndef qBrokenIncludeInCOMSUPPORT
	ReleaseIfNotNull(&gClipboardUtilities);
#endif
	ReleaseIfNotNull(&gMouseUtilities);
	ReleaseIfNotNull(&gSoundUtilities);
	ReleaseIfNotNull(&gParamUtilities);

#ifdef qSMP
	TerminateSMP();
#endif
}

//------------------------------------------------------------------------
void InitSafeUtilities(IMCUnknown* utilities)
//------------------------------------------------------------------------
{
	if (MCVerify2(utilities))
	{
		utilities->QueryInterface(IID_IShUtilities,             (void**)& gShellUtilities);
		utilities->QueryInterface(IID_IShFileFormatUtilities,   (void**)& gFileFormatUtilities);
		utilities->QueryInterface(IID_IShFileUtilities,         (void**)& gFileUtilities);
		utilities->QueryInterface(IID_IShResourceUtilities,     (void**)& gResourceUtilities);
		utilities->QueryInterface(IID_IShSMPUtilities,          (void**)& gShellSMPUtilities);
		utilities->QueryInterface(IID_IShNetworkUtilities,		(void**)& gNetworkUtilities);
		utilities->QueryInterface(IID_IShDebugUtilities,        (void**)& gDebugUtilities);
		utilities->QueryInterface(IID_IShMemoryUtilities,       (void**)& gMemoryUtilities);
		utilities->QueryInterface(IID_IShSafeUtilities,			(void**)& gShSafeUtilities);
		utilities->QueryInterface(IID_IShComponentUtilities,    (void**)& gComponentUtilities);
		utilities->QueryInterface(IID_IChangeManager,           (void**)& gChangeManager);
		utilities->QueryInterface(IID_IShDragAndDropUtilities,  (void**)& gDragAndDropUtilities);
		utilities->QueryInterface(IID_IShPersonalityUtilities,  (void**)& gPersonalityUtilities);
		utilities->QueryInterface(IID_IShPartUtilities,         (void**)& gPartUtilities);
		utilities->QueryInterface(IID_IShMenuUtilities,         (void**)& gMenuUtilities);
		utilities->QueryInterface(IID_IShActionManager,         (void**)& gActionManager);
		utilities->QueryInterface(IID_IShThreadUtilities,       (void**)& gShellThreadUtilities);
		utilities->QueryInterface(IID_IShMouseUtilities,        (void**)& gMouseUtilities);
		utilities->QueryInterface(IID_IShSoundUtilities,        (void**)& gSoundUtilities);
		utilities->QueryInterface(IID_IShParamUtilities,        (void**)& gParamUtilities);
		
#ifndef qBrokenIncludeInCOMSUPPORT
		utilities->QueryInterface(IID_IMFClipboard,             (void**)& gClipboardUtilities);
#endif

#if WIN 
		TProcessorInfo processorInfo;
		gShSafeUtilities->GetProcessorInfo(processorInfo);

		TWIN_MCGlobals::gMMX                    = processorInfo.fUseMMX;
		TWIN_MCGlobals::gIsPentiumProcessor     = processorInfo.fIsPentiumProcessor;
		TWIN_MCGlobals::gIsPentiumIIProcessor   = processorInfo.fIsPentiumIIProcessor;
		TWIN_MCGlobals::gIsPentiumIIIProcessor  = processorInfo.fIsPentiumIIIProcessor;
#endif

#ifdef qSMP
		InitSMP(true);
#endif

#if Debug_  && qRecordCountedPtrRefs
        TMCStackRecorder::gIsInStackReference	= gDebugUtilities->GetStackReference2();
        TMCStackRecorder::gIsReferencingOn		= gDebugUtilities->GetIsReferencingOn();
#endif
#if Debug_
        TMCCountedObject** first = NULL;
        TMCCountedObject** last = NULL;
        TMCSMPCountedObject** firstSMP = NULL;
        TMCSMPCountedObject** lastSMP = NULL;
        TMCAtomicCounterHolder* current = NULL;
        TMCAtomicCounterHolder* total = NULL;
        gDebugUtilities->InitCountedObject(first, last, firstSMP, lastSMP, current, total);
        InitMCCountedObject(first, last, firstSMP, lastSMP, current, total);
#endif
	}
}


//------------------------------------------------------------------------
void* MCnew(uint32 size)
//------------------------------------------------------------------------
{
	if (MCVerify(gMemoryUtilities))
		return gMemoryUtilities->MCnew(size);
	else
		return NULL;
}


//------------------------------------------------------------------------
void* MCmalloc(MCSize size)
//------------------------------------------------------------------------
{
	if (MCVerify2(gMemoryUtilities))
	{
		MCAssertMCSizeCanFit(size, uint32);
		return gMemoryUtilities->Malloc(static_cast<uint32>(size));
	}
	else
	{
		return NULL;
	}
}

//------------------------------------------------------------------------
void* MCcalloc(uint32 nmemb, uint32 size)
//------------------------------------------------------------------------
{
	if (MCVerify2(gMemoryUtilities))
	{
		return gMemoryUtilities->Calloc(nmemb, size);
	}
	else
	{
		return NULL;
	}
}

//------------------------------------------------------------------------
void* MCrealloc(void* ptr, uint32 size)
//------------------------------------------------------------------------
{
	if (MCVerify2(gMemoryUtilities))
	{
		return gMemoryUtilities->Realloc(ptr, size);
	}
	else
	{
		return NULL;
	}
}

//------------------------------------------------------------------------
void MCfree(void* ptr)
//------------------------------------------------------------------------
{
	if (gMemoryUtilities && ptr)
	{
		gMemoryUtilities->Free(ptr);
	}
}

//------------------------------------------------------------------------
void* MCmallocAligned(uint32 size, uint8 alignPower)
//------------------------------------------------------------------------
{
	if (MCVerify2(gMemoryUtilities))
	{
		return gMemoryUtilities->MallocAligned(size, alignPower);
	}
	else
	{
		return NULL;
	}
}

//------------------------------------------------------------------------
void MCfreeAligned(void* ptr)
//------------------------------------------------------------------------
{
	if (gMemoryUtilities && ptr)
	{
		gMemoryUtilities->FreeAligned(ptr);
	}
}


//------------------------------------------------------------------------
void* MCmallocPhysical(uint32 size)
//------------------------------------------------------------------------
{
	if (MCVerify2(gMemoryUtilities))
	{
		return gMemoryUtilities->MallocPhysical(size);
	}
	else
	{
		return NULL;
	}       
}

//------------------------------------------------------------------------
void MCfreePhysical(void* ptr, uint32 size)
//------------------------------------------------------------------------
{
	if (MCVerify2(gMemoryUtilities))
	{
		gMemoryUtilities->FreePhysical(ptr, size);
	}
}

//------------------------------------------------------------------------
void* MChighmallocPSHost(int32 size)
//------------------------------------------------------------------------
{
	if (MCVerify2(gMemoryUtilities))
	{
		return gMemoryUtilities->HighmallocPSHost(size);
	}
	else
	{
		return NULL;
	}
}

//------------------------------------------------------------------------
void* MChighlockPSHost(void* ptr, boolean moveHigh)
//------------------------------------------------------------------------
{
	if (MCVerify2(gMemoryUtilities))
	{
		return gMemoryUtilities->HighlockPSHost( ptr, moveHigh );
	}
	else
	{
		return NULL;
	}
}

//------------------------------------------------------------------------
void MChighfreePSHost(void* ptr)
//------------------------------------------------------------------------
{
	if (MCVerify2(gMemoryUtilities)&& ptr)
	{
		gMemoryUtilities->HighfreePSHost(ptr);
	}
}

//------------------------------------------------------------------------
void MChighunlockPSHost(void* ptr)
//------------------------------------------------------------------------
{
	if (MCVerify2(gMemoryUtilities)&& ptr)
	{
		gMemoryUtilities->HighunlockPSHost(ptr);
	}
}

//------------------------------------------------------------------------
int32 MCgetPIHandleSizePSHost(void* ptr)
//------------------------------------------------------------------------
{
	if (MCVerify2(gMemoryUtilities))
	{
		return gMemoryUtilities->GetPIHandleSizePSHost(ptr);
	}
	else
	{
		return 0;
	}
}

//------------------------------------------------------------------------
int32 MCsetPIHandleSizePSHost(void* ptr, int32 newSize)
//------------------------------------------------------------------------
{
	if (MCVerify2(gMemoryUtilities))
	{
		return gMemoryUtilities->SetPIHandleSizePSHost(ptr, newSize);
	}
	else
	{
		return -1;
	}
}


//------------------------------------------------------------------------
TMCAsciiTranslationTable* GetAsciiTranslationTable()
//------------------------------------------------------------------------
{
	if (MCVerify2(gShSafeUtilities))
	{
		return gShSafeUtilities->GetAsciiTranslationTable();
	}
	return NULL;
}


//------------------------------------------------------------------------
void GetFileForCurrentLanguage(IMCFile* file, boolean checkIfFileExists, boolean addSpace)
//------------------------------------------------------------------------
{
	if (MCVerify2(gShellUtilities))
	{
		gShellUtilities->GetFileForCurrentLanguage(file, checkIfFileExists, addSpace);
	}
}


#ifdef qLeaks

#include "MCMemory.h"

TDisableLeakTracking::TDisableLeakTracking()
{
	fPreviousState = gMemoryUtilities->DisableLeakTracking();
}

TDisableLeakTracking::~TDisableLeakTracking()
{
	gMemoryUtilities->RestoreLeakTracking(fPreviousState);
}

#endif


//------------------------------------------------------------------------
void MC_CallAssert_(pointer f, uint32 l)
//------------------------------------------------------------------------
{
	if (MCVerify2(gDebugUtilities))
	{
		gDebugUtilities->MC_CallAssert_(f, l);
	}
}

//------------------------------------------------------------------------
void MC_CallNotify_(pointer f, uint32 l, const char* message)
//------------------------------------------------------------------------
{
	if (MCVerify2(gDebugUtilities))
	{
		gDebugUtilities->MC_CallNotify_(f, l, message);
	}
}

//------------------------------------------------------------------------
void MC_CallNotify_(pointer f, uint32 l, const char* message, real number)
//------------------------------------------------------------------------
{
	if (MCVerify2(gDebugUtilities))
	{
		gDebugUtilities->MC_CallNotify_(f, l, message, number);
	}
}

//------------------------------------------------------------------------
void MC_CallNotify_(pointer f, uint32 l, const char* message, real number1, real number2)
//------------------------------------------------------------------------
{
	if (MCVerify2(gDebugUtilities))
	{
		gDebugUtilities->MC_CallNotify_(f, l, message, number1, number2);
	}
}


#if Debug_  && qRecordCountedPtrRefs
//------------------------------------------------------------------------
void TMCStackRecorder::AddReference(const void* object, const void* context)
//------------------------------------------------------------------------
{
	if (MCVerify2(gDebugUtilities))
	{
		gDebugUtilities->AddReference(object, context);
	}
}

//------------------------------------------------------------------------
void TMCStackRecorder::RemoveReference(const void* object, const void* context)
//------------------------------------------------------------------------
{
	if (gDebugUtilities)
	{
		gDebugUtilities->RemoveReference(object, context);
	}
}

//------------------------------------------------------------------------
void ExploreAllStackReferences()
//------------------------------------------------------------------------
{       // No implementation for now for extensions - We may wany to add support for it in the future
}

//------------------------------------------------------------------------
void ExploreStackReferences(void* object)
//------------------------------------------------------------------------
{       // No implementation for now for extensions - We may wany to add support for it in the future
}

//------------------------------------------------------------------------
void ExploreStackReferencesIU(void* object)
//------------------------------------------------------------------------
{       // No implementation for now for extensions - We may wany to add support for it in the future
}

//------------------------------------------------------------------------
CountedPtrContext GetNewCountedPtrContext(void)
//------------------------------------------------------------------------
{
	if (gDebugUtilities)
	{
		return gDebugUtilities->GetNewCountedPtrContext();
	}
	return NULL;
}

//------------------------------------------------------------------------
void ReleaseCountedPtrContext(CountedPtrContext& ioContext)
//------------------------------------------------------------------------
{
	if (gDebugUtilities)
	{
		gDebugUtilities->ReleaseCountedPtrContext(ioContext);
	}
}

#endif


