/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/*
 * task-k-to-i.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
 */


/*
 * This file holds operations to read the kolab task fields from an XML tree to
 * an internal structure.
 *
 * The related header file is: kolab.h
 */

#include <config.h>

#include <glib/gi18n-lib.h>

#include <errno.h>
#include "priv-kolab.h"
#include "../util.h"
#include "kolab.h" /* public part of this file */


/*
 * Prototypes for static functions
 */
static void read_task(I_task *i_task, xmlNodePtr task_node, GError **error);
static gboolean read_task_element(I_task *i_task, xmlNodePtr node, GError **error);
static gboolean handle_element_status (I_task *i_task, xmlNodePtr node);
gboolean handle_element_priority (gchar* name, gint *store, xmlNodePtr node);


/**
 * convert Kolab_conv_mail struct to libekolabconv I_task
 */
I_task*
conv_kolab_conv_mail_to_I_task (const Kolab_conv_mail *k_task, GError **error)
{
	I_task *i_task = NULL;
	xmlDocPtr doc = NULL;
	xmlNodePtr node = NULL, n;

	if (*error != NULL)
		return NULL;

	/* get parsed kolab XML */
	i_task = new_i_task();
	doc = util_get_kolab_xml_part(k_task, &i_task->incidence->common->kolab_attachment_store, error);

	/* find root node */
	for (n = doc->children; n != NULL; n = n->next)
		if (n->type == XML_ELEMENT_NODE && strcmp ((gchar*)n->name, KLB_TASK) == 0)
			node = n;

	if (node == NULL) {
		g_set_error (error, KOLABCONV_ERROR_READ_KOLAB,
		             KOLABCONV_ERROR_READ_KOLAB_INVALID_KOLAB_XML,
		             _("Root tag is missing"));
		free_i_task(&i_task);
		xmlFreeDoc(doc);
		return NULL;
	}

	read_task(i_task, node, error);
	xmlFreeDoc(doc);
	if (*error != NULL) {
		free_i_task(&i_task);
		return NULL;
	}
	return i_task;
}

/**
 * This function reads all xml tags from kolab file and calls the task handling function
 * which saves values or returns false. In case of false, node is written in kolab store.
 */
static void
read_task(I_task *i_task, xmlNodePtr task_node, GError **error)
{
	xmlNodePtr rec_ptr = NULL; /* pointer used to temporarily store recurrence node */

	/* iterate over all child elements of event_node an process them */
	xmlNodePtr node; /* used in for loop */
	for (node = task_node->children; node != NULL; node = node->next) {
		if (node->type == XML_ELEMENT_NODE) {
			gboolean node_processed = FALSE;
			/* save recurrence node in case recurrence has to be
			 * stored in kolabstore due to missing start_date
			 */
			if (strcmp ((gchar*) node->name, KLB_INC_RECURRENCE) == 0)
				rec_ptr = node;

			node_processed = read_task_element(i_task, node, error);

			if (*error != NULL)
				return;

			if (!node_processed)
				i_kolab_store_add_xml_element(i_task->incidence->common, i_task->incidence->common, node);

		} else
			log_debug("ignored XML node with name %s", node->name);
	}

	/* cannot be properly converted back from evolution when startdate is missing, therefore => kolabstore */
	if (i_task->incidence
	    && i_task->incidence->recurrence
	    && !i_task->incidence->start_date
	    && (i_task->incidence->recurrence->recurrence_cycle == I_REC_CYCLE_YEARLY_MONTHDAY
	        || i_task->incidence->recurrence->recurrence_cycle == I_REC_CYCLE_YEARLY_WEEKDAY)) {

		g_free(i_task->incidence->recurrence);
		i_task->incidence->recurrence = NULL;

		i_kolab_store_add_xml_element(i_task->incidence->common, i_task->incidence->common, rec_ptr);
	}

	/* TODO: Validate itask. (log warnings / create error if necessary) */
}


/**
 * This function handles all available specific task node types in kolab and saves
 * them to intern structure. If no fitting element found it returns FALSE.
 */
static gboolean
read_task_element(I_task *i_task, xmlNodePtr node, GError **error)
{
	if (conv_incidence_k_to_i(i_task->incidence, node, error))
		return TRUE;
	else if (*error != NULL)
		return FALSE;
	return
		handle_element_priority(KLB_TASK_PRIORITY, &i_task->priority, node) ||		/* calculate and overwrite detailed priority from normal priority when detailed priority not set yet */
		handle_element_integer(KLBX_TASK_KCAL_PRIORITY, &i_task->priority, node) ||	/* always read and overwrite detailed priority */
		handle_element_integer(KLB_TASK_COMPLETED, (gint*)&i_task->completed, node) ||
		handle_element_status(i_task, node) ||
		handle_element_date_or_datetime(KLB_TASK_DUE_DATE, &i_task->due_date, node) ||
		handle_element_datetime(KLBX_TASK_COMPLETED_DATE, &i_task->completed_datetime, node);
}


/**
 * Parse the text node of the given xml element node if it is a Task_status
 * element and set the Task_status property in the itask parameter.
 *
 * @param  itask
 * @param  node
 * @return true if the given xml element is a sensitivity element
 */
static gboolean
handle_element_status (I_task *i_task, xmlNodePtr node)
{
	gchar *value = NULL;

	if (strcmp ((gchar*) node->name, KLB_TASK_STATUS) != 0)
		return FALSE;

	value = xml_get_node_text(node);
	if (strcmp ((gchar*) value, KLB_TASK_STATUS_NOT_STARTED) == 0)
		i_task->status = I_TASK_NOT_STARTED;
	else if (strcmp ((gchar*) value, KLB_TASK_STATUS_IN_PROGRESS) == 0)
		i_task->status = I_TASK_IN_PROGRESS;
	else if (strcmp ((gchar*) value, KLB_TASK_STATUS_COMPLETED) == 0)
		i_task->status = I_TASK_COMPLETED;
	else if (strcmp ((gchar*) value, KLB_TASK_STATUS_WAITING_ON_SOMEONE_ELSE) == 0)
		i_task->status = I_TASK_WAITING_ON_SOMEONE_ELSE;
	else if (strcmp ((gchar*) value, KLB_TASK_STATUS_DEFERRED) == 0)
		i_task->status = I_TASK_DEFERRED;
	else {
		i_task->status = I_TASK_NOT_STARTED;
		log_warn("illegal status value '%s' - status set to Not_Started", value);
	}
	return TRUE;
}

/**
 * Calculate detailed priority from normal priority if detailed priority is not set yet.
 */
gboolean
handle_element_priority (gchar* name, gint *store, xmlNodePtr node)
{
	gchar *value = NULL;
	gchar *p = NULL;

	if (g_strcmp0 ((gchar *) node->name, name) != 0)
		return FALSE;

	value = xml_get_node_text(node);
	g_debug ("**** handle_element_priority() node: %s - value: %s", node->name, value);
	if (*store == -1) {	/* already set? */
		errno = 0;
		*store = priority_k_to_xkcal(strtol(value, &p, 10));
		if (errno != 0 || *p != 0 || p == value)
			log_warn("illegal integer value in element %s", name); /* TODO error handling */
	}
	return TRUE;
}
