/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* 
 * Authors : 
 *  JP Rosevear <jpr@ximian.com>
 *  Rodrigo Moya <rodrigo@ximian.com>
 *
 * Copyright 2003, Novell, Inc.
 *
 * This program is free software; you can redistribute it and/or 
 * modify it under the terms of version 2 of the GNU Lesser General Public 
 * License as published by the Free Software Foundation.
 *
 * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include "e-gw-connection.h"
#include "e-gw-sendoptions.h"
#include "e-gw-message.h"

struct _EGwSendOptionsPrivate {
	EGwSendOptionsGeneral *gopts;
	EGwSendOptionsStatusTracking *mopts;
	EGwSendOptionsStatusTracking *copts;
	EGwSendOptionsStatusTracking *topts;
};

static GObjectClass *parent_class = NULL;

static gboolean e_gw_sendoptions_store_settings (SoupSoapParameter *param, EGwSendOptions *opts);
static void e_gw_sendoptions_init (GObject *object);
static void e_gw_sendoptions_class_init (GObjectClass *klass);
static void e_gw_sendoptions_dispose (GObject *object);
static void e_gw_sendoptions_finalize (GObject *object);

EGwSendOptionsGeneral*
e_gw_sendoptions_get_general_options (EGwSendOptions *opts) 
{
	g_return_val_if_fail (opts != NULL || E_IS_GW_SENDOPTIONS (opts), NULL);

	return opts->priv->gopts;
}

EGwSendOptionsStatusTracking*
e_gw_sendoptions_get_status_tracking_options (EGwSendOptions *opts, char *type)
{
	g_return_val_if_fail (opts != NULL || E_IS_GW_SENDOPTIONS (opts), NULL);
	g_return_val_if_fail (type != NULL, NULL);

	if (!strcasecmp (type, "mail"))
		return opts->priv->mopts;
	else if (!strcasecmp (type, "calendar"))
		return opts->priv->copts;
	else if (!strcasecmp (type, "task"))
		return opts->priv->topts;
	else
		return NULL;
}

static void
e_gw_sendoptions_dispose (GObject *object)
{
	EGwSendOptions *opts = (EGwSendOptions *) object;

	g_return_if_fail (E_IS_GW_SENDOPTIONS (opts));

	if (parent_class->dispose)
		(* parent_class->dispose) (object);
}

static void
e_gw_sendoptions_finalize (GObject *object) 
{
	EGwSendOptions *opts = (EGwSendOptions *) object;
	EGwSendOptionsPrivate *priv;

	g_return_if_fail (E_IS_GW_SENDOPTIONS (opts));

	priv = opts->priv;
	
	if (priv->gopts) {
		g_free (priv->gopts);
		priv->gopts = NULL;
	}

	if (priv->mopts) {
		g_free (priv->mopts);
		priv->mopts = NULL;
	}

	if (priv->copts) {
		g_free (priv->copts);
		priv->copts = NULL;
	}

	if (priv->topts) {
		g_free (priv->topts);
		priv->topts = NULL;
	}

	if (priv) {
		g_free (priv);
		opts->priv = NULL;
	}

	if (parent_class->finalize)
		(* parent_class->finalize) (object);
}

static void
e_gw_sendoptions_class_init (GObjectClass *klass)
{
	GObjectClass *object_class = G_OBJECT_CLASS (klass);

	parent_class = g_type_class_peek_parent (klass);

	object_class->dispose = e_gw_sendoptions_dispose;
	object_class->finalize = e_gw_sendoptions_finalize;
}

static void
e_gw_sendoptions_init (GObject *object)
{		
	EGwSendOptions *opts;
	EGwSendOptionsPrivate *priv;

	opts = E_GW_SENDOPTIONS (object);

	/* allocate internal structure */
	priv = g_new0 (EGwSendOptionsPrivate, 1);
	priv->gopts = g_new0 (EGwSendOptionsGeneral, 1);
	priv->mopts = g_new0 (EGwSendOptionsStatusTracking, 1);
	priv->copts = g_new0 (EGwSendOptionsStatusTracking, 1);
	priv->topts = g_new0 (EGwSendOptionsStatusTracking, 1);
	opts->priv = priv;
}

GType
e_gw_sendoptions_get_type (void)
{
	static GType type = 0;

	if (!type) {
		static GTypeInfo info = {
                        sizeof (EGwSendOptionsClass),
                        NULL,
                        NULL,
                        (GClassInitFunc) e_gw_sendoptions_class_init,
                        NULL, NULL,
                        sizeof (EGwSendOptions),
                        0,
                        (GInstanceInitFunc) e_gw_sendoptions_init,
			NULL
                };
		type = g_type_register_static (G_TYPE_OBJECT, "EGwSendOptions", &info, 0);
	}

	return type;
}

static void
parse_status_tracking_options (SoupSoapParameter *group_param, guint i, EGwSendOptionsStatusTracking *sopts)
{
	SoupSoapParameter *subparam, *field_param, *val_param;

	for (subparam = soup_soap_parameter_get_first_child_by_name(group_param, "setting") ;
			     subparam != NULL ;
			     subparam = soup_soap_parameter_get_next_child_by_name (subparam, "setting")) {

		char *field = NULL, *val = NULL;
		field_param = soup_soap_parameter_get_first_child_by_name (subparam, "field");
		val_param = soup_soap_parameter_get_first_child_by_name (subparam, "value");
		
		if (field_param) {
			field = soup_soap_parameter_get_string_value (field_param);
			if (!field)
				continue;
		} else
			continue;

		if (!g_ascii_strcasecmp (field + i, "StatusInfo")) {
			if (val_param)
				val = soup_soap_parameter_get_string_value (val_param);

			if (val) {
				sopts->tracking_enabled = TRUE;
				if (!strcmp (val, "Delivered"))
					sopts->track_when = E_GW_DELIVERED;
				if (!strcmp (val, "DeliveredAndOpened"))
					sopts->track_when = E_GW_DELIVERED_OPENED;
				if (!strcmp (val, "Full"))
					sopts->track_when = E_GW_ALL;
				if (!strcmp (val, "None"))
					sopts->tracking_enabled = FALSE;
			} else
				sopts->tracking_enabled = FALSE;

		} else	if (!g_ascii_strcasecmp (field + i, "AutoDelete")) {
			if (val_param)
				val = soup_soap_parameter_get_string_value (val_param);

			if (val) {
				if (!strcmp (val, "1"))
					sopts->autodelete = TRUE;
				else
					sopts->autodelete = FALSE;
			} else
				sopts->autodelete = FALSE;

		} else if (!g_ascii_strcasecmp (field + i, "ReturnOpen")) {
			val_param = soup_soap_parameter_get_first_child_by_name (val_param, "mail");
			if (val_param)
				val = soup_soap_parameter_get_string_value (val_param);

			if (val && !strcmp (val, "1")) {
				sopts->opened = E_GW_RETURN_NOTIFY_MAIL;
			} else
				sopts->opened = E_GW_RETURN_NOTIFY_NONE;
			

		} else if (!g_ascii_strcasecmp (field + i, "ReturnDelete")) {
			val_param = soup_soap_parameter_get_first_child_by_name (val_param, "mail");
			
			if (val_param)
				val = soup_soap_parameter_get_string_value (val_param);

			if (val && !strcmp (val, "1")) {
				sopts->declined = E_GW_RETURN_NOTIFY_MAIL;
			} else
				sopts->declined = E_GW_RETURN_NOTIFY_NONE;

		} else if (!g_ascii_strcasecmp (field + i, "ReturnAccept")) {
			val_param = soup_soap_parameter_get_first_child_by_name (val_param, "mail");
			
			if (val_param)
				val = soup_soap_parameter_get_string_value (val_param);

			if (val && !strcmp (val, "1")) {
				sopts->accepted = E_GW_RETURN_NOTIFY_MAIL;
			} else
				sopts->accepted = E_GW_RETURN_NOTIFY_NONE;


		} else if (!g_ascii_strcasecmp (field + i, "ReturnCompleted")) {
			val_param = soup_soap_parameter_get_first_child_by_name (val_param, "mail");
			
			if (val_param)
				val = soup_soap_parameter_get_string_value (val_param);

			if (val && !strcmp (val, "1")) {
				sopts->completed = E_GW_RETURN_NOTIFY_MAIL;
			} else
				sopts->completed = E_GW_RETURN_NOTIFY_NONE;

		} 			
		g_free (field);
		g_free (val);		
	}	
}

/* These are not actually general Options. These can be configured seperatly for
   each component. Since win32 shows them as general options, we too do the same 
   way. So the Options are take from the mail setttings */
	
static void 
parse_general_options (SoupSoapParameter *group_param, EGwSendOptionsGeneral *gopts) 
{
	SoupSoapParameter *subparam, *field_param, *val_param;

	for (subparam = soup_soap_parameter_get_first_child_by_name(group_param, "setting") ;
			     subparam != NULL ;
			     subparam = soup_soap_parameter_get_next_child_by_name (subparam, "setting")) {
		char *field = NULL, *val = NULL;
		field_param = soup_soap_parameter_get_first_child_by_name (subparam, "field");
		val_param = soup_soap_parameter_get_first_child_by_name (subparam, "value");
		
		if (field_param) {
			field = soup_soap_parameter_get_string_value (field_param);
			if (!field)
				continue;
		} else
			continue;

		if (!g_ascii_strcasecmp (field, "mailPriority")) {
			if (val_param)
				val = soup_soap_parameter_get_string_value (val_param);

			if (val) {
				if (!strcasecmp (val, "High"))
					gopts->priority = E_GW_PRIORITY_HIGH;
				else if (!strcasecmp (val, "Standard")) {
					gopts->priority = E_GW_PRIORITY_STANDARD;
				} else if (!strcasecmp (val, "Low"))
					gopts->priority = E_GW_PRIORITY_LOW;
				else
					gopts->priority = E_GW_PRIORITY_UNDEFINED;
					
			} else
				gopts->priority = E_GW_PRIORITY_UNDEFINED;
		} else if (!g_ascii_strcasecmp (field, "mailReplyRequested")) {
		       if (val_param)
				val = soup_soap_parameter_get_string_value (val_param);

	       		if (val) {
				if (!strcasecmp (val, "None"))
					gopts->reply_enabled = FALSE;
				else if (!strcasecmp (val, "WhenConvenient")) {
					gopts->reply_enabled = TRUE;
					gopts->reply_convenient = TRUE;
				} else {
					char *temp;
					int i = 0;
					
					val_param = soup_soap_parameter_get_first_child_by_name (val_param, "WithinNDays");
					temp = soup_soap_parameter_get_string_value (val_param); 
				
					if (temp)	
						i = atoi (temp);							

					gopts->reply_within = i;
					gopts->reply_enabled = TRUE;		
					g_free (temp);
				}
			}
		} else if (!g_ascii_strcasecmp (field, "mailExpireDays")) {
			if (val_param)
				val = soup_soap_parameter_get_string_value (val_param);

			if (val) {
				int i = atoi (val);
				if (i != 0)
					gopts->expiration_enabled = TRUE;
				else 
					gopts->expiration_enabled = FALSE;

				gopts->expire_after = i;
			} else
				gopts->expiration_enabled = FALSE;
		}
		g_free (field);
		g_free (val);
	}
}

/* These settings are common to all components */

static void
parse_advanced_settings (SoupSoapParameter *group_param, EGwSendOptionsGeneral *gopts) 
{
	SoupSoapParameter *subparam, *field_param, *val_param;

	for (subparam = soup_soap_parameter_get_first_child_by_name(group_param, "setting") ;
			     subparam != NULL ;
			     subparam = soup_soap_parameter_get_next_child_by_name (subparam, "setting")) {
		char *field = NULL, *val = NULL;
		field_param = soup_soap_parameter_get_first_child_by_name (subparam, "field");
		val_param = soup_soap_parameter_get_first_child_by_name (subparam, "value");
		
		if (field_param) {
			field = soup_soap_parameter_get_string_value (field_param);
			if (!field)
				continue;
		} else
			continue;

		if (!g_ascii_strcasecmp (field, "delayDelivery")) {
			if (val_param)
				val = soup_soap_parameter_get_string_value (val_param);
			if (val) {
				gint i = atoi (val);
				if (i > 0 ) {
					gopts->delay_enabled = TRUE;
					gopts->delay_until = i;
				} else 
					gopts->delay_enabled = FALSE;
			} else
				gopts->delay_enabled = FALSE;
		}
	}
}

/* TODO have to handle the locked settings */
static gboolean
e_gw_sendoptions_store_settings (SoupSoapParameter *param, EGwSendOptions *opts)
{
	SoupSoapParameter *group_param;
	EGwSendOptionsPrivate *priv;

	priv = opts->priv;
	
	for (group_param = soup_soap_parameter_get_first_child_by_name(param, "group") ;
			     group_param != NULL ;
			     group_param = soup_soap_parameter_get_next_child_by_name (group_param, "group")) {
		char *temp = NULL;

		temp = soup_soap_parameter_get_property (group_param, "type");
		
	        if (!temp) 
			continue;

		if (!g_ascii_strcasecmp (temp, "MailMessageSettings")) {
			parse_status_tracking_options (group_param, 4, priv->mopts);
			parse_general_options (group_param, priv->gopts);
		}	
	  	
	        if (!g_ascii_strcasecmp (temp, "AppointmentMessageSettings")) { 
			parse_status_tracking_options (group_param, 11, priv->copts);
		}
	        if (!g_ascii_strcasecmp (temp, "TaskMessageSettings")) 
			parse_status_tracking_options (group_param, 4, priv->topts);

	        if (!g_ascii_strcasecmp (temp, "AdvancedSettings")) 
			parse_advanced_settings (group_param, priv->gopts);

		g_free (temp);
	}
	
	return TRUE;
}

static void
e_gw_sendoptions_write_settings (SoupSoapMessage *msg, char *field_name, char *value, char *value_name, gboolean value_direct)
{
	soup_soap_message_start_element (msg, "setting", NULL, NULL);
	
	soup_soap_message_start_element (msg, "field", NULL, NULL);
	soup_soap_message_write_string (msg, field_name);
	soup_soap_message_end_element (msg);

	soup_soap_message_start_element (msg, "value", NULL, NULL);
	
	if (!value_direct)
		e_gw_message_write_string_parameter (msg, value_name, NULL, value);
	else
		soup_soap_message_write_string (msg, value);

	soup_soap_message_end_element (msg);
	
	soup_soap_message_end_element (msg);	
}	

static void
set_status_tracking_changes (SoupSoapMessage *msg, EGwSendOptionsStatusTracking *n_sopts, EGwSendOptionsStatusTracking *o_sopts, char *comp)
{
	char *value, *comp_name = NULL;

	if (n_sopts->tracking_enabled != o_sopts->tracking_enabled || n_sopts->track_when != o_sopts->track_when) {
		if (n_sopts->tracking_enabled) {
			if (n_sopts->track_when == E_GW_DELIVERED)
				value = g_strdup ("Delivered");
			else if (n_sopts->track_when == E_GW_DELIVERED_OPENED)
				value = g_strdup ("DeliveredAndOpened");
			else
				value = g_strdup ("Full");
		} else
			value = g_strdup ("None");
		comp_name = g_strconcat (comp, "StatusInfo", NULL);
		e_gw_sendoptions_write_settings (msg, comp_name, value, NULL, TRUE);
		g_free (comp_name), comp_name = NULL;
		g_free (value), value = NULL;
	}
		
	if (!strcmp (comp, "mail")) {
		if (n_sopts->autodelete != o_sopts->autodelete) {
			if (n_sopts->autodelete)
				value = g_strdup ("1");
			else
				value = g_strdup ("0");
			comp_name = g_strconcat (comp, "AutoDelete", NULL);
			e_gw_sendoptions_write_settings (msg, comp_name, value, NULL, TRUE);
			g_free (comp_name), comp_name = NULL;
			g_free (value), value = NULL;
		}
	}

	if (n_sopts->opened != o_sopts->opened) {
		comp_name = g_strconcat (comp, "ReturnOpen", NULL);
		if (n_sopts->opened == E_GW_RETURN_NOTIFY_MAIL) {
			value = g_strdup ("1");
			e_gw_sendoptions_write_settings (msg, comp_name, value, "mail", FALSE);
		} else {
			value = g_strdup ("None");
			e_gw_sendoptions_write_settings (msg, comp_name, value, NULL, TRUE);
		}

		g_free (comp_name), comp_name = NULL;
		g_free (value), value = NULL;
	}
	
	if (n_sopts->declined != o_sopts->declined) {
		comp_name = g_strconcat (comp, "ReturnDelete", NULL);
		if (n_sopts->declined == E_GW_RETURN_NOTIFY_MAIL) {
			value = g_strdup ("1");
			e_gw_sendoptions_write_settings (msg, comp_name, value, "mail", FALSE);
		} else {
			value = g_strdup ("None");
			e_gw_sendoptions_write_settings (msg, comp_name, value, NULL, TRUE);
		}

		g_free (comp_name), comp_name = NULL;
		g_free (value), value = NULL;
	}
	
	if (!strcmp (comp, "appointment") || !strcmp (comp, "task")) {
		if (n_sopts->accepted != o_sopts->accepted) {
			comp_name = g_strconcat (comp, "ReturnAccept", NULL);
			if (n_sopts->accepted == E_GW_RETURN_NOTIFY_MAIL) {
				value = g_strdup ("1");
				e_gw_sendoptions_write_settings (msg, comp_name, value, "mail", FALSE);
			} else {
				value = g_strdup ("None");
				e_gw_sendoptions_write_settings (msg, comp_name, value, NULL, TRUE);
			}
	
			g_free (comp_name), comp_name = NULL;
			g_free (value), value = NULL;
		}
	}
	
	if (!strcmp (comp, "task")) {
		if (n_sopts->completed != o_sopts->completed) {
			comp_name = g_strconcat (comp, "ReturnCompleted", NULL);
			if (n_sopts->completed == E_GW_RETURN_NOTIFY_MAIL) {
				value = g_strdup ("1");
				e_gw_sendoptions_write_settings (msg, comp_name, value, "mail", FALSE);
			} else {
				value = g_strdup ("None");
				e_gw_sendoptions_write_settings (msg, comp_name, value, NULL, TRUE);
			}
	
			g_free (comp_name), comp_name = NULL;
			g_free (value), value = NULL;
		}
	}

}

static void
set_general_options_changes (SoupSoapMessage *msg, EGwSendOptionsGeneral *n_gopts, EGwSendOptionsGeneral *o_gopts)
{
	char *value;

	if (n_gopts->priority != o_gopts->priority) {
		if (n_gopts->priority == E_GW_PRIORITY_HIGH)
			value = g_strdup ("High");
		else if (n_gopts->priority == E_GW_PRIORITY_STANDARD)
			value = g_strdup ("Standard");
		else if (n_gopts->priority == E_GW_PRIORITY_LOW)
			value = g_strdup ("Low");
		else 
			value = NULL;
		e_gw_sendoptions_write_settings (msg, "mailPriority", value, NULL, TRUE);
		e_gw_sendoptions_write_settings (msg, "appointmentPriority", value, NULL, TRUE);
		e_gw_sendoptions_write_settings (msg, "taskPriority", value, NULL, TRUE);
		g_free (value), value = NULL;
	}

	if (n_gopts->reply_enabled != o_gopts->reply_enabled || n_gopts->reply_convenient != o_gopts->reply_convenient ||
			n_gopts->reply_within != o_gopts->reply_within) {
		
		if (n_gopts->reply_enabled) {
			if (n_gopts->reply_convenient)
				value = g_strdup ("WhenConvenient");
			else 
				value = g_strdup_printf ("%d", n_gopts->reply_within);	
		} else 
			value = g_strdup ("None");
		
		if (n_gopts->reply_enabled && !n_gopts->reply_convenient)
			e_gw_sendoptions_write_settings (msg, "mailReplyRequested", value, "WithinNDays" , FALSE);
		else
			e_gw_sendoptions_write_settings (msg, "mailReplyRequested", value, NULL, TRUE);

		g_free (value), value = NULL;
	}

	if (n_gopts->expiration_enabled != o_gopts->expiration_enabled || n_gopts->expire_after != o_gopts->expire_after) {
		if (n_gopts->expiration_enabled) {
			value = g_strdup_printf ("%d", n_gopts->expire_after);
		} else
			value = g_strdup ("0");
		
		e_gw_sendoptions_write_settings (msg, "mailExpireDays", value, NULL, TRUE);
		g_free (value), value = NULL;
	}

	if (n_gopts->delay_enabled != o_gopts->delay_enabled || n_gopts->delay_until != o_gopts->delay_until) {
		if (n_gopts->delay_enabled) {
			value = g_strdup_printf ("%d", n_gopts->delay_until);
		} else
			value = g_strdup ("-1");
		
		e_gw_sendoptions_write_settings (msg, "delayDelivery", value, NULL, TRUE);
		g_free (value), value = NULL;
	}
}

/* n_opts has the new options, o_opts has the old options settings */
gboolean 
e_gw_sendoptions_form_message_to_modify (SoupSoapMessage *msg, EGwSendOptions *n_opts, EGwSendOptions *o_opts)
{
	g_return_val_if_fail (n_opts != NULL || o_opts != NULL, FALSE);
	g_return_val_if_fail (E_IS_GW_SENDOPTIONS (n_opts) || E_IS_GW_SENDOPTIONS (o_opts), FALSE);

	soup_soap_message_start_element (msg, "settings", NULL, NULL);

	set_general_options_changes (msg, n_opts->priv->gopts, o_opts->priv->gopts);
	set_status_tracking_changes (msg, n_opts->priv->mopts, o_opts->priv->mopts, "mail");
	set_status_tracking_changes (msg, n_opts->priv->copts, o_opts->priv->copts, "appointment");
	set_status_tracking_changes (msg, n_opts->priv->topts, o_opts->priv->topts, "task");
	
	soup_soap_message_end_element (msg);

	return TRUE;
}

EGwSendOptions *
e_gw_sendoptions_new ()
{
	EGwSendOptions *opts;

	opts = g_object_new (E_TYPE_GW_SENDOPTIONS, NULL);

	return opts;
}

EGwSendOptions *
e_gw_sendoptions_new_from_soap_parameter (SoupSoapParameter *param) 
{
	EGwSendOptions *opts;
	
	g_return_val_if_fail (param != NULL, NULL);

	opts = g_object_new (E_TYPE_GW_SENDOPTIONS, NULL);

	if (!e_gw_sendoptions_store_settings (param, opts)){
		g_object_unref (opts);
		return NULL;
	}
	
	return opts;
}


