/**
 * @file debug.h
 * @brief Macros for trace, debug, error, and assert.  (December 1, 2005)
 *
 * Define JVD_TRACE_ON, JVD_DEBUG_ON, JVD_ERROR_OFF, and/or JVD_ASSERT_OFF to
 * enable functionality.
 *
 * @author Joshua V. Dillon <jvdillon AAT purdue DDOT edu>
 */


#ifndef DEBUG_H
#define DEBUG_H

#include <stdio.h>

/* JVD: colors "[file:line]" and "function()".
 * \033[x,y,zm
 *    where: x:=attribute (attribcode)
 *           y:=foreground color (30 + colorcode)
 *           z:=background color (40 + colorcode)
 * RESET  BRIGHT DIM    UNDERLINE BLINK REVERSE HIDDEN 
 * 0      1      2      3	  4     7       8
 * BLACK  RED    GREEN  YELLOW    BLUE  MAGENTA CYAN    WHITE   NONE
 * 0      1      2      3         4     5       6       7       10
 */ 
#define TRACE_HEADER  "\033[1;32;40m[%s:%d] \033[1;31;40m%s(): \033[0m"
#define DEBUG_HEADER  "\033[1;34;40m[%s:%d] \033[1;31;40m%s(): \033[0m"
#define ERROR_HEADER  "\033[1;33;40m[%s:%d] \033[1;31;40m%s(): \033[0m"
#define ASSERT_HEADER "\033[1;33;40m[%s:%d] \033[1;31;40m%s(): \033[0m"


/**
 * jvd_trace
 * @brief Print (stdout) filename, line, variable name, and value.
 *
 * @param x variable to trace
 * @param format print directives (see fprintf for codes)
 */
#ifdef JVD_TRACE_ON
   #ifdef __STDC__
      #define jvd_trace(x,format) \
         fprintf(stdout,TRACE_HEADER #x " = %" #format "\n",       \
                        __FILE__,__LINE__,__FUNCTION__,x)
   #else
      #define jvd_trace(x,format) \
         fprintf(stdout,#x " = %" #format "\n",x)
   #endif
#else
   #define jvd_trace(x,format) (void)0
#endif


/**
 * jvd_debug
 * @brief Print (stderr) filename, line, and formatted string matched to args.
 *
 * @param format print directive string (see sprintf)
 * @param args variadic arguments matched to format string
 */
#ifdef JVD_DEBUG_ON
   #ifdef __STDC__
      #define jvd_debug(format,args...)                 \
         fprintf(stderr, DEBUG_HEADER format "\n",       \
                 __FILE__,__LINE__,__FUNCTION__,##args)
   #else
      #define jvd_debug(format,args...) \
         fprintf(stderr,format "\n",##args)
   #endif
#else
   #define jvd_debug(format,args...) (void)0
#endif


/**
 * jvd_error
 * @brief Print (stderr) filename, line, and formatted string matched to args.
 *
 * Note: automatically enable unless its NOT defined.
 *
 * @param format print directive string (see sprintf)
 * @param args variadic arguments matched to format string
 */
#ifndef JVD_ERROR_OFF
   #ifdef __STDC__
      #define jvd_error(format,args...)                 \
         fprintf(stderr, ERROR_HEADER format "\n",       \
                 __FILE__,__LINE__,__FUNCTION__,##args)
   #else
      #define jvd_error(format,args...) \
         fprintf(stderr,format "\n",##args)
   #endif
#else
   #define jvd_error(format,args...) (void)0
#endif


/**
 * jvd_assert
 * @brief On failure, print (stderr) filename, line, condition and then abort.
 *
 * @param cond conditional upon which abort is contingent
 */
#ifndef JVD_ASSERT_OFF
   #ifdef __STDC__
      #define jvd_assert(cond)   ( (cond) ? (void)0 :             \
         (fprintf(stderr,ASSERT_HEADER "assertion failed: %s\n",    \
                  __FILE__,__LINE__,__FUNCTION__,#cond))?abort():abort() )
   #else
      #define jvd_assert(cond)   ( (cond) ? (void)0 :   \
         ( fprintf(stderr,"assertion failed: %s\n",     \
                   #cond))?abort():abort() )
   #endif
#else
   #define jvd_assert(cond) (void)0
#endif

#endif

