/*
 * debug.c - for debug and logging
 *
 * Copyright (C) 2020-2024 IOPSYS Software Solutions AB. All rights reserved.
 *
 */

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>
#include <string.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>

#include <easy/easy.h>

#include "debug.h"
#include "decollector.h"

const char *PROG_NAME = "decollector";

static const char *logfile;
static FILE *outfile;
static int ffd = -1;
static int ofd = -1;
static int verbose;
static bool syslogging;
static bool logfile_isfifo;
static const int syslog_level[] = { LOG_ERR, LOG_WARNING, LOG_INFO, LOG_DEBUG };

void start_logging(void *args)
{
	struct decollector_useropts *opts = args;

	syslogging = opts->syslogging;
	logfile = opts->logfile;
	logfile_isfifo = opts->logfile_isfifo;
	verbose = opts->debug_level;

	if (syslogging)
		openlog(PROG_NAME, 0, LOG_DAEMON);

	if (!logfile) {
		outfile = stderr;
		ofd = fileno(stderr);
		return;
	}

	if (logfile_isfifo) {
		struct stat st;
		int rfd;

		if (stat(logfile, &st))
			unlink(logfile);

		mkfifo(logfile, 0600);
		if (stat(logfile, &st) == -1 || !S_ISFIFO(st.st_mode))
			return;

		rfd = open(logfile, O_RDONLY | O_NONBLOCK);
		if (rfd) {
			ffd = open(logfile, O_WRONLY | O_NONBLOCK);
			close(rfd);
		}
	} else {
		ofd = open(logfile, O_CREAT | O_WRONLY | O_APPEND | O_NONBLOCK);
	}
}

void stop_logging(void)
{
	if (syslogging)
		closelog();

	if (outfile)
		fclose(outfile);

	if (ofd > 0) {
		close(ofd);
		ofd = -1;
	}

	if (ffd > 0) {
		close(ffd);
		unlink(logfile);
	}
}

static void log_timestamp(int fd)
{
	time_t now = time(NULL);
	struct tm *tm_now = localtime(&now);
	const char *tm_fmt = "[%d-%02d-%02d %02d:%02d:%02d] ";

	dprintf(fd, tm_fmt,
		tm_now->tm_year + 1900,
		tm_now->tm_mon + 1,
		tm_now->tm_mday,
		tm_now->tm_hour,
		tm_now->tm_min,
		tm_now->tm_sec);
}

void log_message(int level, const char *fmt, ...)
{
	va_list args;
	int fd = -1;

	if (level > verbose)
		return;

	va_start(args, fmt);

	if (syslogging && level >= 0)
		vsyslog(syslog_level[level > 3 ? 3 : level], fmt, args);

	if (logfile_isfifo && ffd > 0)
		fd = ffd;
	else if (ofd >= 0)
		fd = ofd;

	if (fd != -1) {
		log_timestamp(fd);
		dprintf(fd, "[%d]: ", getpid());
		vdprintf(fd, fmt, args);
	}

	va_end(args);
}
