/************************************************************
**
** Application: TaskLib
**
** Title:       c.log
**
*************************************************************/

/*
*
* Copyright (c) 2017, David Pilling and Chris Johnson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following
*     disclaimer in the documentation and/or other materials provided
*     with the distribution.
*   * Neither the name of the copyright holder nor the names of their
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/


/* Include files */
/* from standard clib */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>

/* from TaskLib */

#include "h.os"
//#include "h.werr"
#include "h.wimpt"
#include "h.constants"
#include "h.fsx"
#include "h.timex"
#include "h.os2"

#include "log.h"


/************************************************************/

/* Local defines */

/************************************************************/

/* exported variables */


/************************************************************/
/* global variables */

/* General stuff */
static int log_destination = LOG_TO_NULL;
static BOOL log_on = FALSE;
static int log_code = 0;
static char * action[] = { "No logging",
                           "Logging enabled in !Run file",
                           "Logging enabled by default"
                         };
/************************************************************/
/* Internal specific */
static char log_fname[256];
static char log_appname[24];

/************************************************************/
/* Reporter specific stuff */
#define Report_SWI_chunk 0x54c80

/* SWI numbers */
static int Report_Text0;
static int Report_Where;
static int Report_Clear;
static int Report_Push;
static int Report_Pull;
// static int Report_;

/************************************************************/
/* Syslog specific */


/************************************************************/
/* forward function declarations */


/************************************************************/




/*
 * Routines for logging to Reporter
 * Note that the Reporter help states:
 * Please use the SWI names wherever possible, as the numbers may change!
 * Thus when we initialise Reporter output, we look up the appropriate
 * SWI numbers.
*/




/**************************************************************************/

static os_error *  reporter_push (void)

{
  os_error  * err;
  os_regset   r;

  r.r[0] = 0;
  err = os_swix (Report_Push, &r);

  return (err);
}





/**************************************************************************/

static os_error *  reporter_pull (void)

{
  os_error  * err;
  os_regset   r;

  r.r[0] = 0;
  err = os_swix (Report_Pull, &r);

  return (err);
}





/**************************************************************************/

static os_error *  reporter_text0 (char * txt)

{
  os_error  * err;
  os_regset   r;

  r.r[0] = (int)txt;
  err = os_swix (Report_Text0, &r);

  return (err);
}





/**************************************************************************/

/* Get the swi numbers - if Reporter is not running, then an error will be returned.
 * Pass the error back to the calling task */

static os_error * reporter_init (BOOL clear)

{
  os_error * err;
  char txt[96];

  err = os2_swi_number_from_string ( "Report_Text0", &Report_Text0 );
  if (!err) err = os2_swi_number_from_string ( "Report_Where", &Report_Where );
  if (!err) err = os2_swi_number_from_string ( "Report_Clear", &Report_Clear );
  if (!err) err = os2_swi_number_from_string ( "Report_Push", &Report_Push );
  if (!err) err = os2_swi_number_from_string ( "Report_Pull", &Report_Pull );
  if (!err)
  {
    sprintf (txt, "Debug log for %s initialised. %s", log_appname, action[log_code]);
    reporter_text0 (txt);
  }
  return (err);
}






/**************************************************************************
 * Routines for logging to local file
 **************************************************************************/

static void internal_print (char * txt)
{
  FILE       *fp;

  fp = fopen (log_fname, "ab+");
  if (fp)
  {
    fprintf (fp, "%s\n", txt);
    fclose (fp);
  }
  return;
}




/**************************************************************************/

static void internal_init (BOOL clear)

{
  FILE       *fp;
  char string[128];
  time_t current;
  struct tm *converted_time;
  size_t length;

  sprintf (log_fname, "<%s$Dir>.dblog", log_appname);
  /* Do we start with an empty file */
  if (clear)
  {
    fp = fopen (log_fname, "wb");
  }
  else
  {
    fp = fopen (log_fname, "ab+");
  }
  /* now get the time and convert to suitable format */
  if (fp)
  {
    current = time (NULL) ;
    converted_time = localtime (&current) ;
    length = strftime (string, sizeof(string), "%H:%M:%S on %d %b %Y", converted_time) ;
    fprintf (fp, "// Debug log for %s initialised at %s\n//\n", log_appname, string);
    if (log_code > 0) fprintf (fp, "%s\n\n", action[log_code]);
    fclose(fp);
    fs_settype (log_fname, TEXT);
  }

  return;
}




/**************************************************************************/
/* General routines */
/**************************************************************************/

void log_print (char * txt)

{
    switch (log_destination)
    {
      case LOG_TO_INTERNAL:
        internal_print (txt);
        break;
      case LOG_TO_REPORTER:
        reporter_text0 (txt);
        break;
      case LOG_TO_SYSLOG:
        break;
    }

  return;
}



/**************************************************************************/

void log_printf (char *format, ...)
{
  va_list     args;
  char        v[512];
  char * ptr;

  if (log_on)
  {
    ptr = v;
    ptr += sprintf (ptr, "%s: ", log_appname);
    va_start (args, format);
    vsprintf (ptr, format, args);
    va_end (args);

    log_print (v);

  }
}





/**************************************************************************/

void log_error (char *v, os_error * err)

{
  char        string[512];
  char       *p;

  if (log_on && err)
  {
    p = string;
    p += sprintf (p, "%s: %s", log_appname, v);
    sprintf (p, err->errmess);
    log_print (string);
  }
}










/**************************************************************************/

void log_init (BOOL from_run, BOOL debug, int logtype, BOOL clear)

{
  char string[128];
  char * lt;


  /* Determine whether we should do any logging */
  /* Store app name */
  sprintf (log_appname, wimpt_programname ());
  if (from_run)
  {
    /* Use the settings from the !Run file */
    sprintf (string, "%s$Logging", log_appname);
    if (getenv (string) != NULL)
    {
      /* Logging is set on */
      /* Is there a destination set? */
      sprintf (string, "%s$Logtype", log_appname);
      lt = getenv (string);
      if (!strcmp(lt, "1")) log_destination = LOG_TO_INTERNAL;
      else if (!strcmp(lt, "2")) log_destination = LOG_TO_REPORTER;
      else if (!strcmp(lt, "3")) log_destination = LOG_TO_SYSLOG;
      else log_destination = LOG_TO_NULL;
      /* If destination is set, turn logging on */
      log_on = (log_destination != LOG_TO_NULL);
      if (log_on) log_code = 1;
    }
  }
  else
  {
    /* Use the settings as set in-app at compile time */
    if (debug)
    {
      log_destination = logtype;
    }
    else
    {
      log_destination = LOG_TO_NULL;
    }
    switch (log_destination)
    {
      case LOG_TO_INTERNAL:
      case LOG_TO_REPORTER:
      case LOG_TO_SYSLOG:
        log_on = TRUE;
        break;
      default:
        log_on = FALSE;
    }
    if (log_on) log_code = 2;
  }

  /* Now check that destination is a valid one and output initial text */
  if (log_on)
  {
    switch (log_destination)
    {
      case LOG_TO_INTERNAL:
        internal_init (clear);
        break;

      case LOG_TO_REPORTER:
        reporter_init(clear);
        break;

      case LOG_TO_SYSLOG:
        break;
    }
  }


  return;
}





/*************  End of c.log  ***********************/

