/*
 * 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"

static void
traverse_config(dsyslog_config_entry_t *ce)
{
	_ENTER;

	_DEBUG("root_ce <%s>/[%p]", ce->ce_varname, ce);

	for (; ce != NULL; ce = ce->ce_next) {
		_DEBUG("ce->ce_varname [%s] ce->ce_vardata[%s]", ce->ce_varname, ce->ce_vardata);

		if (ce->ce_entries)
			traverse_config(ce->ce_entries);
	}

	_LEAVE;
}

static void
dsyslog_config_process(dsyslog_config_entry_t *ce)
{
	_ENTER;

	for (; ce != NULL; ce = ce->ce_next) {
		if (!g_ascii_strcasecmp(ce->ce_varname, "loadmodule")) {
			gchar *tpath = g_strdup_printf("%s/%s", MODDIR, ce->ce_vardata);
			dsyslog_module_load(tpath);
			g_free(tpath);
		} else if (!g_ascii_strcasecmp(ce->ce_varname, "source")) {
			dsyslog_source_t *src;
			dsyslog_config_entry_t *cce;

			if (!ce->ce_vardata)
				continue;

			src = g_slice_new0(dsyslog_source_t);
			src->type = g_strdup(ce->ce_vardata);

			for (cce = ce->ce_entries; cce != NULL; cce = cce->ce_next) {
				if (!g_ascii_strcasecmp(cce->ce_varname, "path"))
					src->path = g_strdup(cce->ce_vardata);
				if (!g_ascii_strcasecmp(cce->ce_varname, "host"))
					src->host = g_strdup(cce->ce_vardata);
				if (!g_ascii_strcasecmp(cce->ce_varname, "port"))
					src->port = cce->ce_vardatanum;
			}

			dsyslog_source_setup(src);
		} else if (!g_ascii_strcasecmp(ce->ce_varname, "filter")) {
			dsyslog_filter_t *filter;
			dsyslog_config_entry_t *cce;
			gint severity = 0, facility = 0;

			if (!ce->ce_entries || !ce->ce_vardata)
				continue;

			filter = g_slice_new0(dsyslog_filter_t);
			filter->type = g_strdup(ce->ce_vardata);

			for (cce = ce->ce_entries; cce != NULL; cce = cce->ce_next) {
				if (!g_ascii_strcasecmp(cce->ce_varname, "program"))
					filter->program = g_strdup(cce->ce_vardata);
				if (!g_ascii_strcasecmp(cce->ce_varname, "search"))
					filter->search = g_strdup(cce->ce_vardata);
				if (!g_ascii_strcasecmp(cce->ce_varname, "message"))
					filter->message = g_strdup(cce->ce_vardata);
				if (!g_ascii_strcasecmp(cce->ce_varname, "replace"))
					filter->replace = g_strdup(cce->ce_vardata);
				if (!g_ascii_strcasecmp(cce->ce_varname, "severity"))
					severity = dsyslog_severity_to_logcode(cce->ce_vardata);
				if (!g_ascii_strcasecmp(cce->ce_varname, "facility"))
					facility = dsyslog_facility_to_logcode(cce->ce_vardata);
				if (!g_ascii_strcasecmp(cce->ce_varname, "condition")) {
					dsyslog_cond_t *cond;
					dsyslog_config_entry_t *ccce;

					if (!cce->ce_entries || !cce->ce_vardata)
						continue;

					for (ccce = cce->ce_entries; ccce != NULL; ccce = ccce->ce_next) {
						if (!ccce->ce_varname || !ccce->ce_vardata)
							continue;

						cond = g_slice_new0(dsyslog_cond_t);
						cond->type = g_strdup(cce->ce_vardata);
						cond->cond = g_strdup(ccce->ce_varname); 
						cond->value = g_strdup(ccce->ce_vardata);

						filter->conditions = dsyslog_cond_add(filter->conditions, cond);
					}
				}
			}

			filter->logcode = (facility << 3) | severity;
			dsyslog_filter_add(filter);
		} else if (!g_ascii_strcasecmp(ce->ce_varname, "output")) {
			dsyslog_output_t *output;
			dsyslog_config_entry_t *cce;

			if (!ce->ce_entries || !ce->ce_vardata)
				continue;

			output = g_slice_new0(dsyslog_output_t);
			output->type = g_strdup(ce->ce_vardata);

			for (cce = ce->ce_entries; cce != NULL; cce = cce->ce_next) {
				if (!g_ascii_strcasecmp(cce->ce_varname, "path"))
					output->path = g_strdup(cce->ce_vardata);
				if (!g_ascii_strcasecmp(cce->ce_varname, "host"))
					output->host = g_strdup(cce->ce_vardata);
				if (!g_ascii_strcasecmp(cce->ce_varname, "port"))
					output->port = cce->ce_vardatanum;
				if (!g_ascii_strcasecmp(cce->ce_varname, "dbname"))
					output->dbname = g_strdup(cce->ce_vardata);
				if (!g_ascii_strcasecmp(cce->ce_varname, "dbhost"))
					output->dbhost = g_strdup(cce->ce_vardata);
				if (!g_ascii_strcasecmp(cce->ce_varname, "dbuser"))
					output->dbuser = g_strdup(cce->ce_vardata);
				if (!g_ascii_strcasecmp(cce->ce_varname, "dbpass"))
					output->dbpass = g_strdup(cce->ce_vardata);
				if (!g_ascii_strcasecmp(cce->ce_varname, "dbport"))
					output->dbport = cce->ce_vardatanum;
				if (!g_ascii_strcasecmp(cce->ce_varname, "condition")) {
					dsyslog_cond_t *cond;
					dsyslog_config_entry_t *ccce;

					if (!cce->ce_entries || !cce->ce_vardata)
						continue;

					for (ccce = cce->ce_entries; ccce != NULL; ccce = ccce->ce_next) {
						if (!ccce->ce_varname || !ccce->ce_vardata)
							continue;

						cond = g_slice_new0(dsyslog_cond_t);
						cond->type = g_strdup(cce->ce_vardata);
						cond->cond = g_strdup(ccce->ce_varname); 
						cond->value = g_strdup(ccce->ce_vardata);

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

			dsyslog_output_add(output);
		}
	}

	_LEAVE;
}

void
dsyslog_config_init(char *path)
{
	dsyslog_config_file_t *cfg;

	_ENTER;

	_DEBUG("path <%s>", path);

	cfg = dsyslog_config_load(path);

	_DEBUG("cfg [%p]", cfg);

	if (!cfg) {
		if (!options.configtest) {
			_ERROR("Config parsing failed, aborting.");
		}

		exit(-1);
	}

#ifndef NDEBUG
	traverse_config(cfg->cf_entries);
#endif
	dsyslog_config_process(cfg->cf_entries);
	dsyslog_config_free(cfg);

	_LEAVE;
}

void
dsyslog_config_rehash(char *path)
{
	_ENTER;

	dsyslog_filter_clear();
	dsyslog_output_clear();
	dsyslog_source_clear();
	dsyslog_module_clear();
	dsyslog_perfctr_reset();
	dsyslog_config_init(path);

	_LEAVE;
}
