/*
 *
 * 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 of the License, or (at your option) version 3.
 *
 * 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 the program; if not, see <http://www.gnu.org/licenses/>
 *
 *
 * Authors:
 *		Vivek Jain <jvivek@novell.com>
 *
 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 *
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <glib.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include <e-util/e-config.h>
#include <mail/em-config.h>
#include <mail/em-popup.h>
#include <mail/em-folder-properties.h>
#include <mail/em-folder-tree.h>
#include <mail/em-folder-selector.h>
#include <mail/mail-mt.h>
#include <mail/mail-component.h>
#include <mail/mail-config.h>
#include <mail/mail-vfolder.h>
#include <mail/em-vfolder-rule.h>
#include <filter/filter-rule.h>
#include <camel/camel-store.h>
#include <camel/camel-session.h>
#include <camel/camel-store.h>
#include <camel/camel-vee-store.h>
#include <camel/camel-folder.h>
#include <e-gw-container.h>
#include <e-gw-connection.h>
#include <glade/glade.h>
#include "share-folder.h"
#define d(x)

ShareFolder *common = NULL;
CamelSession *session;
struct ShareInfo {
	GtkWidget *d;
	ShareFolder *sf;
	EMFolderTreeModel *model;
	EMFolderSelector *emfs;
};

GtkWidget * org_gnome_shared_folder_factory (EPlugin *ep, EConfigHookItemFactoryData *hook_data);
void org_gnome_create_option(EPlugin *ep, EMPopupTargetFolder *target);
static void create_shared_folder(EPopup *ep, EPopupItem *p, gpointer data);
static void popup_free (EPopup *ep, GSList *items, gpointer data);
void shared_folder_commit (EPlugin *ep, EConfigTarget *tget);
void shared_folder_abort (EPlugin *ep, EConfigTarget *target);

static void refresh_folder_tree (EMFolderTreeModel *model, CamelStore *store);

static void
refresh_folder_tree (EMFolderTreeModel *model, CamelStore *store)
{
	gchar *uri;
	EAccount *account;
	CamelException ex;
	CamelProvider *provider;

	uri = camel_url_to_string (((CamelService *) store)->url, CAMEL_URL_HIDE_ALL);
	account = mail_config_get_account_by_source_url (uri);
	if (!account) {
		return;
	}

	uri = account->source->url;
	em_folder_tree_model_remove_store (model, store);

	camel_exception_init (&ex);
	if (!(provider = camel_provider_get(uri, &ex))) {
		camel_exception_clear (&ex);
		return;
	}
	if (!(provider->flags & CAMEL_PROVIDER_IS_STORAGE))
		return;
	em_folder_tree_model_add_store (model, store, account->name);
	/* camel_object_unref (store); */
}

void
shared_folder_commit (EPlugin *ep, EConfigTarget *tget)
{
	EMConfigTargetFolder *target =  (EMConfigTargetFolder *)tget->config->target;
	CamelFolder *folder = target->folder;
	CamelStore *store = folder->parent_store;
	EMFolderTreeModel *model = mail_component_peek_tree_model (mail_component_peek ());
	if (common) {
		share_folder (common);
		refresh_folder_tree (model, store);
		g_object_run_dispose ((GObject *)common);
		common = NULL;
	}
}

void
shared_folder_abort (EPlugin *ep, EConfigTarget *target)
{
	if (common) {
		g_object_run_dispose ((GObject *)common);
		common = NULL;
	}
}

struct _EMCreateFolder {
	MailMsg base;

	/* input data */
	CamelStore *store;
	gchar *full_name;
	gchar *parent;
	gchar *name;

	/* output data */
	CamelFolderInfo *fi;

	/* callback data */
	void (* done) (struct _EMCreateFolder *m, gpointer user_data);
	gpointer user_data;
};

static gchar *
create_folder_desc (struct _EMCreateFolder *m)
{
	return g_strdup_printf (_("Creating folder `%s'"), m->full_name);
}

static void
create_folder_exec (struct _EMCreateFolder *m)
{
	d(printf ("creating folder parent='%s' name='%s' full_name='%s'\n", m->parent, m->name, m->full_name));

	if ((m->fi = camel_store_create_folder (m->store, m->parent, m->name, &m->base.ex))) {
		if (camel_store_supports_subscriptions (m->store))
			camel_store_subscribe_folder (m->store, m->full_name, &m->base.ex);
	}
}

static void
create_folder_done (struct _EMCreateFolder *m)
{
	struct ShareInfo *ssi = (struct ShareInfo *) m->user_data;
	CamelStore *store = CAMEL_STORE (m->store);
	EGwConnection *ccnc;

	if (m->done) {
		ccnc = get_cnc (store);
		if (E_IS_GW_CONNECTION (ccnc)) {
			(ssi->sf)->cnc = ccnc;

			(ssi->sf)->container_id = g_strdup (get_container_id ((ssi->sf)->cnc, m->full_name));
			share_folder(ssi->sf);
		}

		m->done (m, m->user_data);
	}
}

static void
create_folder_free (struct _EMCreateFolder *m)
{
	camel_store_free_folder_info (m->store, m->fi);
	camel_object_unref (m->store);
	g_free (m->full_name);
	g_free (m->parent);
	g_free (m->name);
}

static MailMsgInfo create_folder_info = {
	sizeof (struct _EMCreateFolder),
	(MailMsgDescFunc) create_folder_desc,
	(MailMsgExecFunc) create_folder_exec,
	(MailMsgDoneFunc) create_folder_done,
	(MailMsgFreeFunc) create_folder_free
};

static void
new_folder_created_cb (struct _EMCreateFolder *m, gpointer user_data)
{
	struct ShareInfo *ssi = (struct ShareInfo *) user_data;
	EMFolderSelector *emfs = ssi->emfs;
	if (m->fi) {
		refresh_folder_tree (ssi->model, m->store);
		gtk_widget_destroy ((GtkWidget *) emfs);
		gtk_widget_destroy ((GtkWidget *) ssi->d);
	}

	g_object_unref (emfs);
}

static gint
create_folder (CamelStore *store, const gchar *full_name, void (* done) (struct _EMCreateFolder *m, gpointer user_data), gpointer user_data)
{
	gchar *name, *namebuf = NULL;
	struct _EMCreateFolder *m;
	const gchar *parent;
	gint id;

	namebuf = g_strdup (full_name);
	if (!(name = strrchr (namebuf, '/'))) {
		name = namebuf;
		parent = "";
	} else {
		*name++ = '\0';
		parent = namebuf;
	}

	m = mail_msg_new (&create_folder_info);
	camel_object_ref (store);
	m->store = store;
	m->full_name = g_strdup (full_name);
	m->parent = g_strdup (parent);
	m->name = g_strdup (name);
	m->user_data = (struct ShareInfo *) user_data;
	m->done = done;
	g_free (namebuf);
	id = m->base.seq;
	mail_msg_unordered_push (m);

	return id;
}

static void
users_dialog_response(GtkWidget *dialog, gint response, struct ShareInfo *ssi)
{
	struct _EMFolderTreeModelStoreInfo *si;
	EMFolderSelector *emfs = ssi->emfs;
	const gchar *uri, *path;
	CamelException ex;
	CamelStore *store;

	if (response != GTK_RESPONSE_OK) {
		gtk_widget_destroy ((GtkWidget *) emfs);
		gtk_widget_destroy(dialog);
		return;
	}

	uri = em_folder_selector_get_selected_uri (emfs);
	path = em_folder_selector_get_selected_path (emfs);

	d(printf ("Creating new folder: %s (%s)\n", path, uri));

	camel_exception_init (&ex);
	if (!(store = (CamelStore *) camel_session_get_service (session, uri, CAMEL_PROVIDER_STORE, &ex))) {
		camel_exception_clear (&ex);
		return;
	}

	if (!(si = g_hash_table_lookup ((ssi->model)->store_hash, store))) {
		g_assert_not_reached ();
		camel_object_unref (store);
		return;
	}

	if (CAMEL_IS_VEE_STORE(store)) {
		EMVFolderRule *rule;

		/* ensures vfolder is running */
		vfolder_load_storage ();

		rule = em_vfolder_rule_new();
		filter_rule_set_name((FilterRule *)rule, path);
		vfolder_gui_add_rule(rule);
		gtk_widget_destroy((GtkWidget *)emfs);
	} else {
		g_object_ref (emfs);
		ssi->d = dialog;
		create_folder (si->store, path, new_folder_created_cb, ssi);

	}
	camel_object_unref (store);
}

static void
new_folder_response (EMFolderSelector *emfs, gint response, EMFolderTreeModel *model)
{
	GtkWidget *users_dialog;
	GtkWidget *w;
	struct ShareInfo *ssi;
	const gchar *uri;
	EGwConnection *cnc;
	CamelException ex;
	CamelStore *store;

	ssi = g_new0(struct ShareInfo, 1);
	if (response != GTK_RESPONSE_OK) {
		gtk_widget_destroy ((GtkWidget *) emfs);
		return;
	}

	/* i want store at this point to get cnc not sure proper or not*/
	uri = em_folder_selector_get_selected_uri (emfs);
	camel_exception_init (&ex);
	if (!(store = (CamelStore *) camel_session_get_service (session, uri, CAMEL_PROVIDER_STORE, &ex))) {
		camel_exception_clear (&ex);
		return;
	}

	cnc = get_cnc (store);
	users_dialog = gtk_dialog_new_with_buttons (
			_("Users"), NULL, GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
	w = gtk_label_new_with_mnemonic (_("Enter the users and set permissions"));
	gtk_widget_show(w);
	gtk_box_pack_start(GTK_BOX (GTK_DIALOG (users_dialog)->vbox), (GtkWidget *) w, TRUE, TRUE, 6);
	ssi->sf = share_folder_new (cnc, NULL);
	gtk_widget_set_sensitive (GTK_WIDGET ((ssi->sf)->table), TRUE);
	ssi->model = model;
	ssi->emfs = emfs;
	gtk_widget_reparent (GTK_WIDGET ((ssi->sf)->table), GTK_DIALOG (users_dialog)->vbox);
	gtk_widget_hide((GtkWidget*) emfs);
	gtk_window_resize (GTK_WINDOW (users_dialog), 350, 300);
	gtk_widget_show(users_dialog);
	g_signal_connect (users_dialog, "response", G_CALLBACK (users_dialog_response), ssi);

	camel_object_unref (store);
	return;

}

static EPopupItem popup_items[] = {
	{ E_POPUP_ITEM, (gchar *) "20.emc.001", (gchar *) N_("New _Shared Folder..."), create_shared_folder, NULL, (gchar *) "folder-new", 0, EM_POPUP_FOLDER_INFERIORS }
};

static void
popup_free (EPopup *ep, GSList *items, gpointer data)
{
g_slist_free (items);
}

void
org_gnome_create_option(EPlugin *ep, EMPopupTargetFolder *t)
{
	GSList *menus = NULL;
	gint i = 0;
	static gint first = 0;

	if (! g_strrstr (t->uri, "groupwise://"))
		return;

	/* for translation*/
	if (!first) {
		popup_items[0].label =  _(popup_items[0].label);

	}

	first++;

	for (i = 0; i < sizeof (popup_items) / sizeof (popup_items[0]); i++)
		menus = g_slist_prepend (menus, &popup_items[i]);

	e_popup_add_items (t->target.popup, menus, NULL, popup_free, NULL);

}

static void
create_shared_folder(EPopup *ep, EPopupItem *p, gpointer data)
{

	EMFolderTreeModel *model;
	EMFolderTree *folder_tree;
	GtkWidget *dialog;
	gchar *uri;

	model = mail_component_peek_tree_model (mail_component_peek ());
	folder_tree = (EMFolderTree *) em_folder_tree_new_with_model (model);
	dialog = em_folder_selector_create_new (folder_tree, 0, _("Create folder"), _("Specify where to create the folder:"));
	uri = em_folder_tree_get_selected_uri(folder_tree);
	em_folder_selector_set_selected ((EMFolderSelector *) dialog, uri);
	g_free(uri);
	g_signal_connect (dialog, "response", G_CALLBACK (new_folder_response), model);
	gtk_window_set_title (GTK_WINDOW (dialog), "New Shared Folder" );
	gtk_widget_show(dialog);

}

GtkWidget *
org_gnome_shared_folder_factory (EPlugin *ep, EConfigHookItemFactoryData *hook_data)
{

	gchar *folderuri = NULL;
	gchar *account = NULL;
	gchar *id = NULL;
	gchar *folder_name = NULL;
	EGwConnection *cnc;
	ShareFolder *sharing_tab;
	EMConfigTargetFolder *target=  (EMConfigTargetFolder *)hook_data->config->target;
	CamelFolder *folder = target->folder;

	folder_name = g_strdup (folder->full_name);
	folderuri = g_strdup(target->uri);
	if (folderuri && folder_name)
		account = g_strrstr(folderuri, "groupwise");
	else
		return NULL;

	 /* This is kind of bad..but we don't have types for all these folders.*/

	if ( !( strcmp (folder_name, "Mailbox")
	     && strcmp (folder_name, "Calendar")
	     && strcmp (folder_name, "Contacts")
	     && strcmp (folder_name, "Documents")
	     && strcmp (folder_name, "Authored")
	     && strcmp (folder_name, "Default Library")
	     && strcmp (folder_name, "Work In Progress")
	     && strcmp (folder_name, "Cabinet")
	     && strcmp (folder_name, "Sent Items")
	     && strcmp (folder_name, "Trash")
	     && strcmp (folder_name, "Checklist"))) {

		g_free (folderuri);
		return NULL;
	}

	if (account) {
		CamelStore *store = folder->parent_store;
		cnc = get_cnc (store);

		if (E_IS_GW_CONNECTION (cnc))
			id = get_container_id (cnc, folder_name);
		else
			g_warning("Could not Connnect\n");

		if (cnc && id)
			sharing_tab = share_folder_new (cnc, id);
		else
			return NULL;

		gtk_notebook_append_page((GtkNotebook *) hook_data->parent, (GtkWidget *) sharing_tab->vbox, gtk_label_new_with_mnemonic N_("Sharing"));
		common = sharing_tab;
		g_free (folderuri);
		return GTK_WIDGET (sharing_tab);
	} else
		return NULL;
}

EGwConnection *
get_cnc (CamelStore *store)
{
		EGwConnection *cnc;
		const gchar *uri, *property_value, *server_name, *user, *port;
		gchar *use_ssl;
		CamelService *service;
		CamelURL *url;

		if (!store)
			return  NULL;

		service = CAMEL_SERVICE(store);
		url = service->url;
		server_name = g_strdup (url->host);
		user = g_strdup (url->user);
		property_value =  camel_url_get_param (url, "soap_port");
		use_ssl = g_strdup (camel_url_get_param (url, "use_ssl"));
		if (property_value == NULL)
			port = g_strdup ("7191");
		else if (strlen(property_value) == 0)
			port = g_strdup ("7191");
		else
			port = g_strdup (property_value);

		if (use_ssl && !g_str_equal (use_ssl, "never"))
			uri = g_strconcat ("https://", server_name, ":", port, "/soap", NULL);
		else
			uri = g_strconcat ("http://", server_name, ":", port, "/soap", NULL);

		cnc = e_gw_connection_new (uri, user, service->url->passwd);
		if (!E_IS_GW_CONNECTION(cnc) && use_ssl && g_str_equal (use_ssl, "when-possible")) {
			gchar *http_uri = g_strconcat ("http://", uri + 8, NULL);
			cnc = e_gw_connection_new (http_uri, user, service->url->passwd);
			g_free (http_uri);
		}
		g_free (use_ssl);
		use_ssl = NULL;

		return cnc;

}

gchar *
get_container_id(EGwConnection *cnc, const gchar *fname)
{
	GList *container_list = NULL;
	gchar *id = NULL;
	gchar *name;
	gchar **names;
	gint i = 0, parts = 0;

	names = g_strsplit (fname, "/", -1);
	if (names) {
		while (names [parts])
			parts++;
		fname = names[i];
	}

	/* get list of containers */
	if (e_gw_connection_get_container_list (cnc, "folders", &(container_list)) == E_GW_CONNECTION_STATUS_OK) {
		GList *container = NULL;

		for (container = container_list; container != NULL; container = container->next) {
			name = g_strdup (e_gw_container_get_name (container->data));
			/* if Null is passed as name then we return top lavel id*/
			if (fname == NULL) {
				id = g_strdup (e_gw_container_get_id (container->data));
				break;
			} else if (!strcmp (name, fname)) {
				if (i == parts - 1) {
					id = g_strdup (e_gw_container_get_id (container->data));
					break;
				} else
					fname = names[++i];
			}
			g_free (name);
		}
		e_gw_connection_free_container_list (container_list);
	}

	if (names)
		g_strfreev (names);
	return id;
}
