#include <stdio.h>
#include <string.h>
#include <glib.h>

#include "filter.h"
#include "filter-private.h"
#include "filter-utils.h"


static int xfilter_debug_mode = 1;


int xfilter_init(void)
{
	return 0;
}

void xfilter_done(void)
{
}

XFilter *xfilter_new(XFilterType type, const char *name)
{
	XFilter *filter;

	if (type == XF_CONTENT) {
		filter = XFILTER(g_new0(XContentFilter, 1));
	} else {
		filter = XFILTER(g_new0(XTestFilter, 1));
	}

	filter->type = type;
	filter->name = g_strdup(name);

	return filter;
}

void xfilter_free(XFilter *filter)
{
	if (!filter)
		return;
	g_free(filter->name);
	g_free(filter);
}

XFilterType xfilter_get_type(XFilter *filter)
{
	g_return_val_if_fail(filter != NULL, -1);

	return filter->type;
}

const char *xfilter_get_name(XFilter *filter)
{
	g_return_val_if_fail(filter != NULL, NULL);

	return filter->name;
}

void xfilter_set_input_mime_types(XFilter *filter, const char **types)
{
}

void xfilter_set_output_mime_type(XFilter *filter, const char *type)
{
}

XMessageData *xfilter_message_data_new(const char *src, const char *mime_type)
{
	XMessageData *data;

	g_return_val_if_fail(mime_type != NULL, NULL);

	data = g_new0(XMessageData, 1);
	data->content = g_strdup(src);
	data->mime_type = g_strdup(mime_type);
	return data;
}

XMessageData *xfilter_message_data_read_file(const char *file, const char *mime_type)
{
	XMessageData *data;
	char *content;

	g_return_val_if_fail(file != NULL, NULL);
	g_return_val_if_fail(mime_type != NULL, NULL);

	content = xfilter_utils_get_file_contents(file);
	if (!content)
		return NULL;

	data = g_new0(XMessageData, 1);
	data->content = content;
	data->mime_type = g_strdup(mime_type);
	return data;
}

void xfilter_message_data_free(XMessageData *msgdata)
{
	if (!msgdata)
		return;

	g_free(msgdata->mime_type);
	g_free(msgdata->content);
	g_free(msgdata->from);
	g_free(msgdata->to);
	g_free(msgdata->cc);
	g_free(msgdata->subject);

	g_free(msgdata);
}

void xfilter_message_data_set_content(XMessageData *msgdata, char *content)
{
	if (msgdata->content)
		g_free(msgdata->content);
	msgdata->content = content;
}

void xfilter_message_data_set_attribute(XMessageData *msgdata, XMessageAttr attr, const char *value, int append)
{
	int len;

#define APPEND_STR(d, s)				\
	if (d) {					\
		len = strlen(d);			\
		d = g_realloc(d, len + strlen(s) + 2);	\
		d[len] = '\n';				\
		strcpy(d + len + 1, s);			\
	} else						\
		d = g_strdup(s);

#define SET_STR(d, s)	{ g_free(d); d = g_strdup(s); }

	if (!value)
		return;

	switch (attr) {
	case XM_FROM:
		if (append) {
			APPEND_STR(msgdata->from, value);
		} else {
			SET_STR(msgdata->from, value);
		}
		break;
	case XM_TO:
		if (append) {
			APPEND_STR(msgdata->to, value);
		} else {
			SET_STR(msgdata->to, value);
		}
		break;
	case XM_CC:
		if (append) {
			APPEND_STR(msgdata->cc, value);
		} else {
			SET_STR(msgdata->cc, value);
		}
		break;
	case XM_SUBJECT:
		if (append) {
			APPEND_STR(msgdata->subject, value);
		} else {
			SET_STR(msgdata->subject, value);
		}
		break;
	default:
		break;
	}

#undef APPEND_STR
}

void xfilter_message_data_copy_attributes(XMessageData *msgdata, const XMessageData *srcdata)
{
	g_free(msgdata->from);
	msgdata->from = g_strdup(srcdata->from);
	g_free(msgdata->to);
	msgdata->to = g_strdup(srcdata->to);
	g_free(msgdata->cc);
	msgdata->cc = g_strdup(srcdata->cc);
	g_free(msgdata->subject);
	msgdata->subject = g_strdup(srcdata->subject);
}

const char *xfilter_message_data_get_attribute(const XMessageData *msgdata, XMessageAttr attr)
{
	switch (attr) {
	case XM_FROM:
		return msgdata->from;
	case XM_TO:
		return msgdata->to;
	case XM_CC:
		return msgdata->cc;
	case XM_SUBJECT:
		return msgdata->subject;
	default:
		break;
	}

	return NULL;
}

const char *xfilter_message_data_get_mime_type(const XMessageData *msgdata)
{
	g_return_val_if_fail(msgdata != NULL, NULL);

	return msgdata->mime_type;
}

const char *xfilter_message_data_get_content(const XMessageData *msgdata)
{
	g_return_val_if_fail(msgdata != NULL, NULL);

	return msgdata->content;
}

void xfilter_set_content_filter_func(XContentFilter *filter, XContentFilterFunc func)
{
	g_return_if_fail(XFILTER(filter)->type == XF_CONTENT);

	filter->content_filter_func = func;
}

void xfilter_set_test_filter_func(XTestFilter *filter, XTestFilterFunc func)
{
	g_return_if_fail(XFILTER(filter)->type == XF_TEST);

	filter->test_filter_func = func;
}

XFilterStatus xfilter_exec(XFilter *filter, const XMessageData *msgdata, XFilterResult *result)
{
	g_return_val_if_fail(filter != NULL, XF_ERROR);
	g_return_val_if_fail(msgdata != NULL, XF_ERROR);

	if (filter->type == XF_CONTENT) {
		if (!X_CONTENT_FILTER(filter)->content_filter_func)
			return XF_ERROR;
		return X_CONTENT_FILTER(filter)->content_filter_func(filter, msgdata, result);
	} else {
		if (!X_TEST_FILTER(filter)->test_filter_func)
			return XF_ERROR;
		return X_TEST_FILTER(filter)->test_filter_func(filter, msgdata, result);
	}
}

void xfilter_result_print(XFilterResult *result)
{
	printf("XFilterResult: status = %d, probability = %f\n", result->status, result->probability);
}

XFilterResult *xfilter_result_new(void)
{
	XFilterResult *res;

	res = g_new0(XFilterResult, 1);
	res->status = XF_NONE;
	res->probability = 0.5;
	return res;
}

void xfilter_result_set_status(XFilterResult *result, XFilterStatus status)
{
	result->status = status;
}

void xfilter_result_set_message_data(XFilterResult *result, XMessageData *msgdata)
{
	if (result->msgdata)
		xfilter_message_data_free(result->msgdata);
	result->msgdata = msgdata;
}

void xfilter_result_set_probability(XFilterResult *result, double prob)
{
	result->probability = prob;
}

XFilterStatus xfilter_result_get_status(XFilterResult *result)
{
	g_return_val_if_fail(result != NULL, XF_ERROR);

	return result->status;
}

XMessageData *xfilter_result_get_message_data(XFilterResult *result)
{
	g_return_val_if_fail(result != NULL, NULL);

	return result->msgdata;
}

double xfilter_result_get_probability(XFilterResult *result)
{
	g_return_val_if_fail(result != NULL, 0.0);

	return result->probability;
}

void xfilter_result_free(XFilterResult *result)
{
	if (!result)
		return;
	xfilter_message_data_free(result->msgdata);
	g_free(result);
}

void xfilter_debug_print(const char *format, ...)
{
	va_list args;
	char buf[1024];

	if (!xfilter_debug_mode)
		return;

	va_start(args, format);
	g_vsnprintf(buf, sizeof(buf), format, args);
	va_end(args);

	fputs(buf, stderr);
}
