/*=============================================================================
	CAXException.h
	
	$Log: CAXException.h,v $
	Revision 1.13  2004/10/25 20:04:45  dwyatt
	allow null operation string
	
	Revision 1.12  2004/09/02 23:03:22  jcm10
	*** empty log message ***
	
	Revision 1.11  2004/08/23 06:23:25  jcm10
	make it build on Windows
	
	Revision 1.10  2004/04/06 01:00:21  dwyatt
	store operation string inside the exception
	
	Revision 1.9  2004/04/02 20:09:34  dwyatt
	once more
	
	Revision 1.8  2004/04/02 20:07:14  dwyatt
	CADebugMacros.h defines a "Throw" macro, I give
	
	Revision 1.7  2004/04/02 01:35:59  dwyatt
	oops
	
	Revision 1.6  2004/04/02 01:35:22  dwyatt
	make FormatError const
	
	Revision 1.5  2004/01/13 02:00:33  dwyatt
	moved from Source/Tests/AudioFileUtility/Utility/
	
	Revision 1.4  2003/08/23 04:54:00  dwyatt
	add XThrow, support for warnings
	
	Revision 1.3  2003/08/04 23:42:45  dwyatt
	add FormatError
	
	Revision 1.2  2003/07/25 23:16:47  dwyatt
	use constant strings for operations in CAXException
	
	Revision 1.1  2003/06/23 23:07:37  dwyatt
	initial checkin
	
	created Wed Jun 11 2003, Doug Wyatt
	Copyright (c) 2003 Apple Computer, Inc.  All Rights Reserved

	$NoKeywords: $
=============================================================================*/

#ifndef __CAXException_h__
#define __CAXException_h__

#if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
	#include <CoreServices/CoreServices.h>
#else
	#include <ConditionalMacros.h>
	#include <CoreServices.h>
#endif
#include "CADebugMacros.h"
#include <ctype.h>
#include <stdio.h>
#include <string.h>

// An extended exception class that includes the name of the failed operation
class CAXException {
public:
	CAXException(const char *operation, OSStatus err) :
		mError(err)
		{
			if (operation == NULL)
				mOperation[0] = '\0';
			else if (strlen(operation) >= sizeof(mOperation)) {
				memcpy(mOperation, operation, sizeof(mOperation) - 1);
				mOperation[sizeof(mOperation) - 1] = '\0';
			} else
				strcpy(mOperation, operation);
		}
	
	char *FormatError(char *str) const
	{
		return FormatError(str, mError);
	}
	
	char				mOperation[256];
	const OSStatus		mError;
	
	// -------------------------------------------------
	
	typedef void (*WarningHandler)(const char *msg, OSStatus err);
	
	/*static void Throw(const char *operation, OSStatus err)
	{
		throw CAXException(operation, err);
	}*/
	
	static char *FormatError(char *str, OSStatus error)
	{
		// see if it appears to be a 4-char-code
		*(UInt32 *)(str + 1) = EndianU32_NtoB(error);
		if (isprint(str[1]) && isprint(str[2]) && isprint(str[3]) && isprint(str[4])) {
			str[0] = str[5] = '\'';
			str[6] = '\0';
		} else
			// no, format it as an integer
			sprintf(str, "%ld", error);
		return str;
	}
	
	static void Warning(const char *s, OSStatus error)
	{
		if (sWarningHandler)
			(*sWarningHandler)(s, error);
	}
	
	static void SetWarningHandler(WarningHandler f) { sWarningHandler = f; }
private:
	static WarningHandler	sWarningHandler;
};

#if	DEBUG || CoreAudio_Debug
	#define XThrowIfError(error, operation) \
		do {																	\
			OSStatus __err = error;												\
			if (__err) {															\
				char __buf[12];													\
				DebugMessageN2("error %s: %4s\n", CAXException::FormatError(__buf, __err), operation);\
				STOP;															\
				throw CAXException(operation, __err);		\
			}																	\
		} while (0)

	#define XThrowIf(condition, error, operation) \
		do {																	\
			if (condition) {													\
				OSStatus __err = error;											\
				char __buf[12];													\
				DebugMessageN2("error %s: %4s\n", CAXException::FormatError(__buf, __err), operation);\
				STOP;															\
				throw CAXException(operation, __err);		\
			}																	\
		} while (0)

#else
	#define XThrowIfError(error, operation) \
		do {																	\
			OSStatus __err = error;												\
			if (__err) {															\
				throw CAXException(operation, __err);		\
			}																	\
		} while (0)

	#define XThrowIf(condition, error, operation) \
		do {																	\
			if (condition) {													\
				OSStatus __err = error;											\
				throw CAXException(operation, __err);		\
			}																	\
		} while (0)

#endif

#define XThrow(error, operation) XThrowIf(true, error, operation)
#define XThrowIfErr(error) XThrowIfError(error, #error)

#endif // __CAXException_h__
