#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>

#include "amdms.h"

/* The function gettimeofday() has a different prototype under SUN and HP:   */
/*    HP : int gettimeofday(struct timeval *, struct timezone *);            */
/*    SUN: int gettimeofday(struct timeval);                                 */
/* but the second one is not use in out code.                                */
/* We define the macro vlt_gettimeofday().                                   */
/* This is correctly mapped depending on the architerture                    */
/* The function is defined (along with is own data structures) in sys/time.h */
/* that is included here, although not POSIX.                                */
/* We have also taken into account that timeval and timezone could have been */
/* already defined because of the inclusion of <sys/time.h> or of the RTAP   */
/* portability include file crPortable.h                                     */

#ifdef HP_COMP                  /* don't use HP/IBM/DEC timezone parameter */
#if !defined(crTIMEVAL_TIMEZONE_DEFINED)
struct timeval {
    unsigned long	tv_sec;		/* seconds */
    long		        tv_usec;	/* and microseconds */
};
struct timezone {
    int	tz_minuteswest;	/* minutes west of Greenwich */
    int	tz_dsttime;	/* type of dst correction */
};
#endif

int gettimeofday(struct timeval *tp, struct timezone *tzp);
#define vlt_gettimeofday(tp) gettimeofday((tp),NULL)
#else 
#ifdef SUN_COMP            /* SUN has no timezone parameter */
#if !defined(_SYS_TIME_H) || !defined(crTIMEVAL_TIMEZONE_DEFINED)
struct timeval {
    long	tv_sec;		/* seconds */
    long	tv_usec;	/* and microseconds */
};
#endif
int gettimeofday(struct timeval *tp);
#define vlt_gettimeofday(tp) gettimeofday(tp)
#endif
#ifdef LINUX            /* SUN has no timezone parameter */
#if !defined(_SYS_TIME_H)
struct timeval {
    long	tv_sec;		/* seconds */
    long	tv_usec;	/* and microseconds */
};
struct timezone {
    int	tz_minuteswest;	/* minutes west of Greenwich */
    int	tz_dsttime;	/* type of dst correction */
};
#endif
int gettimeofday(struct timeval *tp, struct timezone *tzp);
#define vlt_gettimeofday(tp) gettimeofday((tp),NULL)
#endif
#endif

/* AMBER specific definitions */

amdmsEVENT amdmsLastEvent = {"", amdmsDEBUG, NULL, -1, ""};
int amdmsOnlyMessage = 0;
static int supressFlag = 0;
static amdmsSEVERITY severityLevel = amdmsERROR;

static void amdmsGetTimeStamp(char *timeStamp);

void amdmsSupressLogMessages(int flag)
{
  supressFlag = flag;
}

void amdmsShowOnlyMessage(int flag)
{
  amdmsOnlyMessage = flag;
}

void amdmsSetSeverityLevel(amdmsSEVERITY level)
{
  severityLevel = level;
}

void amdmsGetTimeStamp(char *timeStamp)
{
  struct timeval tv;
  struct tm  *brokenTime;
  char strTime[32];

  timeStamp[0] = '\0';
  gettimeofday(&tv, NULL);
  brokenTime = localtime((const time_t *)&tv.tv_sec);   
  strftime(strTime, 24, "%Y-%m-%d  %H:%M:%S", brokenTime);         
  sprintf(timeStamp, "%s.%6.6ld", strTime, tv.tv_usec);
}

void amdmsFatal(const char *file, int line, const char *format, ...)
{
  va_list        va_parList;
  
  if (severityLevel > amdmsFATAL) {
    return;
  }
  amdmsGetTimeStamp(amdmsLastEvent.timeStamp);
  amdmsLastEvent.severity = amdmsFATAL;
  amdmsLastEvent.locFile = file;
  amdmsLastEvent.locLine = line;
  va_start(va_parList, format);
  vsprintf(amdmsLastEvent.text, format, va_parList);
  va_end(va_parList);
  if (supressFlag) {
    return;
  }
  if (amdmsOnlyMessage) {
    fprintf(stdout, "FATAL: %s\n",
	    amdmsLastEvent.text);
  } else {
    fprintf(stdout, "FATAL: %s %s:%d %s\n", 
	    amdmsLastEvent.timeStamp,
	    amdmsLastEvent.locFile,
	    amdmsLastEvent.locLine,
	    amdmsLastEvent.text);
  }
}

void amdmsError(const char *file, int line, const char *format, ...)
{
  va_list        va_parList;
  
  if (severityLevel > amdmsERROR) {
    return;
  }
  amdmsGetTimeStamp(amdmsLastEvent.timeStamp);
  amdmsLastEvent.severity = amdmsERROR;
  amdmsLastEvent.locFile = file;
  amdmsLastEvent.locLine = line;
  va_start(va_parList, format);
  vsprintf(amdmsLastEvent.text, format, va_parList);
  va_end(va_parList);
  if (supressFlag) {
    return;
  }
  if (amdmsOnlyMessage) {
    fprintf(stdout, "ERROR: %s\n", 
	    amdmsLastEvent.text);
  } else {
    fprintf(stdout, "ERROR: %s %s:%d %s\n", 
	    amdmsLastEvent.timeStamp,
	    amdmsLastEvent.locFile,
	    amdmsLastEvent.locLine,
	    amdmsLastEvent.text);
  }
}

void amdmsWarning(const char *file, int line, const char *format, ...)
{
  va_list        va_parList;
  
  if (severityLevel > amdmsWARNING) {
    return;
  }
  amdmsGetTimeStamp(amdmsLastEvent.timeStamp);
  amdmsLastEvent.severity = amdmsWARNING;
  amdmsLastEvent.locFile = file;
  amdmsLastEvent.locLine = line;
  va_start(va_parList, format);
  vsprintf(amdmsLastEvent.text, format, va_parList);
  va_end(va_parList);
  if (supressFlag) {
    return;
  }
  if (amdmsOnlyMessage) {
    fprintf(stdout, "WARNING: %s\n", 
	    amdmsLastEvent.text);
  } else {
    fprintf(stdout, "WARNING: %s %s:%d %s\n", 
	    amdmsLastEvent.timeStamp,
	    amdmsLastEvent.locFile,
	    amdmsLastEvent.locLine,
	    amdmsLastEvent.text);
  }
}

void amdmsNotice(const char *file, int line, const char *format, ...)
{
  va_list        va_parList;
  
  if (severityLevel > amdmsNOTICE) {
    return;
  }
  amdmsGetTimeStamp(amdmsLastEvent.timeStamp);
  amdmsLastEvent.severity = amdmsNOTICE;
  amdmsLastEvent.locFile = file;
  amdmsLastEvent.locLine = line;
  va_start(va_parList, format);
  vsprintf(amdmsLastEvent.text, format, va_parList);
  va_end(va_parList);
  if (supressFlag) {
    return;
  }
  if (amdmsOnlyMessage) {
    fprintf(stdout, "NOTICE: %s\n", 
	    amdmsLastEvent.text);
  } else {
    fprintf(stdout, "NOTICE: %s %s:%d %s\n", 
	    amdmsLastEvent.timeStamp,
	    amdmsLastEvent.locFile,
	    amdmsLastEvent.locLine,
	    amdmsLastEvent.text);
  }
}

void amdmsInfo(const char *file, int line, const char *format, ...)
{
  va_list        va_parList;

  if (severityLevel > amdmsINFO) {
    return;
  }
  amdmsGetTimeStamp(amdmsLastEvent.timeStamp);
  amdmsLastEvent.severity = amdmsINFO;
  amdmsLastEvent.locFile = file;
  amdmsLastEvent.locLine = line;
  va_start(va_parList, format);
  vsprintf(amdmsLastEvent.text, format, va_parList);
  va_end(va_parList);
  if (supressFlag) {
    return;
  }
  if (amdmsOnlyMessage) {
    fprintf(stdout, "INFO: %s\n", 
	    amdmsLastEvent.text);
  } else {
    fprintf(stdout, "INFO: %s %s:%d %s\n", 
	    amdmsLastEvent.timeStamp,
	    amdmsLastEvent.locFile,
	    amdmsLastEvent.locLine,
	    amdmsLastEvent.text);
  }
}

void amdmsDebug(const char *file, int line, const char *format, ...)
{
  va_list        va_parList;

  if (severityLevel > amdmsDEBUG) {
    return;
  }
  amdmsGetTimeStamp(amdmsLastEvent.timeStamp);
  amdmsLastEvent.severity = amdmsDEBUG;
  amdmsLastEvent.locFile = file;
  amdmsLastEvent.locLine = line;
  va_start(va_parList, format);
  vsprintf(amdmsLastEvent.text, format, va_parList);
  va_end(va_parList);
  if (supressFlag) {
    return;
  }
  if (amdmsOnlyMessage) {
    fprintf(stdout, "DEBUG: %s\n", 
	    amdmsLastEvent.text);
  } else {
    fprintf(stdout, "DEBUG: %s %s:%d %s\n", 
	    amdmsLastEvent.timeStamp,
	    amdmsLastEvent.locFile,
	    amdmsLastEvent.locLine,
	    amdmsLastEvent.text);
  }
}

