/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/*
 * priv-common-e-to-i.c
 *
 *  Created on: 29.11.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
 */

/* FIXME remove the use of strdup(), replace by g_strdup() */
#define _BSD_SOURCE
#define _SVID_SOURCE
#define _XOPEN_SOURCE 500

#include <string.h>

#include "priv-evolution.h"
#include "evolution-util.h"

/**
 * get ICalendar VTIMEZONE block from ECalComponentWithTZ
 *
 * @param  ectz
 *         An evolution event/task/note type which may contain a time zone.
 *
 * @return the ICalendar VTIMEZONE block
 */
static gchar*
get_vtimezone (const ECalComponentWithTZ *ectz)
{
	icalcomponent *icc = NULL;
	icalcomponent *cloned_icc = NULL;
	icalproperty *dtstamp = NULL;
	icalproperty *uid = NULL;
	gchar *ical_str = NULL;

	if (ectz == NULL || ectz->maincomp == NULL || ectz->timezone == NULL)
		return NULL;

	icc = e_cal_component_get_icalcomponent (ectz->timezone);
	cloned_icc = icalcomponent_new_clone (icc);

	/* uid and dtstamp are not needed (nor wanted) in timezone block */
	uid = icalcomponent_get_first_property(cloned_icc, ICAL_UID_PROPERTY);
	icalcomponent_remove_property (cloned_icc, uid);
	free(uid);
	dtstamp = icalcomponent_get_first_property(cloned_icc, ICAL_DTSTAMP_PROPERTY);
	icalcomponent_remove_property (cloned_icc, dtstamp);
	free(dtstamp);

	/* memory returned by *_as_ical_string() is owned by libical */
	ical_str = g_strdup (icalcomponent_as_ical_string (cloned_icc));
	icalcomponent_free (cloned_icc);

	return ical_str;
}


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

/**
 * Get link attachments from the evolution calendar and store them in the
 * internal structure
 */
static void
link_attachments_e_to_i(const ECalComponent *e_cal_comp, I_common *i_common)
{
	GSList *links;
	e_cal_component_get_attachment_list((ECalComponent *)e_cal_comp, &links);
	for (; links; links = links->next) {
		gchar* url = (gchar*)links->data;
		if (url)
			i_common->link_attachments = g_list_append(
			                                           i_common->link_attachments, url);
	}
	g_slist_free(links);
}

/**
 * get parameters from the icalendar property and store them in the internal
 * struct if the parameter describes a hidden or inline attachment.
 */
static void
add_e_attachment_parameters(icalproperty *prop, I_common *i_common, gboolean inln)
{
	gboolean binary = FALSE;
	gchar* mime_type = NULL;
	gchar* label = NULL;

	/* iterate over all parameters of the attachment property */
	int i, pc = icalproperty_count_parameters(prop);
	icalparameter *para;
	for (i = 0; i < pc; i++) {
		icalparameter_kind kind;
		icalparameter_value xvalue;

		para = i == 0 ? icalproperty_get_first_parameter(prop, ICAL_ANY_PARAMETER) :
			icalproperty_get_next_parameter(prop, ICAL_ANY_PARAMETER);

		kind = icalparameter_isa(para);
		xvalue = icalparameter_get_value(para);
		if (kind == ICAL_VALUE_PARAMETER && xvalue == ICAL_VALUE_BINARY)
			binary = TRUE; /* not a link attachment */
		else if (kind == ICAL_FMTTYPE_PARAMETER) /* found mime type */
			mime_type = (gchar*) icalparameter_get_xvalue(para);
		else if (xvalue == ICAL_VALUE_X) { /* found attachment name */
			const char* name = icalparameter_get_xname(para);
			const char* value = icalparameter_get_xvalue(para);
			if (name && strcmp(name, ICONTACT_KOLAB_STORE_ATTACHMENT_NAME) == 0)
				label = (gchar*) value;
		}
	}

	if (binary) { /* if not a linked attachment add data to struct */
		Kolab_conv_mail_part *mpart = g_new0(Kolab_conv_mail_part, 1);
		gchar* pname = NULL;

		if (label != NULL) {
			if (inln)
				i_common->inline_attachment_names = g_list_append(
				                                                  i_common->inline_attachment_names,
				                                                  strdup(label));
			mpart->name = strdup(label);
		}
		if (mime_type != NULL)
			mpart->mime_type = strdup(mime_type);
		/* add data and length */
		pname = (gchar*) icalproperty_get_value_as_string(prop);
		if (pname) {
			gsize outlen;
			mpart->data = (gchar*) g_base64_decode (pname, &outlen);
			mpart->length = outlen;
			/* add created mail part to the attachment list */
			i_common->kolab_attachment_store = g_list_append(i_common->kolab_attachment_store, mpart);
		}
	}
}


/**
 * Get common fields from ECalComponentWithTZ and set them in I_common
 */
void
conv_common_e_to_i (const ECalComponentWithTZ *ectz, I_common *i_common)
{
	GSList *descr_list = NULL;
	const gchar *uid = NULL;
	const gchar *categories = NULL;
	struct icaltimetype *lastModifiedDate;
	struct icaltimetype *createdDate;
	icalcomponent *icomp = NULL;
	icalproperty *prop = NULL;

	i_common->vtimezone = get_vtimezone(ectz);
	sensitivity_e_to_i(ectz->maincomp, i_common);
	link_attachments_e_to_i(ectz->maincomp, i_common);

	/* handle description/body */
	e_cal_component_get_description_list ((ECalComponent*) ectz->maincomp, &descr_list);

	if (descr_list != NULL) {
		ECalComponentText *text = (ECalComponentText*) descr_list->data;
		i_common->body = g_string_new (text->value);
		e_cal_component_free_text_list(descr_list);
	}

	/* ******************************************SET UID************************************ */
	e_cal_component_get_uid (ectz->maincomp, &uid);

	if (uid)
		i_common->uid = g_string_new (uid);

	/* ******************************************SET CATEGORIES************************************ */
	e_cal_component_get_categories (ectz->maincomp, &categories);

	if (categories)
		i_common->categories = g_string_new (categories);

	/* ******************************************SET DATES (CREATION, LASTMODIFICATION, START, END etc.)************************************ */

	e_cal_component_get_last_modified (ectz->maincomp, &lastModifiedDate);
	i_common->last_modified_datetime = new_date_or_datetime();

	if (lastModifiedDate)
		/* log_debug("ICalDate %d-%d-%d-%d-%d-%d", lastModifiedDate->year, lastModifiedDate->month, lastModifiedDate->day, lastModifiedDate->hour, lastModifiedDate->minute, lastModifiedDate->second); */
		date_or_datetime_e_to_i (lastModifiedDate, i_common->last_modified_datetime);
	else {
		/* Set lastModifiedDate to current system time */
		i_common->last_modified_datetime->date_time = g_new0(time_t, 1);
		*(i_common->last_modified_datetime->date_time) = time(NULL);
	}
	g_free(lastModifiedDate);

	i_common->creation_datetime = new_date_or_datetime();
	e_cal_component_get_created (ectz->maincomp, &createdDate);

	if (createdDate)
		date_or_datetime_e_to_i (createdDate, i_common->creation_datetime);
	else {
		/* Set createdDate to current system time */
		i_common->creation_datetime->date_time = g_new0(time_t, 1);
		*(i_common->creation_datetime->date_time) = time(NULL);
	}
	g_free(createdDate);


	/* ******************************************SET ATTACHMENT LIST******************************************************************************* */

	/* iterate over all ical properties */
	icomp = e_cal_component_get_icalcomponent (ectz->maincomp);
	prop = icalcomponent_get_first_property(icomp, ICAL_ANY_PROPERTY);
	while (prop != NULL) {
		icalproperty_kind kind = icalproperty_isa(prop);
		gchar *pname = (gchar*) icalproperty_get_x_name(prop);
		if (ICAL_ATTACH_PROPERTY == kind) /* found kolab inline or link attachment */
			add_e_attachment_parameters(prop, i_common, TRUE);
		else if (pname && strcmp(pname, ICONTACT_KOLAB_STORE_ATTACHMENT) == 0) /* found hidden kolab attachment */
			add_e_attachment_parameters(prop, i_common, FALSE);
		prop = icalcomponent_get_next_property(icomp, ICAL_ANY_PROPERTY);
	}

	i_common->is_html_richtext = FALSE;
}
