/*	XError.h
 *
 *		Standardized error handling mechanism.
 *
 *		There are three types of errors that can happen. The first are
 *	"fatal errors" which cause an exception to be thrown upwards. This
 *	should be done when something happens that prevents processing from
 *	continuing.
 *
 *		The second are "caution" alerts which give the user the option
 *	to interrupt processing. This is handled by a standard routine
 *	which posts the appropriate error and throws an exception if
 *	needed.
 *
 *		The third are "warnings" which throw up an alert but does not
 *	interrupt the flow of processing.
 */

/*  YAAF - Yet another application framework
 *  Copyright (C) 1997, 1998 William Edward Woody
 *  
 *  This library is free software; you can redistribute it
 *  and/or modify it under the terms of the GNU Library
 *  General Public License as published by the Free Software
 *  Foundation; either version 2 of the License, or any
 *  later version.
 *  
 *  This library is distributed in the hope that it will be
 *  useful, but WITHOUT ANY WARRANTY; without even the implied
 *  warranty of MERCHANTABIILITY or FITNESS FOR A PARTICULAR
 *  PURPOSE. See the GNU Library General Public License for
 *  more details.
 *  
 *  You should have received a copy of the GNU Library General
 *  Public License along with this library; if not, write to the
 *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 *  Boston, MA 02111-1307, USA.
 *  
 *  To contact the author, either e-mail me at woody@pandawave.com, 
 *	or write to
 *  
 *          William Edward Woody
 *          In Phase Consulting
 *          1545 Ard Eevin Avenue
 *          Glendale, CA 91202
 *
 *	Or visit us on the web at http://www.pandawave.com
 */

#ifndef PandaWave_XERROR
#define PandaWave_XERROR

#include <XConfig.h>
#include <XDataUtil.h>
#include <stdarg.h>					// XGPostError varargs

/************************************************************************/
/*																		*/
/*	Enumeration Objects													*/
/*																		*/
/************************************************************************/

/*	XGAlertType
 *
 *		This controls the type of alert that XGPostError puts up.
 *	By default this is the 'fatal' error alert, which is used when
 *	processing was interrupted.
 */

enum XGAlertType {
	KXGAlertFatal = 1,
	KXGAlertCaution = 2,
	KXGAlertWarning = 3
};

/************************************************************************/
/*																		*/
/*	Error Codes															*/
/*																		*/
/************************************************************************/

#define KXGYAAFErrorCodes		128

/*	XGErrorCode
 *
 *		Used in place of a string for internationalization support.
 */

#define KXGOutMemory			MAKEDWORD(KXGYAAFErrorCodes,0)
#define KXGAssertError			MAKEDWORD(KXGYAAFErrorCodes,1)
#define KXGStringListError		MAKEDWORD(KXGYAAFErrorCodes,2)	// XGStringList
#define KXGStringListExtra		MAKEDWORD(KXGYAAFErrorCodes,3)
#define KXGPreferenceError		MAKEDWORD(KXGYAAFErrorCodes,4)
#define KXGThreadCreateError	MAKEDWORD(KXGYAAFErrorCodes,5)
#define KXGThreadNotSupported	MAKEDWORD(KXGYAAFErrorCodes,6)
#define KXGRandomException		MAKEDWORD(KXGYAAFErrorCodes,7)
#define KXGWindowFactoryError	MAKEDWORD(KXGYAAFErrorCodes,8)
#define KXGSingleAppError		MAKEDWORD(KXGYAAFErrorCodes,9)
#define KXGSingleAppDupError	MAKEDWORD(KXGYAAFErrorCodes,10)
#define KXGAppCoreError			MAKEDWORD(KXGYAAFErrorCodes,11)
#define KXGViewFactoryError		MAKEDWORD(KXGYAAFErrorCodes,12)
#define KXGPrintError			MAKEDWORD(KXGYAAFErrorCodes,13)
#define KXGPrintChooser			MAKEDWORD(KXGYAAFErrorCodes,14)


/************************************************************************/
/*																		*/
/*	Standard Error Objects												*/
/*																		*/
/************************************************************************/

/*	@C"XGError"
 *  @H"XError.h"
 *  @I
 *
 *		This is a standard error handling class which is used to specify
 *	how errors are to be handled.
 *
 *		Okay, here's the deal. At the top of the event loop, if my
 *	library catches the event, I will attempt to call the 'DoAlert'
 *	method, and then continue on the loop. This allows me to present
 *	a meaningful error message when the error passes up to me. All
 *	other exceptions that are punted to me that are not a descendant
 *	of the XGError class will present a "unknown error" exception
 *
 *		This is an abstract class; you must override the three public
 *	methods below in order to instantiate an actual class.
 */

class XGError {
	public:
								XGError();
		virtual					~XGError();
		
		/*	@F"XGError::DisplayError"
		 *	@I
		 *		This abstract method is called by YAAF when
		 *	an exception of type XGError is caught.
		 */
		
		virtual void			DisplayError(void) = 0;

		/*	@F"XGError::GetShortError"
		 *	@I
		 *		This abstract method returns the "short"
		 *	error message. This is used to get the short
		 *	error description.
		 */
		
		virtual void			GetShortError(char *) = 0;

		/*	@F"XGError::GetLongError"
		 *	@I
		 *		This abstract method returns the "long"
		 *	error message. This is used to get a detailed
		 *	description of the error.
		 */
		
		virtual void			GetLongError(char *) = 0;
};

/************************************************************************/
/*																		*/
/*	Standard errors														*/
/*																		*/
/************************************************************************/

/*	@C"XGAbort"
 *  @H"XError.h"
 *  @D"XGError"
 *  @I
 *
 *		Throw this object to abort. This does nothing for the 'DoAlert'
 *	method--which means that this is a great way to quietly abort
 *	some processing or another
 */

class XGAbort : public XGError {
	public:
								XGAbort();
		
		/*
		 *	Standard punt
		 */
		
		virtual void			DisplayError(void);
		virtual void			GetShortError(char *);
		virtual void			GetLongError(char *);
};

/*	@C"XGPostError"
 *	@H"XError.h"
 *	@D"XGError"
 *	@I
 *
 *		Post an error message. This is the mechanism that YAAF
 *	uses to post errors.
 *
 *		NOTE: The XGAlertType parameter in the constructor is used
 *	with the Caution() and Warning() routines (below).
 */

class XGPostError : public XGError {
	public:
								XGPostError();
								XGPostError(unsigned long,...);
								XGPostError(unsigned long, va_list);
								
		// @G"Public Methods"

		/*	@F"XGPostError::SetAlertType"
		 *	@I
		 *		This is used internally by YAAF to set the type
		 *	of error alert that is thrown up when DisplayError
		 *	is called.
		 */
		 
		void					SetAlertType(XGAlertType a)
									{
										fType = a;
									}

		/*
		 *	Post error message
		 */
		
		virtual void			DisplayError(void);
		virtual void			GetShortError(char *);
		virtual void			GetLongError(char *);
		
		/*
		 *	'Caution' alert support
		 */
		
		/*	@F"XGPostError::GetAlertResult"
		 *	@I
		 *		This is used internally by YAAF to determine
		 *	if the cancel alert returns 'OK' or 'Cancel'
		 */
		
		static bool				GetAlertResult()
									{
										return gResult;
									}

	protected:
		/*
		 *	Setting the message (for my child classes)
		 */
		
		void					SetMessage(unsigned long, ...);
		void					SetMessage(unsigned long, va_list);

		static char				gSMessage[];
		static char				gLMessage[];
		static bool				gResult;
		XGAlertType				fType;
};

/************************************************************************/
/*																		*/
/*	Platform specific error reporting									*/
/*																		*/
/************************************************************************/

#if OPT_MACOS == 1

/*	@C"XGPostMacOSError"
 *  @H"XError.h"
 *	@D"XGPostError"
 *	@I
 *
 *		Post the Macintosh OS Error. This loads the error message from
 *	a resource file in my resource fork. If that error resource is not
 *	present, this punts the error message
 */

class XGPostMacOSError : public XGPostError {
	public:
								XGPostMacOSError(OSErr, unsigned long, ...);
		
		/*
		 *	Error management
		 */
		
		static void				GetErrorString(OSErr,char *);
		virtual void			GetLongError(char *);

	private:
		OSErr					fErrorID;
};

#endif

#if OPT_WINOS == 1

/*	@C"XGPostWinOSError"
 *  @H"XError.h"
 *	@D"XGPostError"
 *	@I
 *
 *		Post a Windows OS Error. This gets the error string from the
 *	Windows API function ::FormatMessage(), and assumes the error
 *	message is derived from ::GetLastError().
 */

class XGPostWinOSError : public XGPostError {
	public:
								XGPostWinOSError(DWORD, unsigned long,...);
	
		/*
		 *	Simplified interface to ::FormatMessage()
		 */
		
		static void				GetErrorString(DWORD,char *);
		virtual void			GetLongError(char *);
	
	private:
		DWORD					fErrorID;
};

#endif

#if OPT_XWIN == 1

/*	@C"XGPostUnixOSError"
 *  @H"XError.h"
 *	@D"XGPostError"
 *	@I
 *
 *		Post a Unix OS Error. This gets the error string from the
 *	Posix function ::strerror(), and assumes the error
 *	message is derived from errno.
 */

class XGPostUnixOSError : public XGPostError {
	public:
								XGPostUnixOSError(int, unsigned long,...);
	
		/*
		 *	Simplified interface to ::FormatMessage()
		 */
		
		static void				GetErrorString(int,char *);
		virtual void			GetLongError(char *);

	private:
		int						fErrorID;
};

#endif

/************************************************************************/
/*																		*/
/*	Routines															*/
/*																		*/
/************************************************************************/

extern void Error(unsigned long,...);
extern bool Caution(unsigned long,...);
extern void Warning(unsigned long,...);
extern void Message(const char *title, const char *smsg, const char *lmsg, ...);

/************************************************************************/
/*																		*/
/*	Assertion Macros													*/
/*																		*/
/************************************************************************/

/*	_InlineError
 *
 *		To make the Assert macro a legal expression
 */

inline int _InlineError(char *a, char *f, long l)
{
	throw XGPostError(KXGAssertError,a,f,l);
	return 0;
}

/*	@F"Assert"
 *	@U"Assert(conditional)"
 *	@H"XError.h"
 *	@I
 *
 *		This macro expands to a function which handles program
 *	asserts. If there is a problem, this throws an error and 
 *  unwinds, rather than halting the program
 */

#define Assert(x)	((x) ? 0 : _InlineError(#x,__FILE__,(long)__LINE__))
											   

#endif // PandaWave_XERROR
