#ifndef __NQS_GENERIC_DEBUG_HEADER
#define __NQS_GENERIC_DEBUG_HEADER

/*
 * nqs_generic/all-systems/debug.h
 * Debugging support for Monsanto-NQS
 * 
 * Adapted from Sheffield NQS v4.0 (and hence greatly cut down)
 * For use with Monsanto-NQS v3.50 and greater
 */

#include <nqs_generic/license.h>
  /* NQS license information */
#include <nqs_generic/Catalogue.h>
  /* message catalogue for debugging */
#include <stdarg.h>
  /* used for variable argument passing */

#define UFCD_DEBUG_INDENT	2
#define UFCD_MAX_DUMPDEPTH 	5

/*
 * Debugging message types
 *
 * NOTE macro values are an index into UFCT_ErrorTable (in debug.c)
 */

#define UFCD_MESS_AUTHOR	0
#define UFCD_MESS_DATA		1
#define UFCD_MESS_RESOURCE	2
#define UFCD_MESS_LOG		3
#define UFCD_MESS_DEBUGHIGH	4
#define UFCD_MESS_DEBUGMEDIUM	5
#define UFCD_MESS_DEBUGLOW	6
#define UFCD_MESS_TRACE		7

/*
 * Error table - maps macros to data
 */
struct TAG_UFCT_ErrorTable
{
  const char *szPrefix;
    /* a prefix message to go into the logs */
  unsigned int uiShowAtAll;
    /* show message if Debug is >= this value */
  unsigned int uiShowTrace;
    /* show function trace etc if Debug is >= this value */
  unsigned int uiShowWhere;
    /* show file and line values if Debug >= this value */
  unsigned int uiSyslogAction;
    /* what to tell syslog (if we are using it) */
  int boShowAuthor;
    /* do we want to tell the user to contact the author? */
  int boFatal;
    /* do we terminate the program? */
};

typedef struct TAG_UFCT_ErrorTable UFCT_ErrorTable;

/*
 * Structure for function tracing
 */

struct TAG_UFCT_TraceHandle
{
  char		*szFile;
    /* source code filename */
  unsigned int	 uiLine;
    /* line in the file where the function was entered */
  char		*szFunction;
    /* function name */
  struct TAG_UFCT_TraceHandle *pstNext;
    /* pointer to next function in the list */
};

typedef struct TAG_UFCT_TraceHandle UFCT_TraceHandle;

/*
 * Internal debugging API
 */

extern void UFCF_DebugMessage (const char *, uInt, UFCC_Handle *, uInt, const char *, va_list);
extern void UFCF_DebugSyslog  (uInt, const char *, ...);
extern void UFCF_DebugvSyslog (uInt, const char *, va_list);
extern void UFCF_DebugStderr  (uInt, const char *, ...);
extern void UFCF_DebugvStderr (uInt, const char *, va_list);

/*
 * Macros
 */

#define DEBUG_LOW	UFCD_MESS_DEBUGLOW
#define DEBUG_MEDIUM	UFCD_MESS_DEBUGMEDIUM
#define DEBUG_HIGH	UFCD_MESS_DEBUGHIGH

#define INFO \
  __FILE__, __LINE__

/*
 * External debugging API
 *
 * Implementation is in nqs_generic/all-systems/debug.c
 */

#define ENTER_FUNCTION(name) \
  UFCF_EnterFunction(__FILE__, __LINE__, name, NULL)
  /* wrapper macro for UFCF_EnterFunction */

#define EXIT_FUNCTION \
  UFCF_ExitFunction(__FILE__, __LINE__)
  /* wrapper macro for UFCF_ExitFunction */

extern void DEBUGGING	   (const char *, unsigned int, unsigned int, const char *, ...);
  /* log a debugging message of a given priority */
extern void ERROR_AUTHOR   (const char *, unsigned int, const char *, ...);
  /* report an error - normally a piece of code which should not be reached */
extern void ERROR_DATA     (const char *, unsigned int, const char *, ...);
  /* report an error - normally corrupted data */
extern void ERROR_RESOURCE (const char *, unsigned int, const char *, ...);
  /* report an error - normally a missing file, or lack of memory */
extern void LOG		   (const char *, uInt,                const char *, ...);
  /* log a message, for example application name and version */
extern void InitLogging (void);
  /* setup the debugging/logging facilities */
extern void TRACE	   (const char *, uInt,                const char *, ...);
  /* log a message for debugging purposes */
extern void UFCF_EnterFunction (const char *, uInt, const char *, UFCT_VarTable *);
  /* report that a function has been entered */
extern void UFCF_ExitFunction  (const char *, uLong);
  /* report that the function has been exited */

/*
 * Assert() - test for bad data
 */
#define Assert(f)\
  if (!(f)) ERROR_AUTHOR(INFO, GET_MESSAGE(UFCM_ERRD_ASSERT), (#f))

#define NEVER\
  ERROR_AUTHOR(INFO, GET_MESSAGE(UFCM_ERRD_NEVER))

#define ENSURE_AUTHOR(f,g) \
  if (!(f)) ERROR_AUTHOR(INFO, GET_MESSAGE(g))

#define ENSURE_RESOURCE(f,g)\
  if (!(f)) ERROR_RESOURCE(INFO, NULL, GET_MESSAGE(g))

#define ENSURE_DATA(f,g)\
  if (!(f)) ERROR_DATA(INFO, GET_MESSAGE(g))

#define TEST_ARG(f,g)\
  if (!(f)) ERROR_AUTHOR(INFO, GET_MESSAGE(UFCM_ERRD_ARG), (g), (#f))

#endif /* __NQS_GENERIC_DEBUG_HEADER */
