#include <syslog.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <azprolog.h>

/*

// prioritys
#define LOG_EMERG       0       /+ system is unusable +/
#define LOG_ALERT       1       /+ action must be taken immediately +/
#define LOG_CRIT        2       /+ critical conditions +/
#define LOG_ERR         3       /+ error conditions +/
#define LOG_WARNING     4       /+ warning conditions +/
#define LOG_NOTICE      5       /+ normal but significant condition +/
#define LOG_INFO        6       /+ informational +/
#define LOG_DEBUG       7       /+ debug-level messages +/

// option flag
#define LOG_PID         0x01    /+ log the pid with each message +/
#define LOG_CONS        0x02    /+ log on the console if errors in sending +/
#define LOG_ODELAY      0x04    /+ delay open until first syslog() (default) +/
#define LOG_NDELAY      0x08    /+ don't delay open +/
#define LOG_NOWAIT      0x10    /+ don't wait for console forks: DEPRECATED +/
#define LOG_PERROR      0x20    /+ log to stderr as well +/

// facility codes
#define LOG_KERN        (0<<3)  /+ kernel messages +/
#define LOG_USER        (1<<3)  /+ random user-level messages +/
#define LOG_MAIL        (2<<3)  /+ mail system +/
#define LOG_DAEMON      (3<<3)  /+ system daemons +/
#define LOG_AUTH        (4<<3)  /+ security/authorization messages +/
#define LOG_SYSLOG      (5<<3)  /+ messages generated internally by syslogd +/
#define LOG_LPR         (6<<3)  /+ line printer subsystem +/
#define LOG_NEWS        (7<<3)  /+ network news subsystem +/
#define LOG_UUCP        (8<<3)  /+ UUCP subsystem +/
#define LOG_CRON        (9<<3)  /+ clock daemon +/
#define LOG_AUTHPRIV    (10<<3) /+ security/authorization messages (private) +/
#define LOG_FTP         (11<<3) /+ ftp daemon +/
        /+ other codes through 15 reserved for system use +/
#define LOG_LOCAL0      (16<<3) /+ reserved for local use +/
#define LOG_LOCAL1      (17<<3) /+ reserved for local use +/
  :

 ?- openlog(newsyslog,1,16<<3), % StartUp Once
     syslog(5,my_log_wrie),     % 3(ERR),4(WARRNING),5(NOTICE),6(INFO),7(DEBUG)
    closelog.                   % Before Terminate Once

*/

/* openlog(char *ident,int logoption,int facility) */


//#define BACKWARD_FIX


extern BASEINT Numeric_s_num_eval_int(TERM *arg); /* source/numeric.c */

static	char ident[1024];

static BASEINT NL_ATOM;

#ifdef BACKWARD_FIX
static int
get_term_str(Frame* Env, TERM* t, char** s)
{
  int len;

  REALVALUE(t);
  len = az_term_to_cstring_length(Env, t);
  *s = malloc(len + 1);
  if (*s == 0) return -1;

  (void )az_term_to_cstring(Env, t, *s, len + 1);

  return len;
}

static int
term_to_string(Frame* Env, TERM* t, char** rs)
{
  AZ_EXTERN int B2_term_string(Frame *Env, TERM *arg1, TERM *arg2);

  TERM* x;
  int r;
  int len;

  x = next_var_cell;
  MakeUndef(Env);

  r = B2_term_string(Env, t, x);
  //fprintf(stderr, "r: %d\r\n", r);
  if (r == 0) {
    next_var_cell = x;
    return -1;
  }

  len = get_term_str(Env, x, rs);
  //fprintf(stderr, "len: %d\r\n", len);
  next_var_cell = x;
  if (len < 0) {
    return -2;
  }

  return len;
}
#endif /* BACKWARD_FIX */

static int
make_term_to_string(Frame* Env, TERM* t, char buf[], int buflen)
{
  int len;

  REALVALUE(t);

  if (IsAtom(t)) {
    BASEINT a = GetAtom(t);

    if (a == NL_ATOM) {
      len = 1;
      if (len >= buflen)
        return -1;

      buf[0] = '\n';
    }
    else {
      len = az_term_to_cstring_length(Env, t);
      if (len >= buflen)
        return -1;
      if (len < 0)
        return -2;

      Atom2Asciz(a, buf);
    }

    buf[len] = '\0';
  }
  else if (IsInt(t)) {
    SBASEINT i = GetInt(t);

    len = snprintf(buf, buflen, "%lld", (long long )i);
    if (len >= buflen)
      return -1;
  }
  else if (IsDouble(t)) {
    double d = GetDouble(t);

    len = snprintf(buf, buflen, "%.4f", d);
    if (len >= buflen)
      return -1;
  }
  else if (IsCompTerm(t)) {
    char* s;

#ifdef BACKWARD_FIX
    len = term_to_string(Env, t, &s);
    if (len < 0)
      return -3;

    if (len >= buflen) {
      free(s);
      return -1;
    }

    strncpy(buf, s, len);
    buf[len] = '\0';
    free(s);
#else
    s = az_term_conv_to_string(Env, t);
    if (s == 0)
      return -3;

    len = strlen(s);
    if (len >= buflen)
      return -1;

    strncpy(buf, s, len);
    buf[len] = '\0';
#endif
  }
  else if (IsCons(t)) {
    char* p;
    int blen;
    int elen;

    len = 0;
    p = buf;
    blen = buflen;
    while (IsCons(t)) {
      REALVALUE(t);
      t = BODY(t);

      elen = make_term_to_string(Env, t, p, blen);
      if (elen < 0)
        return elen;

      if (elen >= blen)
        return -1;

      p    += elen;
      blen -= elen;
      len  += elen;

      t++;
    }
  }
  else
    return -4;

  return len;
}

pred P3_openlog(Env)
Frame *Env;
{
	Atom2Asciz(GetAtom(next_var_cell-3),ident);
	openlog(ident,(int)Numeric_s_num_eval_int(next_var_cell-2),(int)Numeric_s_num_eval_int(next_var_cell-1) );
	YIELD(DET_SUCC);
}

/* syslog(int priority, any term: message) */

pred P2_syslog(Env)
Frame *Env;
{
  int len;
  char message[AZ_MAX_ATOM_LENGTH];

  len = make_term_to_string(Env, next_var_cell - 1, message, sizeof(message));
  if (len < 0)
    YIELD(FAIL);

#if 0
  fprintf(stderr, "message: [%s]\r\n", message);
#else
  syslog((int )Numeric_s_num_eval_int(next_var_cell - 2), "%s", message);
#endif

  YIELD(DET_SUCC);
}

pred P0_closelog(Env)
Frame *Env;
{
	closelog();
	YIELD(DET_SUCC);
}

extern int initiate_az_syslog(Frame *Env)
{
  put_bltn("openlog",  3, P3_openlog);
  put_bltn("syslog",   2, P2_syslog);
  put_bltn("closelog", 0, P0_closelog);

  NL_ATOM = PutSystemAtom((Frame* )NULL, "nl");

  return 1;
}
