/* Copyright (c) 2020-2023 The Creators of Simphone

   See the file COPYING.LESSER.txt for copying permission.
*/

#ifndef _LOGGER_H_
#define _LOGGER_H_

#include "simtypes.h"

#include <stdarg.h>

#if defined(__GNUC__) && ! defined(_WIN32)
#define SIM_FORMAT_PRINTF(argidx) __attribute__ ((format (printf, argidx, (argidx) + 1)))
#else
#define SIM_FORMAT_PRINTF(argidx)
#endif

/* log levels */
#define SIM_LOG_XTRA 0
#define SIM_LOG_DEBUG 1
#define SIM_LOG_INFO 2
#define SIM_LOG_NOTE 3
#define SIM_LOG_WARN 4
#define SIM_LOG_ERROR 5
#define SIM_LOG_FATAL 6
#define SIM_LOG_UNKNOWN 7

/* initialize logging */
int log_init_ (void);
/* finish logging */
void uninit_log (void);

/* acquire and release the logger lock for atomic logging of multiple lines.
   return false if lock not acquired because log level for module is too low */
simbool log_protect_ (const char *module, int level);
void log_unprotect_ (void);

/* set log level for the specified module name (messages with lower level are not logged)
   module = NULL to set the default log level. default level is SIM_LOG_FATAL before this is called */
void log_set_level_ (const char *module, int level);
/* return log level set */
int log_get_level_ (const char *module);

/* return level of log message */
int sim_log_get_level (simtype *line);

/* return stored message with the specified index or nil if failed. returned *datetime is zero if missing */
simtype log_get_string_ (simunsigned idx, simunsigned *datetime, const char **loglevel);

/* do NOT call without acquiring logger lock first */
simtype log_put_string_ (int level, const simtype line, simunsigned datetime);

/* return number of stored log messages */
simunsigned log_count_ (void);

#define LOG_NO_LOAD 0      /* clear buffer and start new */
#define LOG_NO_EVENT (-1)  /* clear buffer and do not buffer and do not send SIM_EVENT_LOG any more */
#define LOG_NO_BUFFER (-2) /* clear buffer and do not buffer any more */

/* load or unload log buffer */
int log_load_ (simnumber lines, unsigned maxsize);

/* log output of (non-NULL) modules to the specified file (in user directory) or stop logging to file if name is NULL */
int log_init_file_ (const char *filename, simbool append);
/* log to the specified file descriptor (append = true) */
int log_init_fd_ (int fd);

/* internal use only */
int log_get_error_ (void); /* check for disk full error */
void log_print_ (const char *module, int level, const char *format, va_list args);
void log_print_function_ (const char *module, int level, const char *function, const char *format, va_list args);
void log_function (const char *module, int level, const char *function,
                   const char *file, unsigned line, const char *format, ...) SIM_FORMAT_PRINTF (6);
void log_any (const char *module, int level, const char *format, ...) SIM_FORMAT_PRINTF (3);

extern int log_recursed;

/* log a message. module name can be NULL (to use the default log level) */
void log_any_ (const char *module, int level, const char *format, ...) SIM_FORMAT_PRINTF (3);

/* logging functions to use */
void log_xtra_ (const char *module, const char *format, ...) SIM_FORMAT_PRINTF (2);
void log_debug_ (const char *module, const char *format, ...) SIM_FORMAT_PRINTF (2);
void log_info_ (const char *module, const char *format, ...) SIM_FORMAT_PRINTF (2);
void log_note_ (const char *module, const char *format, ...) SIM_FORMAT_PRINTF (2);
void log_warn_ (const char *module, const char *format, ...) SIM_FORMAT_PRINTF (2);
void log_error_ (const char *module, const char *format, ...) SIM_FORMAT_PRINTF (2);
void log_fatal_ (const char *module, int error, const char *format, ...) SIM_FORMAT_PRINTF (3); /* also send SIM_EVENT_FATAL */

#define LOG_BIT_CONT 1 /* do not add newline at the end */
#define LOG_BIT_BIN 2  /* log strings as binary */
#define LOG_BIT_HEX 4  /* log numbers as hex */

/* log contents of simtypes in text format */
void log_simtype (const char *module, int level, const simtype value, unsigned bits,
                  const char *format, ...) SIM_FORMAT_PRINTF (5); /* internal use */
void log_simtype_ (const char *module, int level, const simtype value, unsigned bits,
                   const char *format, ...) SIM_FORMAT_PRINTF (5);
void log_simtypes (const char *module, int level, const simtype value1, const simtype value2, unsigned bits,
                   const char *format, ...) SIM_FORMAT_PRINTF (6); /* internal use */
void log_simtypes_ (const char *module, int level, const simtype value1, const simtype value2, unsigned bits,
                    const char *format, ...) SIM_FORMAT_PRINTF (6);

#endif
