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


		MCException.h


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


		Author:	Ian
		Date:	12/11/97

		Revision History

		when		who			what & why
		==========	==========	======================================================
		12/5/99		Pierre		Outlined the constructors to allow putting breakpoint in release mode
		11/3/99		Gerald		Moved the destructor of TMCException in the .h to avoid link errors with
								other modules than MCCore
		11/2/99		Ian			Added a TMCString* to the exception and another constructor
								that takes a TMCString*. The exception owns the string after
								you pass it to the exceptions constructor, and it will be
								deleted when the exception destructs.
		11/23/98	pbk			moved Declarevolatile here
		08/06/98	Nba/Pbk		removed stdexcept
		7/14/98		Alec		fixed up problem in EXCEPTION_ERR
		7/14/98		Alec		brought over functionality from the ID exception class
									and more macros, now derived from ANSI stdexcept
		4/27/98		Ian			Added ThrowIfNoMem(), this can be used after a new allocation
								it will throw the correct exception for the failure to allocate
								memory.
		3/15/98		Ian			Changed exception macro's to support an argument, this was
								done to avoid unused variable warnings with the original 
								macros.

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

#ifndef __MCException__
#define __MCException__

#if CP_PRAGMA_ONCE
#pragma once
#endif

#include "MCBasicTypes.h"
#include "MCStatusCode.h"
#include "MCOSConfig.h"

// TODO:  We still need to define the mechanism to convert an exception err/message
// into a localized string.  I'd much rather store a const char* to this for
// debugging than the message id that I have to translate manually.


#include "MCString.h"

/// \addtogroup MCCore
/// \{

/// <P>TMCException is the class used to deal with C++ and system exceptions. You should NEVER call throw without creating
/// a TMCException. There are several useful macros that throw exceptions: ThrowIfNil(), ThrowIfNoMem(), or ThrowIfError().
/// Or you can use: throw TMCException(...); </P>
///
/// For more information please refer to the "Failure Handling" chapter in the overview of the SDK
///
class MCDLLEXPORT TMCException : public TMCObject
{
	public:		
		/// constructor: the standard errors can be found in MCStatusCode.h
		/// you can create your own errors: it is best to use MAKE_MCCOMErr with ExtensionModule for that purpose.
		/// \note when using kNoErr, there wont be a warning message!
		///
		 TMCException		 		(const MCErr error = kNoErr, const char* file = 0, const int	line 	= 0 ) ;
		
		/// error and error string constructor
		/// The exception will OWN the given string
		///
		TMCException		 		(const MCErr error,TMCString* errorString, const char* file = 0, const int	line 	= 0 ) ;

		/// We do not want to allocate a new string in the new exception
		/// =>copies the e.fErrorString pointer into this.fErrorString
		///  and sets e.fErrorString to null.
		///
		TMCException				(const TMCException& e);
		
		~TMCException(void);		

		// MSC requires the assignment operator '=' be defined for any
		// class that requires it. It can't be inherited.
		const TMCException& operator=	(const TMCException& e);			

		// convert an exception into an MCErr.
		operator MCErr(void) const { return fError; }

		MCErr		GetError(void) const		{ return fError; }
		void		SetError(const MCErr err )	{ fError = err; }	

		const TMCString* GetErrorString() const { return fErrorString; }

		// retrieve information about the exception. - keeps ANSI happy
		virtual const char* what() const
			{ return fFile; } // don't really have a c-string message
		
	public:
		MCErr 		fError;   //See MCStatusCode.h kNoErr...kfontNotDeclared...
		const char* fFile;
		int	 		fLine;

		//The string is transfered from one exception to another by the copy constructor 
		//and deleted when the last exception is deleted 
		//(THROWAGAIN(_except) creates a new exception and copies the old one into it)
		mutable TMCString*	fErrorString;
};

/// \}

// use these macros to encapsulate the file/line with the exception
//	Example usage:
//
//		throw TMCException( err );
//		throw TMCException( EXCEPTION_ERR( err ) );
//		throw TMCException( EXCEPTION_ERR_MSG( err, "new failed") );

#define EXCEPTION_ERR( inErrID ) \
(inErrID), (__FILE__), (__LINE__)

/*
#define EXCEPTION_ERR_MSG( inErrID, inMessage )			\
	(inErrID), (TMCException::ErrMessageT)(inMessage), (__FILE__), (__LINE__)
*/

// various sordid macros to encapsulate the throw 

#define ThrowException( inErrID, inErrorString ) \
    throw TMCException( (inErrID), (inErrorString), (__FILE__), (__LINE__) );
 
#define ThrowIfNil(a) 											\
	if (!(a))													\
		throw TMCException( EXCEPTION_ERR( kNilPointerError ));	\
	else 														\
		0;

#define ThrowIfNoMem(a) 										\
	if (!(a))													\
		throw TMCException( EXCEPTION_ERR( kMemAllocError )); 	\
	else 														\
		0;

#define ThrowIfError(a) 							\
	if ((a) != kNoErr)								\
		throw TMCException( EXCEPTION_ERR( a ));	\
	else 											\
		0;

#define THROW_IF_ERR( inErr ) 							\
	if ( inErr )										\
		throw TMCException( EXCEPTION_ERR( inErr ) );	\
	else												\
		0;

#if Debug_ 
#define ThrowIfNilNonRelease(a) 								\
	if (!(a))													\
		throw TMCException( EXCEPTION_ERR( kNilPointerError ));	\
	else 														\
		0;
#else
#define ThrowIfNilNonRelease(a) 	
#endif

// obsolete macro definitions from the bygone years
#define TRY					try
#define CATCH				catch(TMCException&)
#define CATCH_ARG(_except)	catch(TMCException& _except)
#define THROWAGAIN(_except)	throw (_except)
#define THROW(a)			throw TMCException(a)

#define SUCCESS

#define DECLAREVOLATILE(a,b) a volatile b;



void CatchPlatformException(boolean doCatch);

#endif
