
/**
 * API for printing to a trace file.
 */

#include "gag_trace.h"

/*****************************************************************************
 *                            Dependencies                                   *
 *****************************************************************************/

#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>
#ifndef WIN32
#include <stdlib.h>
#include <unistd.h>
#if defined(linux)
#include <sys/syscall.h>
#endif
#else
#include "win32.h"
#endif
#include "gsys-message-c.h"

/*****************************************************************************
 *                        Macros & Definitions                               *
 *****************************************************************************/

#define GAG_TRACE_USE_GMESSAGE

#ifndef GAG_TRACE_USE_GMESSAGE
/* File descriptor of trace file */
static FILE *s_trace_fp = NULL;
#endif /* GAG_TRACE_USE_GMESSAGE */

/* Prefix for trace outputs */
static char s_trace_prefix[1024] = { '\0' };

/*****************************************************************************
 *                           Function bodies                                 *
 *****************************************************************************/

static int s_gag_get_pid( )
{
#ifndef WIN32
#if defined(linux)
    return syscall( SYS_gettid);
#else
    return getpid( );
#endif
#else
    return GetCurrentThreadId( );
#endif
}

static char *s_gag_date( )
{
    static char s_date[256];
    time_t t;

    time( &t);
    strftime( s_date, sizeof(s_date), "%d-%b-%Y %H:%M:%S", localtime( &t));
    return s_date;
}

static void s_gag_start()
{
    gag_trace( "<start> #### %s ####", s_gag_date( ));
    if (s_trace_prefix[0])
        gag_trace( "<process_id> %d", s_gag_get_pid( ));
}

/**
 * Open a trace file.
 *
 * @param[in] filename is the name of the file.
 * @param[in] prefix is the string inserted before each output line. If set to
 *            NULL, it is replaced by the process id.
 * @return true if trace file successfully opened.
 */
int gag_trace_open( const char *filename, const char *prefix)
{
#ifndef GAG_TRACE_USE_GMESSAGE
    if (s_trace_fp != NULL) {
        fprintf( stderr, "gag_trace_open: trace already opened !\n");
        return 0;
    }

    /* register gag_trace_close to be called on exit */
    atexit( gag_trace_close);

    if (!strcmp( filename, "-")) {
        s_trace_fp = stdout;
    } else {
        if (filename[0] == '+')
            s_trace_fp = fopen( filename + 1, "a");
        else
            s_trace_fp = fopen( filename, "w");
        if (s_trace_fp == NULL) {
            perror( "fopen");
            return 0;
        }
    }
#endif /* GAG_TRACE_USE_GMESSAGE */
    if (prefix != NULL)
        strcpy( s_trace_prefix, prefix);
    else
        s_trace_prefix[0] = '\0';
    s_gag_start( );
    return 1;
}

/**
 * Open trace file set in GAG_COMM_TRACE environment variable.
 *
 * @param[in] prog_name is used as prefix string for trace outputs.
 * @return true if trace file successfully opened.
 */
int gag_trace_activate( const char *prog_name)
{
    char *trace = getenv( "GAG_COMM_TRACE");
    if (trace == NULL)
        return 0;
    return gag_trace_open( trace, prog_name);
}

/**
 * Call gag_trace_activate with full command line.
 *
 * @param[in] argc is the argc argument of main().
 * @param[in] argv is the argv argument of main().
 * @return true if trace file successfully opened.
 */
int gag_trace_activate_args( int argc, char **argv)
{
    static char s_buf[1024];
    char *s;
    int i;
    int l;

    if (!argc)
        s = "";
    else if ((s = strrchr( argv[0], '/')) != NULL
    || (s = strrchr( argv[0], '\\')) != NULL)
        s++;
    else
        s = argv[0];
    if (!gag_trace_activate( s))
        return 0;

    l = 0;
    for (i = 1; i < argc; i++) {
        strcpy( s_buf + l, argv[i]);
        l += strlen( s_buf + l);
        s_buf[l++] = ' ';
    }
    if (l)
        s_buf[--l] = '\0';

    gag_trace( "<process_args> %s", s_buf);

    return 1;
}

/**
 * Close a opened trace file.
 */
void gag_trace_close( )
{
#ifndef GAG_TRACE_USE_GMESSAGE
    if (s_trace_fp != NULL) {
        gag_trace( "<end> #### %s ####", s_gag_date( ));
        fclose( s_trace_fp);
        s_trace_fp = NULL;
    }
#endif /* GAG_TRACE_USE_GMESSAGE */
}

/**
 * Print all arguments as a printf does in trace log file.
 *
 * @param[in] args is the variable argument list.
 */
void gag_trace( const char *args, ...)
{
    static char s_buf[GAG_MAX_MESSAGE_LENGTH];
    va_list l;

#ifndef GAG_TRACE_USE_GMESSAGE
    if (s_trace_fp == NULL)
        return;
#endif /* GAG_TRACE_USE_GMESSAGE */

    va_start( l, args);
    vsprintf( s_buf, args, l);
    va_end( l);
#ifdef GAG_TRACE_USE_GMESSAGE
    if (s_trace_prefix[0]) {
        gsys_c_message(seve_t, "TRACE", "%s: %s", s_trace_prefix, s_buf);
    } else {
        gsys_c_message(seve_t, "TRACE", "%d: %s", s_gag_get_pid( ), s_buf);
    }
#else /* GAG_TRACE_USE_GMESSAGE */
    fseek( s_trace_fp, 0L, SEEK_END);
    if (s_trace_prefix[0]) {
        fprintf( s_trace_fp, "%s: %s\n", s_trace_prefix, s_buf);
    } else {
        fprintf( s_trace_fp, "%d: %s\n", s_gag_get_pid( ), s_buf);
    }
    fflush( s_trace_fp);
#endif /* GAG_TRACE_USE_GMESSAGE */
}

/**
 * Get opened trace file pointer.
 *
 * @return file pointer.
 */
FILE *gag_trace_get_file_pointer( )
{
#ifdef GAG_TRACE_USE_GMESSAGE
    return NULL;
#else /* GAG_TRACE_USE_GMESSAGE */
    return s_trace_fp;
#endif /* GAG_TRACE_USE_GMESSAGE */
}

/**
 * Set trace file pointer.
 *
 * @param[in] fp is the file pointer.
 */
void gag_trace_set_file_pointer( FILE *fp)
{
#ifndef GAG_TRACE_USE_GMESSAGE
    s_trace_fp = fp;
    if (s_trace_fp != NULL) {
        s_gag_start( );
    }
#endif /* GAG_TRACE_USE_GMESSAGE */
}
