/* switch off ANSI_C_SOURCE (allows compiling all sources with cc/stand=ansi) */
#ifdef __VMS
#ifdef __HIDE_FORBIDDEN_NAMES
#undef __HIDE_FORBIDDEN_NAMES
#endif
#endif

#include <sys/time.h>
#include <sys/timeb.h>
#include <string.h>
#include <stdarg.h>
#include <assert.h>
#include "logfile.h"
#include "errhdl.h"
#include "util.h"

static FILE *fil=NULL;
static char lnam[256]="", filnam[256]="";
static char ebuf[20000]="";
static char *eptr=&ebuf[0];
static int lastStamp=0;
static int notDated=0;
static int logMask=0;
static int wrtMask=0;

int ftime (struct timeb *__timeptr); /* for some reason not defined in timeb.h with flag -std1 */

static int logfileStd;
static int dirty, writeAll;

void logfileOpen(int first) {
  struct tm *tim;
  struct timeb btim;

  if (logfileStd) {
    fil=stdout;
    return;
  }
  assert(fil==NULL);
  if (first) {
    ftime(&btim);
    tim=localtime(&btim.time);
    if (notDated) {
      if (lnam[0]=='\0') {
        str_copy(filnam, "test.log");
      } else {
        str_copy(filnam, lnam);
        str_append(filnam, ".log");
      }
    } else {
      sprintf(filnam, "%s%04d-%02d-%02d.log", lnam, tim->tm_year+1900, tim->tm_mon+1, tim->tm_mday);
    }
  } else {
    assert(filnam[0]!='\0');
  }
#ifdef __VMS
  if (first && notDated) {
    fil=fopen(filnam, "w", "SHR=UPD"); /* new version at restart */
  } else {
    fil=fopen(filnam, "a", "SHR=UPD");
  }
#else
  if (first && notDated) {
    fil=fopen(filnam, "w"); /* overwrite at restart */
  } else {
    fil=fopen(filnam, "a");
  }
#endif
}

void logfileInit(char *path, int nodate, int use_stdout, int write_all) {
  str_copy(lnam, path);
  lastStamp=-1;
  logfileStd=use_stdout;
  writeAll=write_all;
  notDated=nodate;
  logfileOpen(1);
}

void logfileOut(int mask, const char *fmt, ...)
{ va_list ap;

  assert(mask>0 && mask<32);
  va_start(ap, fmt);

  if (writeAll) {
#ifdef __VMS   
    if (fil==NULL) logfileOpen(0);
#endif
    vfprintf(fil, fmt, ap);
    wrtMask=LOG_ALL;
  } else {
    if (eptr!=NULL) {
      if (eptr-ebuf > sizeof(ebuf)-512) {
        sprintf(eptr, "... buffer full ... \1\1");
        eptr=NULL;
      } else {
        vsprintf(eptr, fmt, ap);
        assert(NULL==strchr(eptr, '\1'));
        eptr+=strlen(eptr);
        eptr[0]='\1'; /* put \1 as separator between blocks */
        eptr[1]=mask;
        eptr[2]='\0';
        eptr+=2;
      }
    }
    wrtMask=wrtMask | mask;
  }
  va_end(ap);
}

void logfileMask(int mask) {
  logMask=logMask | mask;
}

void logfileStamp(void) {
  struct tm *tim;
  struct timeb btim;
  int stamp;

  ftime(&btim);
  tim=localtime(&btim.time);
  stamp=tim->tm_hour*60+tim->tm_min;
  if (stamp!=lastStamp) {
    if (stamp<lastStamp) { /* time smaller than last time -> new day -> new logfile */
      if (fil!=NULL) { fclose(fil); fil=NULL; }
      logfileOpen(1);
    }
#ifdef __VMS   
      else if (fil==NULL) logfileOpen(0);
#endif
    lastStamp=stamp;      
    fprintf(fil, "--- %02d:%02d:%02d ---\n", tim->tm_hour, tim->tm_min, tim->tm_sec);
    dirty=0;
  }
}

void logfileWrite0(int mask) {
  char *s, *next;

  logMask=logMask | mask;
  if (dirty) logfileStamp(); /* there was something written since last time */

  s=ebuf;
  if (writeAll || *s!='\0' && wrtMask & logMask) {
    logfileStamp(); /* write stamp before write something */
    next=strchr(s, '\1');
    while (next!=NULL) {
      *next='\0';
      next++;
      if (*next & logMask) {
        fprintf(fil, "%s", s);
        dirty=1;
      }
      s=next+1;
      next=strchr(s, '\1');
    }
  }
  ebuf[0]='\0';
  eptr=&ebuf[0];
  logMask=0;
  wrtMask=0;
}

void logfileWrite(int mask) {

#ifdef __VMS   
  if (fil==NULL) logfileOpen(0);
#endif
  logfileWrite0(mask);
#ifdef __VMS   
  if (!logfileStd) { fclose(fil); fil=NULL; }
#else
  fflush(fil);
#endif

}

void logfileShowErr(char *text)
{
#ifdef __VMS   
  if (fil==NULL) logfileOpen(0);
#endif
  logfileWrite0(LOG_ALL); /* write all */
  ErrWrite(fil, text);
#ifdef __VMS   
  if (!logfileStd) { fclose(fil); fil=NULL; }
#else
  fflush(fil);
#endif
}

void logfileClose()
{
#ifdef __VMS   
  if (fil==NULL) logfileOpen(0);
#endif
  logfileWrite0(LOG_MAIN+LOG_WARN);
  lastStamp-=1;
  logfileStamp();
  if (fil!=NULL) { fclose(fil); fil=NULL; }
  filnam[0]='\0';
}

void logfileOutBuf(int mask, Str_Buf *buf)
{ char str[256];
  int rd0, sep;

  rd0=buf->rdpos;
  if (buf->rdpos < 0 || buf->rdpos >= buf->dsize
    || buf->wrpos < 0 || buf->wrpos >= buf->dsize) {
    logfileOut(mask, "<buffer corrupt>"); return;
  }
  sep=0;
  while (buf->rdpos < buf->wrpos) {
    str_get_str(buf, str);
    if (buf->sep=='\0') {
      if (sep) logfileOut(mask, " ");
      if (*str=='\0') {
        logfileOut(mask, ".");
      } else {
        logfileOut(mask, "%s", str);
      }
      sep=1;
    } else {
      if (sep) logfileOut(mask, "%c", buf->sep);
      logfileOut(mask, "%s", str);
      sep=1;
    }
  }
  buf->rdpos=rd0;
}
