#include <config.h>
#include <IMLog.hh>

#ifdef HAVE_SYSLOG_H
#include <syslog.h>
#endif

IMLog* IMLog::plinst = NULL;
const int IMLOG_MAX_SIZE = 4096;

void
IMLog::output(
    const char *mes,
    enum LOG_LEVEL lvl,
    enum LOG_DESTINATION d
)
{
    if (d == IMLOG_DEFAULT) d = dest;
    switch (d) {
      case IMLOG_STDOUT:
       output_file(stdout, mes);
      case IMLOG_STDERR:
       output_file(stderr, mes);
       break;
#ifdef HAVE_SYSLOG_H
      case SYSLOG_AUTHPRIV:
#ifdef LOG_AUTHPRIV
       output_syslog(LOG_AUTHPRIV, get_syslog_priority(lvl), mes);
#elif defined(LOG_AUTH)
       output_syslog(LOG_AUTH, get_syslog_priority(lvl), mes);
#endif
       break;
      case SYSLOG_USER:
       output_syslog(LOG_USER, get_syslog_priority(lvl), mes);
       break;
      case SYSLOG_LOCAL0:
       output_syslog(LOG_LOCAL0, get_syslog_priority(lvl), mes);
       break;
      case SYSLOG_LOCAL1:
       output_syslog(LOG_LOCAL1, get_syslog_priority(lvl), mes);
       break;
      case SYSLOG_LOCAL2:
       output_syslog(LOG_LOCAL2, get_syslog_priority(lvl), mes);
       break;
      case SYSLOG_LOCAL3:
       output_syslog(LOG_LOCAL3, get_syslog_priority(lvl), mes);
       break;
      case SYSLOG_LOCAL4:
       output_syslog(LOG_LOCAL4, get_syslog_priority(lvl), mes);
       break;
      case SYSLOG_LOCAL5:
       output_syslog(LOG_LOCAL5, get_syslog_priority(lvl), mes);
       break;
      case SYSLOG_LOCAL6:
       output_syslog(LOG_LOCAL6, get_syslog_priority(lvl), mes);
       break;
      case SYSLOG_LOCAL7:
       output_syslog(LOG_LOCAL7, get_syslog_priority(lvl), mes);
       break;
#endif
      default:
       output_file(stderr, mes);
       break;
    }
}

/*
  logging interface.
 */

void
IMLog::voutput(
    enum LOG_LEVEL l,
    enum LOG_DESTINATION d,
    const char *fmt,
    va_list args
)
{
    char buf[IMLOG_MAX_SIZE];
    if (!(lv >= l)) return;

    vsnprintf(buf, sizeof(buf), fmt, args);
    output(buf, lv, d);
}

/*
  output physical implementations.
 */

void
IMLog::output_file(
    FILE *file,
    const char *mes
)
{
    fputs(mes, file);
    fputc('\n', file);
}

void
IMLog::output_syslog(
    int facility,
    int priority,
    const char *mes
)
{
#ifdef HAVE_SYSLOG_H
    openlog(progname, LOG_PID, facility);
    syslog(priority, "%s", mes);
    closelog();
#endif
}

int
IMLog::get_syslog_priority(
    enum LOG_LEVEL l
)
{
#ifdef HAVE_SYSLOG_H
    switch (l) {
      case QUIET:
       return LOG_ALERT;
      case ERROR:
       return LOG_ERR;
      case WARNING:
       return LOG_WARNING;
      case NORMAL:
       return LOG_NOTICE;
      case INFO:
       return LOG_INFO;
      case VERBOSE:
       return LOG_DEBUG;
      case DEBUGLOG:
       return LOG_DEBUG;
    }
    return LOG_NOTICE;
#else
    return 0;
#endif
}

/*
  management functions.
 */

IMLog*
IMLog::construct(
    const char* progname,
    enum LOG_LEVEL lv,
    enum LOG_DESTINATION d
)
{
    if (plinst) return plinst;
    plinst = new IMLog(progname);
    plinst->set_log_level(lv);
    plinst->set_default_destination(d);

    return plinst;
}

IMLog::IMLog(
    const char *x_progname
)
{
    if (x_progname) {
	int len;
	const char *spos_s, *spos_b;

	spos_s = strrchr(x_progname, '/');
	if (spos_s) {
	    spos_s++;
	} else {
	    spos_s = x_progname;
	}

	spos_b = strrchr(x_progname, '\\');
	if (spos_b) {
	    spos_b++;
	} else {
	    spos_b = x_progname;
	}
	if (spos_s < spos_b) spos_s = spos_b;

	len = strlen(spos_s);
	progname = new char[len + 1];
	strcpy(progname, spos_s);
    }

    lv = NORMAL;
    dest = IMLOG_DEFAULT;
}

IMLog::~IMLog()
{
    if (progname) delete [] progname;
}

/* Local Variables: */
/* c-file-style: "iiim-project" */
/* End: */
