/*
 * dsyslog - a dumb syslog (e.g. syslog for people who have a clue)
 * Copyright (c) 2008 William Pitcock <nenolod@sacredspiral.co.uk>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice is present in all copies.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "dsyslog.h"

struct dsyslog_output_type_map {
        gchar *type;
        dsyslog_output_handler_t hdl;
};

static GList *output_list_ = NULL;
static GList *output_type_list_ = NULL;

void
dsyslog_output_add(dsyslog_output_t *output)
{
	GList *n;

	_ENTER;

	for (n = output_type_list_; n != NULL; n = g_list_next(n)) {
		struct dsyslog_output_type_map *m = (struct dsyslog_output_type_map *) n->data;

		if (!g_ascii_strcasecmp(m->type, output->type)) {
			output->handler = m->hdl;
			break;
		}
	}

	output_list_ = g_list_append(output_list_, output);
	dsyslog_perfctr.outputs++;

	_LEAVE;
}

void
dsyslog_output_remove(dsyslog_output_t *output)
{
	GList *n, *n2;

	_ENTER;

	output_list_ = g_list_remove_all(output_list_, output);

	if (output->destructor)
		output->destructor(output);

	g_free(output->type);
	g_free(output->path);
	g_free(output->host);
	g_free(output->dbuser);
	g_free(output->dbpass);
	g_free(output->dbhost);
	g_free(output->dbname);

	for (n = output->conditions, n2 = g_list_next(output->conditions); n != NULL; n = n2, n2 = g_list_next(n2)) {
		dsyslog_cond_t *cond = (dsyslog_cond_t *) n->data;

		output->conditions = dsyslog_cond_remove(output->conditions, cond);
	}

	g_slice_free(dsyslog_output_t, output);
	dsyslog_perfctr.outputs--;

	_LEAVE;
}

void
dsyslog_output_type_register(gchar *type, dsyslog_output_handler_t hdl)
{
	struct dsyslog_output_type_map *m;

	_ENTER;

	m = g_slice_new(struct dsyslog_output_type_map);
	m->type = type;
	m->hdl = hdl;

	output_type_list_ = g_list_prepend(output_type_list_, m);

	_LEAVE;
}

void
dsyslog_output_type_unregister(gchar *type)
{
	GList *n;

	_ENTER;

	for (n = output_type_list_; n != NULL; n = g_list_next(n)) {
		struct dsyslog_output_type_map *m = (struct dsyslog_output_type_map *) n->data;

		if (!g_ascii_strcasecmp(m->type, type)) {
			output_type_list_ = g_list_remove_all(output_type_list_, m);
			g_slice_free(struct dsyslog_output_type_map, m);

			_LEAVE;
		}
	}

	_LEAVE;
}

void
dsyslog_output_process(dsyslog_event_t *event)
{
	GList *n;

	_ENTER;

	for (n = output_list_; n != NULL; n = g_list_next(n)) {
		dsyslog_output_t *output = (dsyslog_output_t *) n->data;

		if (!dsyslog_cond_process(event, output->conditions)) {
			_DEBUG("output[%p] conditions didn't match, try next output", output);
			continue;
		}

		output->handler(event, output);
	}

	_LEAVE;
}

void
dsyslog_output_clear(void)
{
	GList *n, *n2;

	_ENTER;

	for (n = output_list_, n2 = g_list_next(output_list_); n != NULL; n = n2, n2 = g_list_next(n2)) {
		dsyslog_output_t *output = (dsyslog_output_t *) n->data;

		dsyslog_output_remove(output);
	}

	output_list_ = NULL;

	_LEAVE;
}
