/* log.c - Logging and user information routines
 *
 * Copyright (C) 2005, 2007  Oskar Liljeblad
 *
 * 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; either version 3 of the License, or
 * (at your option) any later version.
 *
 * 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 Library General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

#include <config.h>
#include <sys/types.h>		/* POSIX */
#include <unistd.h>		/* POSIX */
#include <time.h>		/* POSIX */
#include <stdio.h>		/* C89 */
#include <stdlib.h>		/* C89 */
#include <stdarg.h>		/* C89 */
#include <errno.h>		/* C89 */
#include "gettext.h"		/* Gnulib/gettext */
#define _(s) gettext(s)
#define N_(s) gettext_noop(s)
#include "xvasprintf.h"		/* Gnulib */
#include "strftime.h"		/* Gnulib */
#include "progname.h"		/* Gnulib */
#include "quote.h"		/* Gnulib */
#include "gmediaserver.h"

#define MAX_TIMESTAMP_LENGTH 1024

uint32_t verbosity = 0;
static FILE *logfh = NULL;
static const char *timestamp_format = NULL;
static bool started = false;

static char *
prepare_msg_v(const char *format, va_list args)
{
    char *msg1;
    char *msg2;

    msg1 = xvasprintf(format, args);
    msg2 = convert_string_to_log(msg1);
    if (msg2 == NULL) {
        warn(_("cannot convert log message: %s\n"), errstr);
        msg2 = msg1; /* print raw! */
    } else {
        free(msg1);
    }

    return msg2;
}

static char *
prepare_msg(const char *format, ...)
{
    va_list args;
    char *msg;

    va_start(args, format);
    msg = prepare_msg_v(format, args);
    va_end(args);

    return msg;
}



static void
log_timestamp(FILE *out)
{
    if (timestamp_format != NULL) {
        time_t curtime;
        struct tm *loctime;
        size_t len;

        if (time(&curtime) < 0) {
            /* XXX: report error somehow? */
            return;
        }
	loctime = localtime(&curtime);
        len = nstrftime(NULL, -1, timestamp_format, loctime, 0, 0);

        if (len > 0) {
            char buf[len+1];
            char *msg;

            nstrftime(buf, len+1, timestamp_format, loctime, 0, 0);
            msg = prepare_msg("%s ", buf);
            fputs(msg, out);
            free(msg);
        }
    }
}

void
init_logging(const char *logfilename, const char *ts_format)
{
    timestamp_format = ts_format;

    started = true;
    if (logfilename != NULL) {
        logfh = fopen(logfilename, "a");
        if (logfh == NULL)
            die(_("cannot open log file %s for appending\n"), quote(conv_filename(logfilename)));
        setlinebuf(logfh);
    }
    say(1, _("%s process id %d starting\n"), PACKAGE, getpid());
}

void
finish_logging(bool success)
{
    if (success)
        say(1, _("%s process id %d terminated normally\n"), PACKAGE, getpid());
    else
	say(1, _("%s process id %d terminated due to error\n"), PACKAGE, getpid());

    if (logfh != NULL) {
        fclose(logfh);
        logfh = NULL;
    }
    started = false;
}

void
say(int level, const char *format, ...)
{
    if (verbosity >= level) {
    	va_list args;
        char *msg;

    	va_start(args, format);
    	msg = prepare_msg_v(format, args);
        if (logfh != NULL) {
            log_timestamp(logfh); /* XXX: what about conversion!? */
            fputs(msg, logfh);
        } else {
            log_timestamp(stdout); /* XXX: what about conversion!? */
            fputs(msg, stdout);
        }
        free(msg);
	va_end(args);
    }
}

void
die(const char *format, ...)
{
    va_list args;
    char *msg1;
    char *msg2;

    va_start(args, format);
    msg1 = xvasprintf(format, args);
    if (logfh != NULL) {
    	log_timestamp(logfh);
    	msg2 = prepare_msg(_("Error: %s"), msg1);
      	fputs(msg2, logfh);
    } else {
        log_timestamp(stderr);
        msg2 = prepare_msg("%s: %s", program_name, msg1);
        fputs(msg2, stderr);
    }
    free(msg1);
    free(msg2);
    va_end(args);

    finish_logging(false);

    exit(EXIT_FAILURE);
}

void
warn(const char *format, ...)
{
    va_list args;
    char *msg1;
    char *msg2;

    va_start(args, format);
    msg1 = xvasprintf(format, args);
    if (logfh != NULL) {
        log_timestamp(logfh);
        msg2 = prepare_msg(_("Warning: %s"), msg1);
        fputs(msg2, logfh);
    } else {
        log_timestamp(stderr);
        msg2 = prepare_msg("%s: %s", program_name, msg1);
        fputs(msg2, stderr);
    }
    free(msg1);
    free(msg2);
    va_end(args);
}
