/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/*
 * priv-common-i-to-e.c
 *
 *  Created on: 21.12.2010
 *      Author: Umer Kayani <u.kayani@tarent.de>,
 *              Hendrik Helwich <h.helwich@tarent.de>,
 *              Peter Neuhaus <p.neuhaus@tarent.de>,
 *              Andreas Grau <a.grau@tarent.de>
 */

/*
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA
 */

#include <libxml/HTMLparser.h>	/* HTML parsing */
#include "priv-evolution.h"
#include "evolution-util.h"

/*
 * prototypes for static functions
 */
static void sensitivity_i_to_e (const ECalComponent *e_cal_comp, I_common *i_common);
static void link_attachments_i_to_e(const ECalComponent *e_cal_comp, GList *links);
static void add_node_contents (htmlNodePtr element, gchar **description);
static void find_html_body (htmlNodePtr element, gchar **description);


/**
 * get common fields from I_common and set them in ECalComponentWithTZ
 */
void
conv_common_i_to_e (ECalComponentWithTZ *ectz, I_common *common)
{
	sensitivity_i_to_e(ectz->maincomp, common);
	link_attachments_i_to_e(ectz->maincomp, common->link_attachments);

	/* Description*/
	if (common->body) {
		gchar *description = NULL;

		/* parse HTML if given */
		if (common->is_html_richtext == TRUE) {
			xmlChar *body_text = NULL;
			description = g_strdup("");
			body_text = (xmlChar*)common->body->str;

			if (body_text != NULL) {
				xmlParserCtxtPtr p = xmlCreateDocParserCtxt(body_text);
				/* comment "xmlCtxtUseOptions" to show errors and warnings */
				xmlCtxtUseOptions (p, 96); /* Enum xmlParserOption: XML_PARSE_NOERROR = 32 : suppress error reports | XML_PARSE_NOWARNING = 64 : suppress warning reports */

				if (xmlParseDocument(p) != -1) {	/* -1 = error while parsing */
					xmlParseDocument(p);		/* parse document */

					if (p->myDoc != NULL) { 	/* go on if xml conform text with nodes was found */
						htmlNodePtr root = xmlDocGetRootElement(p->myDoc); /* set ptr to root node of document */
						if (root != NULL)
							find_html_body(root, &description);
					}
				}
				xmlFreeParserCtxt(p);
			}
		}
		else /* set description if no html-description parsed */
			description = common->body->str;

		if (description) {
			ECalComponentText text;
			GSList l;
			text.value = description;
			text.altrep = NULL;
			l.data = &text;
			l.next = NULL;
			e_cal_component_set_description_list (ectz->maincomp, &l);
		}
	}

	if (common->uid)
		e_cal_component_set_uid( ectz->maincomp, common->uid->str );


	if (common->categories)
		e_cal_component_set_categories (ectz->maincomp, common->categories->str);
	/* e_cal_component_set_classification (eCalComp, getClassificationFromSensitivity( ievent->incidence->common->sensitivity ) ); */

	if (common->creation_datetime && (common->creation_datetime->date || common->creation_datetime->date_time)) {
		struct icaltimetype *creationDate = g_new(icaltimetype, 1);
		date_or_datetime_i_to_e( common->creation_datetime, creationDate, TRUE);
		e_cal_component_set_created(ectz->maincomp, creationDate);
		g_free(creationDate);
	}

	if (common->last_modified_datetime && (common->last_modified_datetime->date || common->last_modified_datetime->date_time)) {
		struct icaltimetype *lastModifiedDate = g_new0(icaltimetype, 1);
		date_or_datetime_i_to_e( common->last_modified_datetime, lastModifiedDate, TRUE);
		e_cal_component_set_last_modified (ectz->maincomp, lastModifiedDate);
		g_free(lastModifiedDate);
	}

	/* e_set_vtimezone_block (&ectz->timezone, common->vtimezone); */
	if (common->vtimezone)
		ectz->timezone = e_cal_component_new_from_string(common->vtimezone);
}

/**
 * can be used as free function for the operation icalattach_new_from_data
 */
static void icalattach_free_g_string (unsigned char *data, void *user_data) {
	(void)user_data;
	g_free(data);
}

/**
 * add elements of the kolab_attachment_store list to the evolution calendar.
 * The property name is different for inline and hidden attachments.
 */
void
kolab_attachment_store_i_to_e (ECalComponent* e_cal_comp, I_common *icommon)
{
	GList *klb_att_store = icommon->kolab_attachment_store;
	GList *list = g_list_first (klb_att_store);

	icalcomponent *icomp = e_cal_component_get_icalcomponent (e_cal_comp);

	while (list != NULL) {
		Kolab_conv_mail_part *mpart = ((Kolab_conv_mail_part *) list->data);
		icalproperty *prop;
		icalparameter *param;

		/* check if the name of the attachment is stored in the inline */
		/* attachment names list */
		GList *names = icommon->inline_attachment_names;
		gboolean hidden = TRUE;
		for (; names; names = names->next) {
			gchar *name = (gchar*) names->data;
			if (strcmp(name, mpart->name) == 0) {
				hidden = FALSE;
				break;
			}
		}

		if (hidden) {
			gchar *b64enc = NULL;
			icalvalue *ival = NULL;

			prop = icalproperty_new_x("");
			icalproperty_set_x_name(prop, ICONTACT_KOLAB_STORE_ATTACHMENT);
			b64enc = g_base64_encode ((guchar*) mpart->data, mpart->length);

			ival = icalvalue_new_x(b64enc);
			g_free(b64enc);
			icalproperty_set_value(prop, ival);
		} else {
			icalattach *a;
			/* ATTACH;VALUE=BINARY;FMTTYPE=image/gif;ENCODING=BASE64;X-LABEL=blablubb: */

			/* create attach property with base64 content */
			gchar *b64enc = g_base64_encode ((guchar*) mpart->data, mpart->length);
			a = icalattach_new_from_data(b64enc, icalattach_free_g_string, NULL);

			g_free(b64enc);
			prop = icalproperty_new_attach(a);

		}

		/* add value type */
		param = icalparameter_new_value(ICAL_VALUE_BINARY);
		icalproperty_add_parameter(prop, param);
		/* add mime type */
		if (mpart->mime_type) {
			param = icalparameter_new_fmttype(mpart->mime_type);
			icalproperty_add_parameter(prop, param);
		}
		/* add encoding */
		param = icalparameter_new_encoding(ICAL_ENCODING_BASE64);
		icalproperty_add_parameter(prop, param);
		/* add name */
		if (mpart->name) {
			param = icalparameter_new_x(mpart->name);
			icalparameter_set_xname(param, ICONTACT_KOLAB_STORE_ATTACHMENT_NAME);
			icalproperty_add_parameter(prop, param);
		}
		/* add property to component */
		icalcomponent_add_property(icomp, prop);

		kolabconv_free_kmail_part((void **) &mpart);

		list = list->next;
	}

	g_list_free(list);
}

/**
 * Assign the sensitivity to the ecalcomp parameter which corresponds to the
 * classification which is set in icommon.
 *
 * @param  ecalcomp
 * @param  icommon
 */
static void
sensitivity_i_to_e (const ECalComponent *e_cal_comp, I_common *i_common)
{
	ECalComponentClassification classif;
	switch (i_common->sensitivity) {
	case ICOMMON_SENSITIVITY_PUBLIC:
		classif = E_CAL_COMPONENT_CLASS_PUBLIC;
		break;
	case ICOMMON_SENSITIVITY_PRIVATE:
		classif = E_CAL_COMPONENT_CLASS_PRIVATE;
		break;
	case ICOMMON_SENSITIVITY_CONFIDENTIAL:
		classif = E_CAL_COMPONENT_CLASS_CONFIDENTIAL;
		break;
	default:
		classif = E_CAL_COMPONENT_CLASS_PUBLIC;
	}
	e_cal_component_set_classification((ECalComponent*) e_cal_comp, classif);
}

/**
 * add link attachments to the evolution cal object
 */
static void
link_attachments_i_to_e(const ECalComponent *e_cal_comp, GList *links)
{
	GSList *l2 = NULL;
	for (; links; links = links->next)
		l2 = g_slist_append(l2, links->data);
	e_cal_component_set_attachment_list((ECalComponent *) e_cal_comp, l2);
}

/**
 * concat all element contents from element and subelements to desciption string
 */
static void
add_node_contents (htmlNodePtr element, gchar **description)
{
	htmlNodePtr node;
	for (node = element; node != NULL; node = node->next) {
		if (node->content != NULL) {
			/* calculate needed memory */
			/* TODO: Maybe block allocation (blocksize?) */
			size_t actual_memory = 0, additional_needed_memory = 0;
			actual_memory = (strlen(*description)) + (sizeof(gchar));
			additional_needed_memory = strlen((gchar*)node->content);

			/* size up memory */
			*description = (gchar*) g_realloc (*description, actual_memory + additional_needed_memory);

			/* attach new content */
			*description = strcat (*description, (gchar*)node->content);
		}

		if (node->children != NULL) /* recurse subnotes */
			add_node_contents(node->children, description);
	}
}

/**
 * find body tag in html string
 */
static void
find_html_body (htmlNodePtr element, gchar **description)
{
	htmlNodePtr node;
	for (node = element; node != NULL; node = node->next)
		if (node->type == XML_ELEMENT_NODE) {
			if (strcmp((gchar*)node->name, "body") == 0) /* parse complete content */
				add_node_contents(node, description);
			if (node->children != NULL) /* recurse subnotes */
				find_html_body(node->children, description);
		}
}
