/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/*
 * priv-evolution-preserve.c
 *
 *  Created on: 15.11.2010
 *      Author: Hendrik Helwich <h.helwich@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 "priv-evolution.h"

/**
 * add the given property to the itnernal evolution store
 */
static void
i_evo_store_add_prop(I_common *i_common, icalproperty *prop, icalcomponent_kind kind)
{
	icalcomponent *comp;
	if (i_common->evolution_store) {
		comp = icalcomponent_new_from_string(i_common->evolution_store);
		g_free(i_common->evolution_store);
	} else
		comp = icalcomponent_new(kind);
	prop = icalproperty_new_clone(prop);
	icalcomponent_add_property(comp, prop);
	/* memory returned by *_as_ical_string() is owned by libical */
	i_common->evolution_store = g_strdup (icalcomponent_as_ical_string(comp));
	icalcomponent_free(comp);
}

/**
 * add property which is identified by an ical enum value to the evolution store
 * in I_common.
 */
static void
i_evo_store_add(I_common *i_common, icalcomponent *ical_comp, icalproperty_kind kind)
{
	icalproperty *prop = icalcomponent_get_first_property(ical_comp, kind);
	while (prop != NULL) {
		i_evo_store_add_prop(i_common, prop, icalcomponent_isa(ical_comp));
		prop = icalcomponent_get_next_property(ical_comp, kind);
	}
}

/**
 * add property which is identified by its name to the evolution store in
 * I_common.
 */
static void
i_evo_store_add_by_string(I_common *i_common, const icalcomponent *icomp, const gchar *kind) {
	icalproperty *prop = icalcomponent_get_first_property(icomp, ICAL_ANY_PROPERTY);
	while (prop != NULL) {
		gchar *pname = (gchar*) icalproperty_get_x_name(prop);
		if (pname && strcmp(pname, kind) == 0)
			i_evo_store_add_prop(i_common, prop, icalcomponent_isa(icomp));
		prop = icalcomponent_get_next_property(icomp, ICAL_ANY_PROPERTY);
	}
}

/**
 * Add an evolution vCard attribute which should not be mapped as hidden element
 * to the internal evolution store.
 *
 * @param  e_contact
 *         EContact which holds the vCard attributes
 * @param  i_common
 *         internal structure which holds the evolution store
 * @param  name
 *         the name of the vCard attribute which should be stored
 */
static void
i_evo_store_add_contact_by_name(EContact *e_contact, I_common *i_common, gchar *name)
{
	GList *list = e_vcard_get_attributes ((EVCard *) e_contact);
	for (; list != NULL; list = list->next) {
		EVCardAttribute *attrib = (EVCardAttribute*)list->data;
		if (strcmp(e_vcard_attribute_get_name (attrib), name) == 0) {
			EVCardAttribute *attrib = (EVCardAttribute*)list->data;
			EVCard *vcard;
			gchar *vstr = NULL;
			if (i_common->evolution_store) {
				vcard = e_vcard_new_from_string (i_common->evolution_store);
				g_free(i_common->evolution_store);
			} else
				vcard = e_vcard_new();
			e_vcard_add_attribute(vcard, attrib);
			vstr = e_vcard_to_string(vcard, EVC_FORMAT_VCARD_30);
			i_common->evolution_store = vstr;
		}
	}
}

/**
 * Add all unmappable properties from incidence (event/task) ECalComponent which
 * should be preserved to the evolution store.
 */
void
i_evo_store_add_cal(I_common *i_common, const ECalComponentWithTZ *ectz)
{
	icalcomponent *icomp = e_cal_component_get_icalcomponent (ectz->maincomp);

	/* TODO: Add properties which should be preserved and which are missing below. */
	i_evo_store_add(i_common, icomp, ICAL_ORGANIZER_PROPERTY);
	i_evo_store_add(i_common, icomp, ICAL_URL_PROPERTY);
	i_evo_store_add_by_string(i_common, icomp, "X-EVOLUTION-RECIPIENTS");
	/* evo_store_add(icommon, icomp, ICAL_RECURRENCEID_PROPERTY); */
}

/**
 * Add all unmappable properties from a note ECalComponent which should be
 * preserved to the evolution store.
 */
void
i_evo_store_add_cal_note(I_common *i_common, const ECalComponentWithTZ *ectz)
{
	icalcomponent *icomp;

	i_evo_store_add_cal(i_common, ectz);

	icomp = e_cal_component_get_icalcomponent (ectz->maincomp);
	i_evo_store_add(i_common, icomp, ICAL_DTSTART_PROPERTY);
}

/**
 * Add all unmappable properties from EContact which should be preserved to the
 * evolution store.
 */
void
i_evo_store_add_contact(EContact *e_contact, I_common *i_common)
{
	/* TODO: Add properties which should be preserved and which are missing below. */
	i_evo_store_add_contact_by_name(e_contact, i_common, "X-MOZILLA-HTML");
	i_evo_store_add_contact_by_name(e_contact, i_common, "CALURI");
	/* XXX: Reconsider how to handle X-EVOLUTION-FILE-AS
	 * file-as is a string for sorting in evolution. It has higher priority as full name.
	 * You can set it manually. If you create a contact or delete field in VCard it is
	 * always set to: "lastname, forename". Put in Evolution Store or better let write default value?
	 */
	/* evo_store_add_contact_by_name(e_contact, i_common, "X-EVOLUTION-FILE-AS"); */
	i_evo_store_add_contact_by_name(e_contact, i_common, "X-EVOLUTION-VIDEO-URL");
	i_evo_store_add_contact_by_name(e_contact, i_common, "MAILER");
	i_evo_store_add_contact_by_name(e_contact, i_common, "KEY");
	i_evo_store_add_contact_by_name(e_contact, i_common, "X-EVOLUTION-LIST");
	i_evo_store_add_contact_by_name(e_contact, i_common, "X-EVOLUTION-LIST-SHOW_ADDRESSES");
	i_evo_store_add_contact_by_name(e_contact, i_common, "X-SIP");
	i_evo_store_add_contact_by_name(e_contact, i_common, "X-EVOLUTION-BOOK-URI");
	/* i_evo_store_add_contact_by_name(e_contact, i_common, "ICSCALENDAR"); XXX: What is stored in this field? could this lead to data inconsistencies? */
}

/**
 * get from evolution store (I_common)
 */
void
i_evo_store_get_all(I_common *i_common, ECalComponentWithTZ *ectz)
{
	if (i_common->evolution_store) {
		icalcomponent *icomp = e_cal_component_get_icalcomponent (ectz->maincomp);
		icalcomponent *comp = icalcomponent_new_from_string(i_common->evolution_store);
		icalproperty *prop = icalcomponent_get_first_property(comp, ICAL_ANY_PROPERTY);
		while (prop != NULL) {
			prop = icalproperty_new_clone(prop);
			icalcomponent_add_property(icomp, prop);
			prop = icalcomponent_get_next_property(comp, ICAL_ANY_PROPERTY);
		}
		icalcomponent_free(comp);
	}
}

/**
 * Add all vCard attributes from the internal evolution store to the vCard
 *
 * @param  i_common
 *         Holds the evolution store
 * @param  e_contact
 *         evolution contact which will hold the vCard attributes
 */
void
i_evo_store_get_all_contact(I_common *i_common, EContact *e_contact)
{
	if (i_common->evolution_store) {
		EVCard *vcard = e_vcard_new_from_string (i_common->evolution_store);
		GList *list = e_vcard_get_attributes (vcard);
		for (; list; list = list->next) {
			if (list->data) {
				EVCardAttribute *attr = list->data;
				e_vcard_add_attribute((EVCard*)e_contact, attr);
			}
		}
		g_list_free(list);
	}
}

/**
 * Get all kolab store elements from the iCal and pute them in the internal
 * kolab store.
 *
 * @param  ectz
 *         holds the iCal from which the kolab store elements are read.
 * @param  i_common
 *         holds the kolab store
 */
void
e_kolab_store_get_fields(const ECalComponentWithTZ *ectz, I_common *i_common) {
	icalcomponent *icomp = e_cal_component_get_icalcomponent (ectz->maincomp);
	icalproperty *prop = icalcomponent_get_first_property(icomp, ICAL_ANY_PROPERTY);
	while (prop != NULL) {
		gchar *pname = (gchar*) icalproperty_get_x_name(prop);
		if (pname && strcmp(pname, ICONTACT_KOLAB_STORE) == 0) {
			gsize outlen;
			guchar *b64enc = NULL;
			gpointer parent_ptr = NULL;
			const gchar *id_str = NULL;

			pname = (gchar*) icalproperty_get_x(prop);
			b64enc = g_base64_decode (pname, &outlen);

			parent_ptr = i_common;
			id_str = icalproperty_get_parameter_as_string(prop, ICONTACT_KOLAB_STORE_ID);
			if (id_str != NULL)
				parent_ptr = (gpointer) strtol (id_str, NULL, 10);

			kolab_store_add_element(i_common, parent_ptr, (gchar*)b64enc, TRUE);
		}
		prop = icalcomponent_get_next_property(icomp, ICAL_ANY_PROPERTY);
	}
}

/**
 * Add the kolab store elements for the given kolab element pointer to the iCal
 */
static void
e_kolab_store_add_field_group(ECalComponentWithTZ *ectz, I_common *i_common, gpointer parent_ptr)
{
	if (i_common->kolab_store) {
		icalcomponent *icomp = e_cal_component_get_icalcomponent (ectz->maincomp);
		/* Add a param in kolab_store for each element in the list icontact->kolab_store */
		GList *list = kolab_store_get_element_list(i_common, parent_ptr);
		for (list = g_list_last (list); list != NULL; list = list->prev) {
			icalproperty *prop = icalproperty_new_x("");
			icalparameter *para = icalparameter_new_encoding(ICAL_ENCODING_BASE64);
			gchar *b64enc = NULL;
			icalvalue *ival = NULL;

			icalproperty_set_x_name(prop, ICONTACT_KOLAB_STORE);
			icalproperty_add_parameter(prop, para);
			if (parent_ptr != i_common) { /* sub element field? => store id */
				gchar id_str[5];
				sprintf (id_str, "%li", (glong) parent_ptr);
				para = icalparameter_new_x(id_str);
				icalparameter_set_xname(para, ICONTACT_KOLAB_STORE_ID);
				icalproperty_add_parameter(prop, para);
			}
			b64enc = g_base64_encode ((guchar*) list->data, strlen((gchar*)list->data));
			ival = icalvalue_new_x(b64enc);
			g_free(b64enc);
			icalproperty_set_value(prop, ival);
			icalcomponent_add_property(icomp, prop);
		}
	}
}

/**
 * Add the kolab store top level elements to the iCal
 */
void
e_kolab_store_add_common_fields(ECalComponentWithTZ *ectz, I_common *i_common)
{
	e_kolab_store_add_field_group(ectz, i_common, i_common);
}

/**
 * Add the kolab store incidence elements to the iCal
 */
void
e_kolab_store_add_incidence_fields(ECalComponentWithTZ *ectz, I_incidence *incidence)
{
	e_kolab_store_add_common_fields(ectz, incidence->common);
	e_kolab_store_add_field_group(ectz, incidence->common, (gpointer) KOLAB_STORE_PTR_INC_ORGANIZER);
	e_kolab_store_add_field_group(ectz, incidence->common, (gpointer) KOLAB_STORE_PTR_INC_RECURRENCE);
}
