/* 
  Copyright 2018-2023 Thorsten Alteholz <libcontra@alteholz.eu>

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; version 2 of the License

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program (see the file COPYING included with this
  distribution); if not, write to the Free Software Foundation, Inc.,
  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

/*!
*************************************************************************
*
* \file libcontra_log.c
*
* \author Thorsten Alteholz <libcontra@alteholz.eu>
*
* \todo documentation
*
* \brief functions for logging
*
* for more info see documents in docu directory
*
*
* \addtogroup libcontra
* The group of the library.
* @{
************************************************************************/

#include <libcontra.h>
#include <libcontra_log.h>

extern int	libcontra_loglevel;
extern pthread_mutex_t libcontra_lock;
extern bool	libcontra_logStdio;
extern FILE*	libcontra_file;

/*!
*************************************************************************
*
* \fn char * bool2str(bool value);
*
* \author Thorsten Alteholz <libcontra@alteholz.eu>
*
* \brief return string of boolean parameter
*
* write stuff to log
*
************************************************************************/
char * bool2str(bool value)
{
  if (value) return "true";
  else  return "false";
}

/*!
*************************************************************************
*
* \fn void _libcontra_log(int level, const char *fmt, ...)
*
* \author Thorsten Alteholz <libcontra@alteholz.eu>
*
* \todo documentation
*
* \bug up to now, there is no know bug
*
* \brief write stuff to logfile
*
* write stuff to log
*
************************************************************************/
void _libcontra_log(int level, const char *fmt, ...)
{
  va_list arg;
//  FILE *log_file = (level == LOG_ERROR) ? err_log : info_log;
  time_t timestamp;
  struct tm result;
  char sTimestamp[32];

  pthread_mutex_lock(&libcontra_lock);

  /* Check if the message should be logged */
  if (level > libcontra_loglevel)
    return;

  timestamp=time(NULL);
  localtime_r(&timestamp, &result);
  asctime_r(&result, sTimestamp);
  sTimestamp[strlen(sTimestamp) - 1] = ' ';

  /* Write the error message */
  if (libcontra_logStdio==true) {
    fprintf(stdout, "%s", sTimestamp);
    va_start(arg, fmt);
    vfprintf(stdout, fmt, arg);
    va_end(arg);
  }
  if (libcontra_file!=NULL) {
    fprintf(libcontra_file, "%s", sTimestamp);
    va_start(arg, fmt);
    vfprintf(libcontra_file, fmt, arg);
    va_end(arg);
    #ifdef DEBUG
     fflush(libcontra_file);
     fsync(fileno(libcontra_file));
    #endif
  }

  pthread_mutex_unlock(&libcontra_lock);
}

/* about 25 chars are used for the timestamp, 16 = chars shall be displayed (25 + 4*16 = 89 */
#define LOG_LINE_LENGTH 16 /*!< we have 16 bytes of binary date per line */
#define BINSTRINGLENGTH (LOG_LINE_LENGTH*3+1) /*!< length of binary string (three times number of data) */
#define ASCIISTRINGLENGTH (LOG_LINE_LENGTH+1) /*!< we also print the ascii charachters in each line */

/*!
*************************************************************************
*
* \fn void libcontra_log_data(int level, const void *buffer, int length)
*
* \author Thorsten Alteholz <libcontra@alteholz.eu>
*
* \brief log some binary data
*
************************************************************************/
void libcontra_log_data(int level, const void *buffer, int length)
{
  int bytesToPrint, numberOfBytesToWorkOn, currentIndex=0;
  int i;
  char binString[BINSTRINGLENGTH], asciiString[ASCIISTRINGLENGTH];
  char charString[3];
  unsigned char character;
  const unsigned char *bytes = buffer;
  bool doPrint;
  
  bytesToPrint=length;
  while (bytesToPrint) {
    numberOfBytesToWorkOn=min(LOG_LINE_LENGTH,bytesToPrint);
    bzero(binString, BINSTRINGLENGTH);
    bzero(asciiString, ASCIISTRINGLENGTH);
    for (i=0;i<LOG_LINE_LENGTH;i++) {
      if (currentIndex<length) {
        character=bytes[currentIndex];
        currentIndex++;
        bytesToPrint--;
        doPrint=true;
      } else {
        character=' ';
        doPrint=false;
      }
  
      if (doPrint) {
        sprintf(charString,"%02x",character);
        asciiString[i]=isprint((int)character) ? character : '.';
        binString[3*i+0]=charString[0];
        binString[3*i+1]=charString[1];
        binString[3*i+2]=' ';
      } else {
        asciiString[i]=' ';
        binString[3*i+0]=' ';
        binString[3*i+1]=' ';
        binString[3*i+2]=' ';
      }
    }
    libcontra_log(level, "%s -> %s",binString, asciiString);
  }
}

/*! @} */

