#ifndef __SAL_DEBUG_DEFINES_HEADER
#define __SAL_DEBUG_DEFINES_HEADER

/*
 * libsal/debug/defines.h
 * Pre-processor macros for debugging
 *
 * DESCRIPTION:
 * 
 * 	The pre-processor macros defined in this file are used throughout
 * 	libsal for debugging purposes.
 * 
 * 	Original Author
 * 	===============
 * 	Stuart Herbert
 * 	Academic Computing Services, The University of Sheffield
 */

#include <errno.h>

#define SAL_DEBUG_INFO __FILE__, __LINE__

/* NOTE:
 * 	The values of these macros correspond DIRECTLY to an index into
 * 	the debugging message table in debug_misc.c
 */

#define SAL_DEBUG_MSG_START			-1

#define SAL_DEBUG_MSG_ERRORAUTHOR		0
#define SAL_DEBUG_MSG_ERRORRESOURCE		1
#define SAL_DEBUG_MSG_ERRORDATA			2

#define SAL_DEBUG_MSG_WARNING			3
#define SAL_DEBUG_MSG_INFO	       		4

#define SAL_DEBUG_MSG_DEBUGHIGH			5
#define SAL_DEBUG_MSG_DEBUGMEDIUM		6
#define SAL_DEBUG_MSG_DEBUGLOW			7

#define SAL_DEBUG_MSG_TRACE			8
#define SAL_DEBUG_MSG_INTERNAL			9

#define SAL_DEBUG_MSG_END			10

#ifdef assert
#undef assert
#endif

#define assert(x) \
  if (!(x)) sal_dprintf(SAL_DEBUG_INFO, SAL_DEBUG_MSG_ERRORAUTHOR, "Assertion failed: %s\n", #x)

#define assertnot(x) \
  if ((x)) sal_dprintf(SAL_DEBUG_INFO, SAL_DEBUG_MSG_ERRORAUTHOR, "Assertion failed: !(%s)\n", #x)

#define ENSURE_DATA(x, y)\
  if (!(x)) sal_dprintf(SAL_DEBUG_INFO, SAL_DEBUG_MSG_ERRORDATA, "Invalid data: %s failed test %s!\n", y, #x)

#define ENSURE_RESOURCE(x, y)\
  if (!(x)) sal_dprintf(SAL_DEBUG_INFO, SAL_DEBUG_MSG_ERRORRESOURCE, "Out of resource %s!\nErrno is %d\n", y, errno)

#define ENTER_FUNCTION(x)\
  sal_debug_CallStack_Push(SAL_DEBUG_INFO, x)

#define EXIT_FUNCTION\
  sal_debug_CallStack_Pop(SAL_DEBUG_INFO)

#define NEVER \
  sal_dprintf(SAL_DEBUG_INFO, SAL_DEBUG_MSG_ERRORAUTHOR, "This line should never have been reached.\n")

#define CALL_ONCE_ONLY \
  static int __sal_debug_iFlag = 0; \
  if (__sal_debug_iFlag != 0) sal_dprintf(SAL_DEBUG_INFO, SAL_DEBUG_MSG_ERRORAUTHOR, "Function called more than once!\n"); \
  __sal_debug_iFlag++

#define RUN_ONCE_ONLY(x) \
  static int __sal_debug_iFlag = 0; \
  if (__sal_debug_iFlag != 0) return (x); \
  __sal_debug_iFlag++;

#define RUN_ONCE_ONLY_VOID \
  static int __sal_debug_iFlag = 0; \
  if (__sal_debug_iFlag != 0) return; \
  __sal_debug_iFlag++;

#define TEST_ARG(x,y) \
  if (!(x)) sal_dprintf(SAL_DEBUG_INFO, SAL_DEBUG_MSG_ERRORAUTHOR, "Argument %s failed test '%s'\n", y, #x)

#endif /* __SAL_DEBUG_DEFINES_HEADER */
