/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/*
 * contact-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"
#include "kolab.h" /* public part of this file */
#include "../util.h"
#include <libxml/tree.h>	/* XML parsing */

/*
 * Prototypes for static functions
 */
static gchar *address_type_i_to_k(Icontact_address_type I_addr_type);
static gchar *i_contact_to_xml (const I_contact* i_contact);
static GList *process_contact_i_to_k (I_contact **i_contact_ptr);
static gchar *phone_type_i_to_k(Icontact_phone_type i_phone_type);


/**
 * Convert libekolabconv I_contact to Kolab_conv_mail
 */
Kolab_conv_mail*
conv_I_contact_to_kolab_conv_mail (I_contact **i_contact, GError **error)
{
	GList *kolab_conv_mail_list = NULL;

	g_assert(error != NULL && *error == NULL);

	log_debug ("\nconv_I_contact_to_kolab_conv_mail(): convert I_contact to Kolab_conv_mail.");

	if (*i_contact)
		kolab_conv_mail_list = process_contact_i_to_k (i_contact);

	return g_list_to_kolab_conv_mail(kolab_conv_mail_list);
}


/**
 * This method expects a populated icontact and converts it into kolabMailPartArray
 * in correct order as it was originally.
 * 1. Firstly it constructs an xml tree from scratch from all the fields in icontact.
 * 2. Then it generates a picture attachemnt if one is present in icontact.
 * 3. Then it does the same for extra attachments if there are any.
 *
 */
static GList*
process_contact_i_to_k (I_contact **i_contact_ptr)
{
	I_contact *i_contact = *i_contact_ptr;
	GList* mail_part_list = NULL;
	Kolab_conv_mail_part *mail_part;

	gchar *xml_text = i_contact_to_xml (i_contact);

	log_debug("\nXml Text:\n%s",xml_text);

	/* ADD XML mailPart */
	mail_part = g_new0(Kolab_conv_mail_part, 1);
	mail_part->data = xml_text;
	mail_part->length = strlen (xml_text);
	mail_part->mime_type = g_strdup ("application/x-vnd.kolab.contact");
	mail_part->name = g_strdup ("kolab-common1.xml"); /* Change it after adding a field in contact.h */
	/* mailPart->order = 1; Change it after adding a field in contact.h */

	mail_part_list = g_list_append (mail_part_list, (Kolab_conv_mail_part *) mail_part);

	/* ADD Picture Attachment */
	if (i_contact->photo != NULL) {
#if 0
		mail_part = clone_kolab_conv_mail_part(i_contact->photo);
		mail_part = i_contact->photo;
#endif
		mail_part_list = g_list_append (mail_part_list, i_contact->photo);
		i_contact->photo = NULL; /* so that free_i_contact() doesn't free the struct */
	}

	mail_part_list = g_list_concat(mail_part_list, g_list_copy(i_contact->common->kolab_attachment_store));

	free_i_contact(i_contact_ptr);
	*i_contact_ptr = NULL;

	return mail_part_list;
}


/*
 * Construct an xml tree from icontact and return a string representation of it.
 * Also convert custom fields in icontact to xml tags x-custom.
 * As a last part of this step, xml trees stored in kolab_store are also merged into the main xml tree.
 */
static gchar *
i_contact_to_xml (const I_contact* i_contact)
{
	GString *xml_string = g_string_new ("");

	xmlNodePtr root_node, node;
	xmlDocPtr doc;
	xmlChar *xml_buf;
	GList *iterator;
	gint buf_size;

	/*
	 * Create the document.
	 */
	doc = xmlNewDoc(BAD_CAST "1.0");
	root_node = xmlNewNode(NULL, BAD_CAST KLB_CNT);
	add_property (root_node, "version", "1.0");
	/* xmlNodeSetContent(root_node, BAD_CAST "content"); */
	xmlDocSetRootElement (doc, root_node);

	common_i_to_k(root_node, i_contact->common);

	/*
	 * write name and subnotes
	 */
	node = add_child_node (root_node, KLB_CNT_NAME, NULL);
	if (i_contact->given_name)
		add_child_node (node, KLB_CNT_NAME_GIVEN_NAME, i_contact->given_name->str);
	if (i_contact->middle_names)
		add_child_node (node, KLB_CNT_NAME_MIDDLE_NAMES, i_contact->middle_names->str);
	if (i_contact->last_name)
		add_child_node (node, KLB_CNT_NAME_LAST_NAME, i_contact->last_name->str);
	if (i_contact->full_name)
		add_child_node (node, KLB_CNT_NAME_FULL_NAME, i_contact->full_name->str);
	if (i_contact->prefix)
		add_child_node (node, KLB_CNT_NAME_PREFIX, i_contact->prefix->str);
	if (i_contact->suffix)
		add_child_node (node, KLB_CNT_NAME_SUFFIX, i_contact->suffix->str);

	i_kolab_store_get_xml_nodes(i_contact->common, (gpointer) KOLAB_STORE_PTR_CONTACT_NAME, node);

	/*
	 * write media elements
	 */
	if (i_contact->photo && i_contact->photo->name)
		add_child_node (root_node, KLB_CNT_PICTURE, i_contact->photo->name);

	if (i_contact->organization)
		add_child_node (root_node, KLB_CNT_ORGANIZATION, i_contact->organization->str);
	if (i_contact->web_page)
		add_child_node (root_node, KLB_CNT_WEB_PAGE, i_contact->web_page->str);
	if (i_contact->department)
		add_child_node (root_node, KLB_CNT_DEPARTMENT, i_contact->department->str);
	if (i_contact->office_location)
		add_child_node (root_node, KLB_CNT_OFFICE_LOCATION, i_contact->office_location->str);
	if (i_contact->profession)
		add_child_node (root_node, KLB_CNT_PROFESSION, i_contact->profession->str);
	if (i_contact->free_busy_url)
		add_child_node (root_node, KLB_CNT_FREE_BUSY_URL, i_contact->free_busy_url->str);
	if (i_contact->job_title)
		add_child_node (root_node, KLB_CNT_JOB_TITLE, i_contact->job_title->str);
	if (i_contact->manager_name)
		add_child_node (root_node, KLB_CNT_MANAGER_NAME, i_contact->manager_name->str);
	if (i_contact->assistant)
		add_child_node (root_node, KLB_CNT_ASSISTANT, i_contact->assistant->str);
	if (i_contact->nick_name)
		add_child_node (root_node, KLB_CNT_NICK_NAME, i_contact->nick_name->str);
	if (i_contact->birthday) {
		gchar *datestr = g_date_to_string (i_contact->birthday);
		add_child_node (root_node, KLB_CNT_BIRTHDAY, datestr);
		g_free(datestr);
	}
	if (i_contact->spouse_name)
		add_child_node (root_node, KLB_CNT_SPOUSE_NAME, i_contact->spouse_name->str);
	if (i_contact->anniversary) {
		gchar *datestr = g_date_to_string (i_contact->anniversary);
		add_child_node (root_node, KLB_CNT_ANNIVERSARY, datestr);
		g_free(datestr);
	}

	iterator = i_contact->phone_numbers;
	while (iterator != NULL) {
		Phone_number *phone_nr = ((Phone_number *) iterator->data);
		Phone_number *phone_nr_next = NULL;
		if (iterator->next != NULL) {
			phone_nr_next = ((Phone_number *) iterator->next->data);
		}

		if (phone_nr_next != NULL) {
			if (strcmp(phone_nr->number, phone_nr_next->number) == 0
			    && phone_nr->type != ICONTACT_PHONE_PRIMARY
			    && phone_nr_next->type == ICONTACT_PHONE_PRIMARY )	/* TODO: Reconsider if primary number is still next element after reconverting from evolution, or if it has to be searched in the whole list. */
				{
					if (phone_nr->type == ICONTACT_PHONE_BUSINESS_1) {
						phone_nr->type = ICONTACT_PHONE_BUSINESS_2;	/* business 2 = business 1 + primary */
						iterator = iterator->next; /* -primary */
					}
					else if (phone_nr->type == ICONTACT_PHONE_HOME_1) {
						phone_nr->type = ICONTACT_PHONE_HOME_2; 	/* home 2 = home 1 + primary */
						iterator = iterator->next; /* -primary */
					}
				}
		}

		node = add_child_node (root_node, KLB_CNT_PHONE_LIST, NULL);
		if (phone_nr->type)
			add_child_node (node, KLB_CNT_PHONE_TYPE, phone_type_i_to_k (phone_nr->type));
		if (phone_nr->number)
			add_child_node (node, KLB_CNT_PHONE_NUMBER, phone_nr->number);

		i_kolab_store_get_xml_nodes(i_contact->common, phone_nr, node);

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

	/* E-Mails */
	iterator = i_contact->emails;
	while (iterator != NULL) {

		Email *email = ((Email *) iterator->data);

		node = add_child_node (root_node, KLB_CNT_EMAIL_LIST, NULL);
		if (email->smtp_address)
			add_child_node (node, KLB_CNT_EMAIL_SMTP_ADDRESS, email->smtp_address->str);

		/* display name and unknown elements in kolab store */
		i_kolab_store_get_xml_nodes(i_contact->common, email, node);

		iterator = iterator->next;
	}

	g_list_free(iterator);

	/* Addresses */
	iterator = i_contact->addresses;
	while (iterator != NULL) {
		Address *address = ((Address *) iterator->data);

		node = add_child_node (root_node, KLB_CNT_ADDRESS_LIST, NULL);
		if (address->type)
			add_child_node (node, KLB_CNT_ADDRESS_TYPE, address_type_i_to_k(address->type));
		/* add_child_node(node, "x-kde-type", anAddress->address_type); */
		if (address->street)
			add_child_node (node, KLB_CNT_ADDRESS_STREET, address->street->str);
		if (address->pobox)
			add_child_node (node, KLBX_CNT_ADDRESS_POBOX, address->pobox->str);
		if (address->locality)
			add_child_node (node, KLB_CNT_ADDRESS_LOCALITY, address->locality->str);
		if (address->region)
			add_child_node (node, KLB_CNT_ADDRESS_REGION, address->region->str);
		if (address->postal_code)
			add_child_node (node, KLB_CNT_ADDRESS_POSTAL_CODE,
			                address->postal_code->str);
		if (address->country)
			add_child_node (node, KLB_CNT_ADDRESS_COUNTRY, address->country->str);

		i_kolab_store_get_xml_nodes(i_contact->common, address, node);

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

	/* GEO */
	if (i_contact->latitude >= -90 && i_contact->latitude <= 90
	    && i_contact->longitude >= -180 && i_contact->longitude <= 180) {
		gchar *lat = g_strdup_printf("%.16f", i_contact->latitude);
		gchar *lon = NULL;
		add_child_node(root_node, KLB_CNT_LATITUDE, lat);
		lon = g_strdup_printf("%.16f", i_contact->longitude);
		add_child_node(root_node, KLB_CNT_LONGITUDE, lon);
		g_free(lat);
		g_free(lon);
	}

	i_kolab_store_get_xml_nodes(i_contact->common, i_contact->common, root_node);

	/* Add x-custom fields in xmltree from the custom-list of icontact. */
	iterator = i_contact->custom_list;
	while (iterator != NULL) {
		Custom * custom_field = ((Custom *) iterator->data);

		/* log_debug("\nCustom field to be put in xml is: app=%s, name=%s, value=%s\n", */
		/* customField->app->str, customField->name->str, customField->value->str); */

		node = add_child_node (root_node, KLBX_CNT_X_CUSTOM_LIST, NULL);
		add_property (node, KLBX_CNT_X_CUSTOM_VALUE, custom_field->value->str);
		add_property (node, KLBX_CNT_X_CUSTOM_APP, custom_field->app->str);
		add_property (node, KLBX_CNT_X_CUSTOM_NAME, custom_field->name->str);

		/* Add x-custom node to the main xml tree node. */
		xmlAddChild (root_node, node);

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

	/* Convert xml to a string */
	xmlDocDumpFormatMemoryEnc (doc, &xml_buf, &buf_size, "UTF-8", 1);
	g_string_append (xml_string, (gchar*) xml_buf);
	/* log_debug("%s", (gchar *) xml_buf); */

	/* free associated memory. */

	xmlFree (xml_buf);
	xmlFreeDoc (doc);

	return g_string_free(xml_string, FALSE);
}


/**
 * convert libekolabconv I_address_type to Kolab string constant
 */
static gchar*
address_type_i_to_k(Icontact_address_type I_addr_type)
{
	switch (I_addr_type) {
	case ICONTACT_ADDR_TYPE_HOME:
		return KLB_CNT_ADDRESS_TYPE_HOME;
	case ICONTACT_ADDR_TYPE_BUSINESS:
		return KLB_CNT_ADDRESS_TYPE_BUSINESS;
	case ICONTACT_ADDR_TYPE_OTHER:
	default:
		return KLB_CNT_ADDRESS_TYPE_OTHER;
	}
}


/*
 * map icontact phone type to kolab phone type
 */
static gchar*
phone_type_i_to_k(Icontact_phone_type i_phone_type)
{
	switch(i_phone_type) {
	case ICONTACT_PHONE_ASSISTANT:
		return KLB_CNT_PHONE_TYPE_ASSISTANT;
	case ICONTACT_PHONE_BUSINESS_1:
		return KLB_CNT_PHONE_TYPE_BUSINESS_1;
	case ICONTACT_PHONE_BUSINESS_2:
		return KLB_CNT_PHONE_TYPE_BUSINESS_2;
	case ICONTACT_PHONE_BUSINESS_FAX:
		return KLB_CNT_PHONE_TYPE_BUSINESS_FAX;
	case ICONTACT_PHONE_CALLBACK:
		return KLB_CNT_PHONE_TYPE_CALLBACK;
	case ICONTACT_PHONE_CAR:
		return KLB_CNT_PHONE_TYPE_CAR;
	case ICONTACT_PHONE_COMPANY:
		return KLB_CNT_PHONE_TYPE_COMPANY;
	case ICONTACT_PHONE_HOME_1:
		return KLB_CNT_PHONE_TYPE_HOME_1;
	case ICONTACT_PHONE_HOME_2:
		return KLB_CNT_PHONE_TYPE_HOME_2;
	case ICONTACT_PHONE_HOME_FAX:
		return KLB_CNT_PHONE_TYPE_HOME_FAX;
	case ICONTACT_PHONE_ISDN:
		return KLB_CNT_PHONE_TYPE_ISDN;
	case ICONTACT_PHONE_MOBILE:
		return KLB_CNT_PHONE_TYPE_MOBILE;
	case ICONTACT_PHONE_OTHER:
		return KLB_CNT_PHONE_TYPE_OTHER;
	case ICONTACT_PHONE_PAGER:
		return KLB_CNT_PHONE_TYPE_PAGER;
	case ICONTACT_PHONE_PRIMARY:
		return KLB_CNT_PHONE_TYPE_PRIMARY;
	case ICONTACT_PHONE_RADIO:
		return KLB_CNT_PHONE_TYPE_RADIO;
	case ICONTACT_PHONE_TELEX:
		return KLB_CNT_PHONE_TYPE_TELEX;
	case ICONTACT_PHONE_TTYTDD:
		return KLB_CNT_PHONE_TYPE_TTYTDD;
	default:
		return KLB_CNT_PHONE_TYPE_PRIMARY;
	}
}
