/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/*
 * priv-incidence-i-to-k.c
 *
 *  Created on: 12.10.2010
 *      Author: 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 "priv-kolab.h"

/*
 * Prototypes for static functions
 */
static gchar *alarm_type_i_to_k(Alarm_type alarm_type);
static gchar *incidence_role_i_to_k(Incidence_role role);
static gchar *incidence_status_i_to_k(Incidence_status status);
static void weekday_i_to_k(xmlNodePtr node, gint weekdays);
static void recurrence_i_to_k(const Recurrence *recurrence, xmlNodePtr node);



/**
 * Convert libekolabconv I_incidence to Kolab XML
 */
void
conv_incidence_i_to_k(xmlNodePtr root_node, I_incidence *i_incidence)
{
	xmlNodePtr node = NULL;
	GList *iterator = NULL;

	if (i_incidence == NULL)
		return;

	/* common */
	common_i_to_k(root_node, i_incidence->common);

	/* pilot-sync-status */
	/* summary */
	if(i_incidence->summary)
		add_child_node(root_node, KLB_INC_SUMMARY, i_incidence->summary->str );
	/* location */
	if(i_incidence->location)
		add_child_node(root_node, KLB_INC_LOCATION, i_incidence->location->str );

	/* organizer */
	node = add_child_node(root_node, KLB_INC_ORGANIZER, NULL); /* always write organizer node because kolab store could hold sub elements */
	if (i_incidence->organizer_display_name )
		add_child_node( node, KLB_INC_DISPLAY_NAME, i_incidence->organizer_display_name->str);
	if (i_incidence->organizer_smtp_address )
		add_child_node( node, KLB_INC_SMTP_ADDRESS, i_incidence->organizer_smtp_address->str);

	i_kolab_store_get_xml_nodes(i_incidence->common, (gpointer) KOLAB_STORE_PTR_INC_ORGANIZER, node);

	/* start-date */
	if (i_incidence->start_date ) {
		gchar *start_str = date_or_datetime_to_string(i_incidence->start_date);
		add_child_node(root_node, KLB_INC_START_DATE, start_str);
		g_free(start_str);
	}
	/* advanced_alarm */
	if (i_incidence->advanced_alarm) {
		GList *iterator = NULL;

		xmlNodePtr simple_alarm_node;
		simple_alarm_node = add_child_node(root_node, KLB_INC_ALARM, NULL);
		node = add_child_node(root_node, KLBX_INC_ADV_ALARM, NULL);

		iterator = i_incidence->advanced_alarm;

		while (iterator != NULL) {
			Alarm *alarm_element = ((Alarm *)iterator->data);

			if (alarm_element->type == I_ALARM_TYPE_DISPLAY
			    && alarm_element->display_text == NULL	/* if display text is set its no simple alarm */
			    && alarm_element->start_offset		/* must have a minute value */
			    && !alarm_element->end_offset		/* must be null */
			    && !alarm_element->repeat_count		/* must be null */
			    && !alarm_element->repeat_interval	/* must be null */
			    && iterator->prev == NULL)		/* only first element can be simple alarm */
				{
					/* simple alarm */
					/* add_child_node(root_node, KLB_INC_ALARM, int_to_string(alarm_element->start_offset)); */
					gchar * node_content = g_strdup_printf("%i", alarm_element->start_offset);
					xmlNodeAddContent(simple_alarm_node, (xmlChar*) node_content);
					if (iterator->next == NULL) {
						/* remove set advanced-alarms node if no node follows after the simple one. */
						xmlUnlinkNode(node);
						xmlFreeNode(node);
					}
					g_free(node_content);
				} else {
				/* advanced alarm */
				xmlNodePtr element_node;
				element_node = add_child_node(node, KLB_INC_ALARM, NULL);

				if (alarm_element->type) {
					add_property(element_node, KLBX_INC_ADV_ALARM_TYPE, alarm_type_i_to_k(alarm_element->type));
					if (alarm_element->type == I_ALARM_TYPE_DISPLAY) {
						if (alarm_element->display_text != NULL)
							add_child_node(element_node, KLBX_INC_ADV_ALARM_TYPE_DISPLAY_TEXT, alarm_element->display_text->str);
					}
					if (alarm_element->type == I_ALARM_TYPE_AUDIO) {
						if (alarm_element->audio_file)
							add_child_node(element_node, KLBX_INC_ADV_ALARM_TYPE_AUDIO_FILE, alarm_element->audio_file->str);
					}
					if (alarm_element->type == I_ALARM_TYPE_PROCEDURE) {
						if (alarm_element->proc_param) {
							if (alarm_element->proc_param->program)
								add_child_node(element_node, KLBX_INC_ADV_ALARM_TYPE_PROCEDURE_PROGRAM, alarm_element->proc_param->program->str);
							if (alarm_element->proc_param->arguments)
								add_child_node(element_node, KLBX_INC_ADV_ALARM_TYPE_PROCEDURE_ARGUMENTS, alarm_element->proc_param->arguments->str);
						}
					}
					if (alarm_element->type == I_ALARM_TYPE_EMAIL) {
						if (alarm_element->email_param) {
							if (alarm_element->email_param->addresses) {
								GList *address_iterator = NULL;
								xmlNodePtr addresses_node = NULL;
								addresses_node = add_child_node(element_node, KLBX_INC_ADV_ALARM_TYPE_EMAIL_ADDRESSES, NULL);

								address_iterator = alarm_element->email_param->addresses;

								while(address_iterator != NULL){
									GString *address_element = ((char*)address_iterator->data);
									add_child_node(addresses_node, KLBX_INC_ADV_ALARM_TYPE_EMAIL_ADDRESSES_ADDRESS, address_element->str);
									address_iterator = address_iterator->next;
								}
								g_list_free(address_iterator);
							}

							if (alarm_element->email_param->subject)
								add_child_node(element_node, KLBX_INC_ADV_ALARM_TYPE_EMAIL_SUBJECT, alarm_element->email_param->subject->str);
							if (alarm_element->email_param->mail_text)
								add_child_node(element_node, KLBX_INC_ADV_ALARM_TYPE_EMAIL_MAIL_TEXT, alarm_element->email_param->mail_text->str);
							if (alarm_element->email_param->attachments) {
								xmlNodePtr attachments_node = add_child_node(element_node, KLBX_INC_ADV_ALARM_TYPE_EMAIL_ATTACHMENTS, NULL);

								GList *attachment_iterator;
								attachment_iterator = alarm_element->email_param->attachments;

								while (attachment_iterator != NULL) {
									gchar *attachment_element = ((gchar*)attachment_iterator->data);

									add_child_node(attachments_node, KLBX_INC_ADV_ALARM_TYPE_EMAIL_ATTACHMENTS_ATT, attachment_element);
									attachment_iterator = attachment_iterator->next;
								}

								g_list_free(attachment_iterator);
							}
						}
					}
				}

				/* common in adv. alarm */
				if (alarm_element->start_offset) {
					gchar *child_content = g_strdup_printf("%i", alarm_element->start_offset);
					add_child_node(element_node, KLBX_INC_ADV_ALARM_START_OFFSET, child_content);
					g_free(child_content);
				}
				if (alarm_element->end_offset) {
					gchar *child_content = g_strdup_printf("%i", alarm_element->end_offset);
					add_child_node(element_node, KLBX_INC_ADV_ALARM_END_OFFSET, child_content);
					g_free(child_content);
				}
				if (alarm_element->repeat_count) {
					gchar *child_content = g_strdup_printf("%i", alarm_element->repeat_count);
					add_child_node(element_node, KLBX_INC_ADV_ALARM_REPEAT_COUNT, child_content);
					g_free(child_content);
				}
				if (alarm_element->repeat_interval) {
					gchar *child_content = g_strdup_printf("%i", alarm_element->repeat_interval);
					add_child_node(element_node, KLBX_INC_ADV_ALARM_REPEAT_INTERVAL, child_content);
					g_free(child_content);
				}
				i_kolab_store_get_xml_nodes(i_incidence->common, alarm_element, element_node);
			}
			iterator = iterator->next;
		}
		if (simple_alarm_node->children == NULL) {
			/* remove simple alarm when its not set (children == NULL) */
			xmlUnlinkNode(simple_alarm_node);
			xmlFreeNode(simple_alarm_node);
		}
		g_list_free(iterator);
	}

	/* recurrence */
	if (i_incidence->recurrence) {
		node = add_child_node(root_node, KLB_INC_RECURRENCE, NULL);
		recurrence_i_to_k(i_incidence->recurrence, node);
		i_kolab_store_get_xml_nodes(i_incidence->common, (gpointer) KOLAB_STORE_PTR_INC_RECURRENCE, node);
	}

	/* attendee */
	iterator = i_incidence->attendee;

	while (iterator != NULL) {
		Attendee *attendee = ((Attendee *)iterator->data);

		node = add_child_node(root_node, KLB_INC_ATTENDEE, NULL);
		if( attendee->display_name )
			add_child_node(node, KLB_INC_DISPLAY_NAME, attendee->display_name->str);
		if( attendee->smtp_address )
			add_child_node(node, KLB_INC_SMTP_ADDRESS, attendee->smtp_address->str);
		add_child_node(node, KLB_INC_ATTENDEE_REQUEST_RESPONSE, attendee->request_response == TRUE ? "true" : "false");
		add_child_node(node, KLBX_INC_ATTENDEE_INVITATION_SENT, attendee->invitation_sent == TRUE ? "true" : "false");
		add_child_node(node, KLB_INC_ATTENDEE_ROLE, incidence_role_i_to_k(attendee->role));
		add_child_node(node, KLB_INC_ATTENDEE_STATUS, incidence_status_i_to_k(attendee->status));

		switch (attendee->cutype) {
		case I_INC_CUTYPE_INDIVIDUAL:
			add_child_node(node, KLBC_INCIDENCE_ATTENDEE_TYPE, KLBC_INCIDENCE_ATTENDEE_TYPE_INDIVIDUAL);
			break;
		case I_INC_CUTYPE_GROUP:
			add_child_node(node, KLBC_INCIDENCE_ATTENDEE_TYPE, KLBC_INCIDENCE_ATTENDEE_TYPE_GROUP);
			break;
		case I_INC_CUTYPE_RESOURCE:
			add_child_node(node, KLBC_INCIDENCE_ATTENDEE_TYPE, KLBC_INCIDENCE_ATTENDEE_TYPE_RESOURCE);
			break;
		case I_INC_CUTYPE_ROOM:
			add_child_node(node, KLBC_INCIDENCE_ATTENDEE_TYPE, KLBC_INCIDENCE_ATTENDEE_TYPE_ROOM);
			break;
		case I_INC_CUTYPE_UNDEFINED:
			/* nothing to do (default case) */
			break;
		default:
			g_assert(FALSE);
			break;
		}

		i_kolab_store_get_xml_nodes(i_incidence->common, attendee, node);

		iterator = iterator->next;
	}
	g_list_free(iterator);
}


/**
 * Convert an alarm type enumeration value from an internal event or task to a
 * Kolab XML alarm type value.
 *
 * @param  alarm_type
 *         an alarm type enumeration value from an internal event or task
 * @return a Kolab XML alarm type value
 */
static gchar*
alarm_type_i_to_k (Alarm_type alarm_type)
{
	switch (alarm_type) {
	case I_ALARM_TYPE_DISPLAY:
		return KLBX_INC_ADV_ALARM_TYPE_DISPLAY;
	case I_ALARM_TYPE_AUDIO:
		return KLBX_INC_ADV_ALARM_TYPE_AUDIO;
	case I_ALARM_TYPE_PROCEDURE:
		return KLBX_INC_ADV_ALARM_TYPE_PROCEDURE;
	case I_ALARM_TYPE_EMAIL:
		return KLBX_INC_ADV_ALARM_TYPE_EMAIL;
	default:
		return KLBX_INC_ADV_ALARM_TYPE_DISPLAY;
	}
}

/**
 * Convert a role enumeration value from an internal event or task to a
 * Kolab XML attendee role value.
 *
 * @param  role
 *         a role enumeration value from an internal event or task
 * @return a Kolab XML attendee role value
 */
static gchar*
incidence_role_i_to_k (Incidence_role role)
{
	switch (role) {
	case I_INC_ROLE_REQUIRED:
		return KLB_INC_ATTENDEE_ROLE_REQUIRED;
	case I_INC_ROLE_OPTIONAL:
		return KLB_INC_ATTENDEE_ROLE_OPTIONAL;
	case I_INC_ROLE_RESOURCE:
		return KLB_INC_ATTENDEE_ROLE_RESOURCE;
	default:
		return KLB_INC_ATTENDEE_ROLE_REQUIRED;
	}
}

/**
 * Convert a status enumeration value from an internal event or task to a
 * Kolab XML attendee status value.
 *
 * @param  status
 *         a status enumeration value from an internal event or task
 * @return a Kolab XML attendee status value
 */
static gchar*
incidence_status_i_to_k (Incidence_status status)
{
	switch (status) {
	case I_INC_STATUS_NONE:
		return KLB_INC_ATTENDEE_STATUS_NONE;
	case I_INC_STATUS_TENTATIVE:
		return KLB_INC_ATTENDEE_STATUS_TENTATIVE;
	case I_INC_STATUS_ACCEPTED:
		return KLB_INC_ATTENDEE_STATUS_ACCEPTED;
	case I_INC_STATUS_DECLINED:
		return KLB_INC_ATTENDEE_STATUS_DECLINED;
	case I_INC_STATUS_DELEGATED:
		return KLBX_INC_ATTENDEE_STATUS_DELEGATED;
	default:
		return "None";
	}
}


/**
 * Add kolab day nodes which are defined by the weekdays bitset parameter to the
 * given recurrence node.
 *
 * @param  node
 *         The recurrence kolab xml node
 * @param  weekdays
 *         A bitset which defines a subset of the seven weekdays
 */
static void
weekday_i_to_k (xmlNodePtr node, gint weekdays)
{
	if (!weekdays) /* nothing to add => exit */
		return;
	if (weekdays & I_COMMON_MONDAY)
		add_child_node(node, KLB_INC_RCR_DAY, KLB_INC_RCR_DAY_MONDAY);
	if (weekdays & I_COMMON_TUESDAY)
		add_child_node(node, KLB_INC_RCR_DAY, KLB_INC_RCR_DAY_TUESDAY);
	if (weekdays & I_COMMON_WEDNESDAY)
		add_child_node(node, KLB_INC_RCR_DAY, KLB_INC_RCR_DAY_WEDNESDAY);
	if (weekdays & I_COMMON_THURSDAY)
		add_child_node(node, KLB_INC_RCR_DAY, KLB_INC_RCR_DAY_THURSDAY);
	if (weekdays & I_COMMON_FRIDAY)
		add_child_node(node, KLB_INC_RCR_DAY, KLB_INC_RCR_DAY_FRIDAY);
	if (weekdays & I_COMMON_SATURDAY)
		add_child_node(node, KLB_INC_RCR_DAY, KLB_INC_RCR_DAY_SATURDAY);
	if (weekdays & I_COMMON_SUNDAY)
		add_child_node(node, KLB_INC_RCR_DAY, KLB_INC_RCR_DAY_SUNDAY);
}

/**
 * Convert an internal recurrence structure to a Kolab XML node.
 *
 * @param  recurrence
 *         an internal recurrence structure
 * @param  node
 *         An empty Kolab XML node which will be filled with recurrence data
 */
static void
recurrence_i_to_k(const Recurrence *recurrence, xmlNodePtr node)
{
	gchar *dnstr = NULL;
	gchar *daynr_str = NULL;
	gchar *monthStr = NULL;
	gchar *monthStr_ = NULL;
	gchar *date_str = NULL;
	gchar *nbr_str = NULL;
	xmlNodePtr n_range = NULL;
	GList *exclusion_list = NULL;

	if (recurrence->interval != -1) {
		gchar *ristr = g_strdup_printf ("%d", recurrence->interval);
		add_child_node(node, KLB_INC_RCR_INTERVAL, ristr);
		g_free(ristr);
	}

	weekday_i_to_k(node, recurrence->weekdays);

	switch (recurrence->recurrence_cycle) {
	case I_REC_CYCLE_DAILY:
		add_property(node, KLB_INC_RCR_CYCLE, "daily");
		break;
	case I_REC_CYCLE_WEEKLY:
		add_property(node, KLB_INC_RCR_CYCLE, "weekly");
		break;
	case I_REC_CYCLE_MONTHLY_DAYNUMBER:
		add_property(node, KLB_INC_RCR_CYCLE, "monthly");
		add_property(node, KLB_INC_RCR_CYCLETYPE, "daynumber");
		dnstr = g_strdup_printf ("%d", recurrence->day_number);
		add_child_node(node, KLB_INC_RCR_DAYNUMBER, dnstr);
		g_free(dnstr);
		break;
	case I_REC_CYCLE_MONTHLY_WEEKDAY:
		add_property(node, KLB_INC_RCR_CYCLE, "monthly");
		add_property(node, KLB_INC_RCR_CYCLETYPE, "weekday");
		dnstr = g_strdup_printf ("%d", recurrence->day_number);
		add_child_node(node, KLB_INC_RCR_DAYNUMBER, dnstr);
		g_free(dnstr);
		break;
	case I_REC_CYCLE_YEARLY_MONTHDAY:
		add_property(node, KLB_INC_RCR_CYCLE, "yearly");
		add_property(node, KLB_INC_RCR_CYCLETYPE, "monthday");
		dnstr = g_strdup_printf ("%d", recurrence->day_number);
		add_child_node(node, KLB_INC_RCR_DAYNUMBER, dnstr);
		g_free(dnstr);
		monthStr = recurrence_month_i_to_k(recurrence->month);
		add_child_node(node, KLB_INC_RCR_MONTH, monthStr);
		break;
	case I_REC_CYCLE_YEARLY_YEARDAY:
		add_property(node, KLB_INC_RCR_CYCLE, "yearly");
		add_property(node, KLB_INC_RCR_CYCLETYPE, "yearday");
		dnstr = g_strdup_printf ("%d", recurrence->day_number);
		add_child_node(node, KLB_INC_RCR_DAYNUMBER, dnstr);
		g_free(dnstr);
		break;
	case I_REC_CYCLE_YEARLY_WEEKDAY:
		add_property(node, KLB_INC_RCR_CYCLE, "yearly");
		add_property(node, KLB_INC_RCR_CYCLETYPE, "weekday");
		daynr_str = g_strdup_printf ("%d", recurrence->day_number);
		add_child_node(node, KLB_INC_RCR_DAYNUMBER, daynr_str);
		g_free(daynr_str);
		monthStr_ = recurrence_month_i_to_k(recurrence->month);
		add_child_node(node, KLB_INC_RCR_MONTH, monthStr_);
		break;
	default:
		log_debug("illegal recurrence cycle %d: ", recurrence->recurrence_cycle);
	}

	n_range = add_child_node(node, KLB_INC_RCR_RANGE, NULL);

	if (recurrence->range_date != NULL) {
		add_property(n_range, KLB_INC_RCR_RANGETYPE, KLB_INC_RCR_RANGETYPE_DATE);
		date_str = g_date_to_string (recurrence->range_date);
		xmlNodeSetContent(n_range, (xmlChar*) date_str);
		g_free(date_str);
	} else if (recurrence->range_number != NULL) {
		add_property(n_range, KLB_INC_RCR_RANGETYPE, KLB_INC_RCR_RANGETYPE_NUMBER);
		nbr_str = g_strdup_printf ("%d", *(recurrence->range_number));
		xmlNodeSetContent(n_range, (xmlChar*) nbr_str);
		g_free(nbr_str);
	} else
		add_property(n_range, KLB_INC_RCR_RANGETYPE, KLB_INC_RCR_RANGETYPE_NONE);

	exclusion_list = recurrence->exclusion;
	while (exclusion_list) {
		GDate *excl_date = exclusion_list->data;
		gchar *excl_string = g_date_to_string(excl_date);
		add_child_node(node, KLB_INC_RCR_EXCLUSION, excl_string);
		g_free(excl_string);
		exclusion_list = exclusion_list->next;
	}
}
