/*-
 * Copyright 2016 Vsevolod Stakhov
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "config.h"
#include "printf.h"
#include "message.h"
#include "util.h"
#include "content_type.h"
#include "task.h"
#include "mime_parser.h"
#include "unix-std.h"

#define MODE_NORMAL 0
#define MODE_GMIME 1
static gdouble total_time = 0.0;

static void
rspamd_show_normal (struct rspamd_mime_part *part)
{
	rspamd_printf ("got normal part %p: parent: %p, type: %T/%T,"
			"length: %z (%z raw)\n",
			part, part->parent_part,
			&part->ct->type, &part->ct->subtype,
			part->parsed_data.len,
			part->raw_data.len);
}

static void
rspamd_show_multipart (struct rspamd_mime_part *part)
{
	struct rspamd_mime_part *cur;
	guint i;

	rspamd_printf ("got multipart part %p, boundary: %T: parent: %p, type: %T/%T, children: [",
			part, &part->ct->boundary,
			part->parent_part,
			&part->ct->type, &part->ct->subtype);

	if (part->specific.mp.children) {
		for (i = 0; i < part->specific.mp.children->len; i ++) {
			cur = g_ptr_array_index (part->specific.mp.children, i);

			if (i != 0) {
				rspamd_printf (", %p{%T/%T}", cur,
						&cur->ct->type, &cur->ct->subtype);
			}
			else {
				rspamd_printf ("%p{%T/%T}", cur,
						&cur->ct->type, &cur->ct->subtype);
			}
		}
	}

	rspamd_printf ("]\n");
}

static void
rspamd_show_message (struct rspamd_mime_part *part)
{
	rspamd_printf ("got message part %p: parent: %p\n",
				part, part->parent_part);
}

#if 0
static void
mime_foreach_callback (GMimeObject * parent,
	GMimeObject * part,
	gpointer user_data)
{
	GMimeContentType *type;

	if (GMIME_IS_MESSAGE_PART (part)) {
		/* message/rfc822 or message/news */
		GMimeMessage *message;

		/* g_mime_message_foreach_part() won't descend into
			   child message parts, so if we want to count any
			   subparts of this child message, we'll have to call
			   g_mime_message_foreach_part() again here. */
		rspamd_printf ("got message part %p: parent: %p\n",
						part, parent);
		message = g_mime_message_part_get_message ((GMimeMessagePart *) part);
		g_mime_message_foreach (message, mime_foreach_callback, part);
	}
	else if (GMIME_IS_MULTIPART (part)) {
		type = (GMimeContentType *) g_mime_object_get_content_type (GMIME_OBJECT (
						part));
		rspamd_printf ("got multipart part %p, boundary: %s: parent: %p, type: %s/%s\n",
					part, g_mime_multipart_get_boundary (GMIME_MULTIPART(part)),
					parent,
					g_mime_content_type_get_media_type (type),
					g_mime_content_type_get_media_subtype (type));
	}
	else {
		type = (GMimeContentType *) g_mime_object_get_content_type (GMIME_OBJECT (
				part));
		rspamd_printf ("got normal part %p, parent: %p, type: %s/%s\n",
				part,
				parent,
				g_mime_content_type_get_media_type (type),
				g_mime_content_type_get_media_subtype (type));
	}
}
#endif
static void
rspamd_process_file (struct rspamd_config *cfg, const gchar *fname, gint mode)
{
	struct rspamd_task *task;
	gint fd;
	gpointer map;
	struct stat st;
	GError *err = NULL;
#if 0
	GMimeMessage *message;
	GMimeParser *parser;
	GMimeStream *stream;
	GByteArray tmp;
#endif
	struct rspamd_mime_part *part;
	guint i;
	gdouble ts1, ts2;

	fd = open (fname, O_RDONLY);

	if (fd == -1) {
		rspamd_fprintf (stderr, "cannot open %s: %s\n", fname, strerror (errno));
		exit (EXIT_FAILURE);
	}

	if (fstat (fd, &st) == -1) {
		rspamd_fprintf (stderr, "cannot stat %s: %s\n", fname, strerror (errno));
		exit (EXIT_FAILURE);
	}

	map = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
	close (fd);

	if (map == MAP_FAILED) {
		rspamd_fprintf (stderr, "cannot mmap %s: %s\n", fname, strerror (errno));
		exit (EXIT_FAILURE);
	}

	task = rspamd_task_new (NULL, cfg, NULL);
	task->msg.begin = map;
	task->msg.len = st.st_size;

	ts1 = rspamd_get_ticks ();

	if (mode == MODE_NORMAL) {
		if (!rspamd_mime_parse_task (task, &err)) {
			rspamd_fprintf (stderr, "cannot parse %s: %e\n", fname, err);
			g_error_free (err);
		}
	}
#if 0
	else if (mode == MODE_GMIME) {
		tmp.data = map;
		tmp.len = st.st_size;
		stream = g_mime_stream_mem_new_with_byte_array (&tmp);
		g_mime_stream_mem_set_owner (GMIME_STREAM_MEM (stream), FALSE);
		parser = g_mime_parser_new_with_stream (stream);
		message = g_mime_parser_construct_message (parser);
	}
#endif
	ts2 = rspamd_get_ticks ();
	total_time += ts2 - ts1;

	if (mode == MODE_NORMAL) {
		for (i = 0; i < task->parts->len; i ++) {
			part = g_ptr_array_index (task->parts, i);

			if (part->ct->flags & RSPAMD_CONTENT_TYPE_MULTIPART) {
				rspamd_show_multipart (part);
			}
			else if (part->ct->flags & RSPAMD_CONTENT_TYPE_MESSAGE) {
				rspamd_show_message (part);
			}
			else {
				rspamd_show_normal (part);
			}
		}
	}
#if 0
	else if (mode == MODE_GMIME) {
		g_mime_message_foreach (message, mime_foreach_callback, NULL);
	}
#endif

	rspamd_task_free (task);
	munmap (map, st.st_size);
#if 0
	if (mode == MODE_GMIME) {
		g_object_unref (message);
	}
#endif
}

int
main (int argc, char **argv)
{
	gint i, start = 1, mode = MODE_NORMAL;
	struct rspamd_config *cfg;
	rspamd_logger_t *logger = NULL;

	if (argc > 2 && *argv[1] == '-') {
		start = 2;

		if (argv[1][1] == 'g') {
			mode = MODE_GMIME;
		}
	}
	cfg = rspamd_config_new ();
	cfg->libs_ctx = rspamd_init_libs ();
	cfg->log_type = RSPAMD_LOG_CONSOLE;
	rspamd_set_logger (cfg, g_quark_from_static_string ("mime"), &logger, NULL);
	(void) rspamd_log_open (logger);
	g_log_set_default_handler (rspamd_glib_log_function, logger);
	g_set_printerr_handler (rspamd_glib_printerr_function);
	rspamd_config_post_load (cfg,
			RSPAMD_CONFIG_INIT_LIBS|RSPAMD_CONFIG_INIT_URL|RSPAMD_CONFIG_INIT_NO_TLD);

	for (i = start; i < argc; i ++) {
		if (argv[i]) {
			rspamd_process_file (cfg, argv[i], mode);
		}
	}

	rspamd_printf ("Total time parsing: %.4f seconds\n", total_time);

	rspamd_log_close (logger);
	REF_RELEASE (cfg);

	return 0;
}