/****************************************************************************************
        
                COMUtilities.cpp
                
                Copyright: (c) 2001 Eovia Corp. All rights reserved.
                
                Author: Ray Dream
                Date:   3/2/98
                
                Revision History
                
                when            who                     what & why
                ==========      ==========      ======================================================
                9/15/99         psq                     GetNewCountedPtrContext always returns a value
                09/13/99        Jerome          Added a test on gDebugUtilities in the 2 methods:
                                                                - GetNewCountedPtrContext()
                                                                - ReleaseCountedPtrContext(CountedPtrContext& ioContext)
                9/11/99         Ian                     Fixes for new refcounting stuff.
                09/06/99        Brice           Added gClipboardUtilities
                08/17/99        Luc                     Fixed a leak in InitUtilities & CleanUpUtilities
                7/13/99         cph                     cleaned up method names of random calls in shell utils (now setrandomseed & randomstep)
                5/18/99         psq                     removed unused globals
                5/18/99         Yann            Init the InitCountedObject locals in InitUtilities() to NULL
                4/5/99          Greg            Added debug-only counted ptr reference checker support
                04/01/99        Mathieu         another fix to have MCImage/Palettes link
                3/30/99         psq                     fixed ian's cleanup (grrr).
                3/30/99         Ian                     Cleaned up global usage a little.
                2/23/99         Alec            added prototypes to elim warnings
                2/16/99         Greg            Added DragAndDropUtilities
                2/4/99          psq                     fix const problem
                01/27/99        Nba                     Added new[] and delete[]
                1/18/99         Greg            Added gPersonalityUtilities
                12/03/98        Mathieu         Added gColorConversionUtilities
                11/15/98        tsh                     fix SIZE_T for Metrowerks Windows
                11/12/98        dsm                     moved IChangeManager from COM3DUtilities to COMUtilities
                11/11/98        Arnaud          Added physical memory functions 
                10/14/98        cph                     added gAssertUtilities
                9/21/98         tsh                     added IID_IShFileUtilities, moved GetSeparator, GetAppPath=>GetAppDirectory
                9/14/98         cph                     Added gFileStreamUtilities
                9/14/98         tsh                     comment out call to "atexit", won't link on Mac
                8/10/98         Greg            Merged IShMenuManager into IShMenuUtilities, added IShPartUtilities
                8/3/98          cph                     brought over IShMenuManager and IShActionManager from COM3DUtilities    
                6/25/98         cph                     removed include of IChangeManagement.h
                6/18/98         Greg            Added gMenuUtilities
        
*****************************************************************************************/

#include "COMUtilities.h"

#include "IShDebugUtilities.h"
#include "IShMemoryUtilities.h"
#include "IShUtilities.h"

#include "MCException.h"
#include "MCErrorMessages.h"
#include "MCCountedPtr.h"
#include "COMSafeUtilities.h"


class TMCCountedObject;
class TMCSMPCountedObject;


#include <string.h>
#include <stdlib.h>
#include <assert.h>



// extern-ed functions without prototypes, this elims warnings but really need a header(s)
// these are represented in different headers between the shell and the extensions
void    QuitExtension();
int32   MCRandom();
void    MCSetRandomSeed(int32 seed);
void*   __vec_new(void* p, int nb, int size, void* cst);
void    __vec_delete(void* p, int nb, int size, void* dst, int auto_delete_vec, int auto_delete);


#if Debug_
//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 QuitExtension()
//------------------------------------------------------------------------
{
	gShellUtilities = NULL;
}


const TMCString* GetErrorMessage(EMCErrorCode errorCode)
{
        return gShellUtilities->GetErrorMessage(errorCode);
}


//------------------------------------------------------------------------
int32 MCRandom()
//------------------------------------------------------------------------
{
	if (gShellUtilities)
	{
		return gShellUtilities->Random();
	}
	else
	{
		return 0;
	}
}

//------------------------------------------------------------------------
void MCSetRandomSeed(int32 seed)
//------------------------------------------------------------------------
{
	if (gShellUtilities)
	{
		gShellUtilities->SetRandomSeed(seed);
	}
}

//------------------------------------------------------------------------
int32 MCRandomStep(int32 before)
//------------------------------------------------------------------------
{
	if (gShellUtilities)
	{
		return gShellUtilities->RandomStep(before);
	}
	else
	{
		return 0;
	}
}

//------------------------------------------------------------------------
int32 MCRandomSteps(int32 before, int32 steps)
//------------------------------------------------------------------------
{
	if (gShellUtilities)
	{
		return gShellUtilities->RandomSteps(before, steps);
	}
	else
	{
		return 0;
	}
}

#ifndef qNoAllocators

#ifdef __GNUC__
	#error	cannot override new with gcc  //at least on the mac
#endif

//------------------------------------------------------------------------
void* operator new(MCSize byteCount) throw()
//------------------------------------------------------------------------
{
	if (MCVerify2(gMemoryUtilities))
	{
		MCAssertMCSizeCanFit(byteCount, uint32);
		return gMemoryUtilities->MCnew(static_cast<uint32>(byteCount));
	}
	else
	{
		return NULL;
	}
}

//------------------------------------------------------------------------
void operator delete(void* block) throw()
//------------------------------------------------------------------------
{
	if (gMemoryUtilities)
	{
		gMemoryUtilities->MCdelete(block);
	}
}

//------------------------------------------------------------------------
void* operator new[](MCSize byteCount) throw()
//------------------------------------------------------------------------
{
	if (MCVerify2(gMemoryUtilities))
	{
		MCAssertMCSizeCanFit(byteCount, uint32);
		return gMemoryUtilities->MCnewArray(static_cast<uint32>(byteCount));
	}
	else
	{
		return NULL;
	}
}

//------------------------------------------------------------------------
void operator delete[](void* block) throw()
//------------------------------------------------------------------------
{
	if (gMemoryUtilities)
	{
		gMemoryUtilities->MCdeleteArray(block);
	}
}


//------------------------------------------------------------------------
void* __vec_new(void* p, int nb, int size, void* cst)
//------------------------------------------------------------------------
{
	if (!p)
	{
		p = MCmalloc(nb* size);
	}
	if (p)
	{
		int i;
		int8* pp = (int8*)p;
		for (i = 0; i < nb; i++)
		{
			(*(void(*) (int8*) )cst)(pp);
			pp += size;
		}
		return p;
	}
	return 0;
}

//------------------------------------------------------------------------
void __vec_delete(void* p, int nb, int size, void* dst, int auto_delete_vec, int auto_delete)
//------------------------------------------------------------------------
{
	if (nb == -1)
	{
		throw TMCException(-108);
	}
	if (p)
	{
		int i;
		int8* pp;
		pp = ((int8*)p) + nb * size;
		for (i = 0; i < nb; i++)
		{
			pp -= size;
			(*(void(*) (int8* , int32) )dst)(pp, auto_delete);
		}
	}
	if (p && auto_delete_vec)
	{
		MCfree(p);
	}
}

#endif

