/*=========================================================================
 *
 * GENERR.H - 18 January 1999, Dave Humphrey
 *
 * Some often used error handling related functions and routines.
 *
 *=======================================================================*/
#ifndef __GENERR_H
#define __GENERR_H

	/* Required Includes */
#include <stdlib.h>


/*=========================================================================
 *
 * Begin Definitions
 *
 *=======================================================================*/

	/* Program identification */
  #define GENERR_NAME    "GENERR.CPP"
  #define GENERR_VERSION "0.1b"
  #define GENERR_AUTHOR  "Dave Humphrey (uesp@m0use.net)"
  #define GENERR_DATE    "28 March 1999"

	/* Get the static global errorhandler variable from the function. This is
	 * done because we need to ensure the object is initialized before any custom
	 * errors are added to it during program startup. */
  #define ErrorHandler GetErrorHandler()

	/* Number of custom error definitions allowed at one time */
  #define MAX_CUSTOM_ERRORS 150

	/* Return value for an invalid custom error index */
  #define CUSTOM_ERROR_NOTFOUND -1

	/* Size of strings used to create error messages */
  #define MAX_ERRBUF_SIZE 256
  #define MAX_ERRMSG_SIZE 1024

	/* Default Custom Error Codes */
  #define ERR_NONE      0
  #define ERR_FILE      1
  #define ERR_READ      2
  #define ERR_WRITE     3
  #define ERR_MEM       4
  #define ERR_INDEX     5
  #define ERR_HEAP      6
  #define ERR_MAXINDEX  7
  #define ERR_NULL      8
  #define ERR_INPUT     9
  #define ERR_UINTMAX   10
  #define ERR_STRING    12
  #define ERR_OVERFLOW  13
  #define ERR_FILETYPE  14
  #define ERR_CUSTOM    15
  #define ERR_SYSTEM    20	/* Special case of system specific errors */
  #define ERR_WINDOWS   21
  #define ERR_D3D       22

	/* Notify type values */
  #define ERR_NOTIFY_NOTHING 0
  #define ERR_NOTIFY_LOG     1 
  #define ERR_NOTIFY_USER    2

	/* Default function definition to ensure the macro exists */
  #undef  __FUNC__
  #define __FUNC__ ""

	/* Macros to define custom class errors */
  #define BEGIN_CLASS_ERRORS(Class) boolean Class::AddCustomErrors (void) {
  #define ADD_CLASS_ERROR(Code, Msg, Level) ErrorHandler.AddError(Code, Msg, Level);
  #define END_CLASS_ERRORS()	    return (TRUE); }
  #define DEFINE_CLASS_ERRORS()	    virtual static boolean AddCustomErrors (void);
  
	/* Shortcuts to setting the extended error information */
  #define SET_EXT_ERROR(Code)				SET_EXT_ERROR6(Code, NULL, NULL, NULL, NULL, NULL)
  #define SET_EXT_ERROR2(Code, Msg)			SET_EXT_ERROR6(Code,  Msg, NULL, NULL, NULL, NULL)
  #define SET_EXT_ERROR3(Code, Msg, V1)			SET_EXT_ERROR6(Code,  Msg,   V1, NULL, NULL, NULL)
  #define SET_EXT_ERROR4(Code, Msg, V1, V2)		SET_EXT_ERROR6(Code,  Msg,   V1,   V2, NULL, NULL)
  #define SET_EXT_ERROR5(Code, Msg, V1, V2, V3)		SET_EXT_ERROR6(Code,  Msg,   V1,   V2,   V3, NULL)
  #define SET_EXT_ERROR6(Code, Msg, V1, V2, V3, V4)	{ ErrorHandler.SetExtError(Code, __FILE__, __FUNC__, __LINE__, Msg, V1, V2, V3, V4); }

	/* Shortcut to setting windows error information */
  #define SET_WIN_ERROR()				SET_WIN_ERROR6(NULL, NULL, NULL, NULL, NULL)
  #define SET_WIN_ERROR2(Msg)				SET_WIN_ERROR6( Msg, NULL, NULL, NULL, NULL)
  #define SET_WIN_ERROR3(Msg, V1)			SET_WIN_ERROR6( Msg,   V1, NULL, NULL, NULL)
  #define SET_WIN_ERROR4(Msg, V1, V2)			SET_WIN_ERROR6( Msg,   V1,   V2, NULL, NULL)
  #define SET_WIN_ERROR5(Msg, V1, V2, V3)		SET_WIN_ERROR6( Msg,   V1,   V2,   V3, NULL)
  #define SET_WIN_ERROR6(Msg, V1, V2, V3, V4)		{ ErrorHandler.SetExtError(ERR_WINDOWS, __FILE__, __FUNC__, __LINE__, Msg, V1, V2, V3, V4); }

	/* Shortcuts to setting Direct3D/DirectDraw error information */
  #define SET_D3D_ERROR(Code)				SET_D3D_ERROR6(Code, NULL, NULL, NULL, NULL, NULL)
  #define SET_D3D_ERROR2(Code, Msg)			SET_D3D_ERROR6(Code,  Msg, NULL, NULL, NULL, NULL)
  #define SET_D3D_ERROR3(Code, Msg, V1)			SET_D3D_ERROR6(Code,  Msg,   V1, NULL, NULL, NULL)
  #define SET_D3D_ERROR4(Code, Msg, V1, V2)		SET_D3D_ERROR6(Code,  Msg,   V1,   V2, NULL, NULL)
  #define SET_D3D_ERROR5(Code, Msg, V1, V2, V3)		SET_D3D_ERROR6(Code,  Msg,   V1,   V2,   V3, NULL)
  #define SET_D3D_ERROR6(Code, Msg, V1, V2, V3, V4)	{ ErrorHandler.SetD3DError(Code); ErrorHandler.SetExtError(ERR_D3D, __FILE__, __FUNC__, __LINE__, Msg, V1, V2, V3, V4); ErrorHandler.SetD3DError(Code); }


	/* Create an assertion macro if required */
#ifndef ASSERT

		/* Assert macro exists only in debug version */ 
  #if defined(DEBUG) || defined(__DEBUG) || defined(_DEBUG)
    #define ASSERT(exp) if (!(exp)) { CustomAssert(#exp, __FILE__, __FUNC__, __LINE__); }
  #else
    #define ASSERT(exp)
  #endif

#endif

/*=========================================================================
 *		End of Definitions
 *=======================================================================*/


/*=========================================================================
 *
 * Begin Type Definitions
 *
 *=======================================================================*/

	/* Define the type used to store an error code value */
  typedef long errnum_t;

	/* The type used to store an error code severity level */
  typedef enum { EL_UNKNOWN  = 0,	/* Unknown error level */
		 EL_INFO     = 1,	/* An informative message */
		 EL_WARNING  = 2,	/* A warning */
		 EL_ERROR    = 3,	/* A general error message */
		 EL_CRITICAL = 4	/* A critical error */
	} errlevel_t;

/*=========================================================================
 *		End of Type Definitions
 *=======================================================================*/

 
/*===========================================================================
 *
 * Class CErrorRecord Definition
 *
 * This class holds one custom error definition.  The class is used only
 * by the class CErrorHandler, to which it is friends.
 *
 *=========================================================================*/	
class CErrorRecord {
  friend class CErrorHandler;

  /*---------- Begin Protected Class Members ----------------------*/
protected:
  errnum_t   Code;	/* The error code */
  errlevel_t Level;	/* The severity of the error */
  char *     pDesc;	/* The description of the error */


  /*---------- Begin Public Class Methods ------------------------*/
public:

	/* Class Constructor and Destructor */
  CErrorRecord (void);
  ~CErrorRecord (void) { Destroy(); }

	/* Pseudo-Destructor, clears and resets all values */
  void Destroy (void);

	/* Return the various member values */
  errnum_t   GetCode  (void)  { return (Code); }
  errlevel_t GetLevel (void)  { return (Level); }
  char*      GetDesc  (void)  { return (pDesc); }

	/* Set the various member values */
  void SetCode  (const errnum_t   NewCode)  { Code  = NewCode; }
  void SetLevel (const errlevel_t NewLevel) { Level = NewLevel; }
  void SetDesc  (const char*      pString)  { DestroyPointer(pDesc); pDesc = CreateString(pString); }

 };
/*===========================================================================
 *		End of Class CErrorRecord Definition
 *=========================================================================*/


/*===========================================================================
 *
 * Class CErrorHandler Definition
 *
 * This class is the main class used for handling all the various types of
 * errors through one consistent interface.  It supports the default errors
 * available to the system and any user defined errors as well.
 *
 *=========================================================================*/
class CErrorHandler {

  /*---------- Begin Protected Class Members ----------------------*/
protected:

  CErrorRecord* pCustomErrors[MAX_CUSTOM_ERRORS];	/* A list of custom error messages */
  int           NumCustomErrors;			/* Number of custom error messages currently defined */

  errnum_t      ErrorCode;		/* The value of the current custom error code */
  errnum_t      SystemErrorCode;	/* The value of the current system error code */
  errnum_t      WindowsErrorCode;	/* The value of the current windows error code */
  errnum_t	D3DErrorCode;		/* Value of the current D3D error code */

  long    ErrorLine;			/* The optional line the error occured on */
  char*   pErrorFile;			/* The optional file the error occured in */
  char*   pErrorFunction;		/* The optional function the error occured in */
  char*   pErrorMessage;		/* The optional message specified by the user */

  int     NotifyType;			/* What to do upon a notify call */
  boolean NotifiedUser;			/* Has the user been notified of the last error? */

	/* Allow exporting of class commands */
  //DECLARE_COMMAND_FUNCMAP()


  /*---------- Begin Protected Class Methods ----------------------*/
protected:

  	/* Searches custom error array for a matching error code */
  int FindCustomError (const errnum_t ErrCode);

    	/* Returns a non-NULL pointer to the d3d-type error message */
  char *GetD3DErrorMessage (char *pString);

	/* Returns a non-NULL pointer to the system error message */
  char *GetSystemErrorMessage (char *pString);

  	/* Returns a non-NULL pointer to the windows error message */
  char *GetWindowsErrorMessage (char *pString);


  /*---------- Begin Public Class Methods -------------------------*/
public:

	/* The Class Constructor and Destructor */
  CErrorHandler (void);
  ~CErrorHandler (void) { Destroy(); }

	/* Add a new custom error to the class data */
  boolean AddError (const errnum_t NewCode, const char* pNewDesc, const errlevel_t NewLevel = EL_ERROR);

	/* Deletes any allocated data and resets all values */
  void Destroy (void);

	/* Outputs error message to user and exits program */
  void Exit (const char *pString, ...);

	/* Returns the value of the current error code and level */
  errnum_t   GetErrorCode  (void);
  errlevel_t GetErrorLevel (void);

	/* Return error string based on given error code */
  char* GetErrorMessage (void);
  char* GetErrorMessage (const errnum_t NewError) { SetError(NewError); return (GetErrorMessage()); }

	/* Get the current extended error information */
  char* GetExtErrorMessage  (void) { return (pErrorMessage); }
  char* GetExtErrorFile     (void) { return (pErrorFile); }
  char* GetExtErrorFunction (void) { return (pErrorFunction); }
  long  GetExtErrorLine     (void) { return (ErrorLine); }

	/* Has the user been notified of the last error? */
  boolean HaveNotifiedUser (void) { return (NotifiedUser); }

	/* Returns TRUE if error code is a valid one */
  boolean IsError (void) { return (ErrorCode == ERR_NONE ? FALSE : TRUE); }

	/* Outputs error message to user */
  void Notify (const char *pString = NULL, ...);

	/* Output error information to a file stream */
  boolean OutputLog (FILE* pFileHandle = NULL);

	/* Sets the current values for the error code */
  void SetError    (const errnum_t NewCode = ERR_NONE);
  void SetExtError (const errnum_t NewCode, const char* pFile, const char* pFunc, const long LineNum);
  void SetExtError (const errnum_t NewCode, const char* pFile, const char* pFunc, const long LineNum, const char* pMsg, ...);
  void SetFunction (const char* pString) { DestroyPointer(pErrorFunction); pErrorFunction = CreateString(pString); }
  void SetFile     (const char* pString) { DestroyPointer(pErrorFile);	   pErrorFile = CreateString(pString); }
  void SetMessage  (const char* pString) { DestroyPointer(pErrorMessage);  pErrorMessage = CreateString(pString); }
  void SetLine     (const long     Line) { ErrorLine = Line; }
  void SetWindowsError (const errnum_t NewCode);
  void SetD3DError     (const errnum_t NewCode);
  
	/* Change the notify type */
  void SetNotifyType (const int NewType) { NotifyType = NewType; }
  	
 };
/*===========================================================================
 *		End of Class CErrorHandler Definition
 *=========================================================================*/


/*=========================================================================
 *
 * Begin External Variable Definitions
 *
 *=======================================================================*/

/*=========================================================================
 *		End of External Variable Definitions
 *=======================================================================*/


/*=========================================================================
 *
 * Begin Forward Function/Procedure Declarations
 *
 *=======================================================================*/

	/* A custom assert procedure used if one not supplied by system */
  void CustomAssert (const char *pString, const char *pFile, const char* pFunc, const int Line);

	/* Get the global error handler variable */
  CErrorHandler& GetErrorHandler (void);

	/* Converts a error level value to a string */
  char *ErrorLeveltoStr (const errlevel_t Level);

/*=========================================================================
 *		End of Forward Function/Procedure Declarations
 *=======================================================================*/


#endif
/*=========================================================================
 *		End of File GENERR.H
 *=======================================================================*/