/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/***************************************************************************
 *            e-kolab-plugin-ui.c
 *
 *  Fri Feb 10 17:21:05 2012
 *  Copyright  2012  Christian Hilberg
 *  <hilberg@kernelconcepts.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 <config.h>

#include <glib/gi18n-lib.h>

#include <libedataserverui/e-source-selector.h>

#include <e-util/e-util.h>
#include <e-util/e-dialog-utils.h>
#include <e-util/e-plugin-ui.h>

#include <shell/e-shell-sidebar.h>
#include <shell/e-shell-view.h>
#include <shell/e-shell-window.h>

#include <mail/em-config.h>
#include <mail/em-folder-tree.h>

#include <libekolab/kolab-data-imap-account.h>
#include <libekolab/kolab-util-backend.h>
#include <libekolabutil/kolab-util-camel.h>

#include "e-kolab-folder-metadata.h"
#include "e-kolab-folder-permissions.h"
#include "e-kolab-plugin-ui.h"

/*----------------------------------------------------------------------------*/

/* how many menu entries are defined; all calendar/tasks/memos/contacts
   actions should have same count */
#define KOLAB_CONTEXT_NUM_ENTRIES 1

static void kolab_plugin_ui_action_kolab_properties_cb (GtkAction *action, EShellView *shell_view);

static GtkActionEntry mail_folder_context_entries[] = {
	{ "kolab-mail-folder-properties",
	  "folder-new",
	  N_("Kolab Folder Properties..."),
	  NULL,
	  N_("Edit Kolab mail folder properties"),
	  G_CALLBACK (kolab_plugin_ui_action_kolab_properties_cb) }
};

static GtkActionEntry calendar_context_entries[] = {
	{ "kolab-calendar-folder-properties",
	  "folder-new",
	  N_("Kolab Folder Properties..."),
	  NULL,
	  N_("Edit Kolab calendar folder properties"),
	  G_CALLBACK (kolab_plugin_ui_action_kolab_properties_cb) }
};

static GtkActionEntry memos_context_entries[] = {
	{ "kolab-memos-folder-properties",
	  "folder-new",
	  N_("Kolab Folder Properties..."),
	  NULL,
	  N_("Edit Kolab memos folder properties"),
	  G_CALLBACK (kolab_plugin_ui_action_kolab_properties_cb) }
};

static GtkActionEntry tasks_context_entries[] = {
	{ "kolab-tasks-folder-properties",
	  "folder-new",
	  N_("Kolab Folder Properties..."),
	  NULL,
	  N_("Edit Kolab Tasks folder properties"),
	  G_CALLBACK (kolab_plugin_ui_action_kolab_properties_cb) }
};

static GtkActionEntry contacts_context_entries[] = {
	{ "kolab-contacts-folder-properties",
	  "folder-new",
	  N_("Kolab Folder Properties..."),
	  NULL,
	  N_("Edit Kolab contacts folder properties"),
	  G_CALLBACK (kolab_plugin_ui_action_kolab_properties_cb) }
};

/*----------------------------------------------------------------------------*/
/* UI data structures */

#define  E_KOLAB_PROP_DLG_UIDATA "e-kolab-prop-dlg-uidata"

typedef struct _KolabFolderPropUIWidgets KolabFolderPropUIWidgets;
struct _KolabFolderPropUIWidgets {
	GtkWidget *dialog;
	/* sub-widgets of dialog */
	GtkWidget *selected_folder;
	GtkWidget *notebook;
};

typedef struct _KolabFolderPropUIData KolabFolderPropUIData;
struct _KolabFolderPropUIData {
	KolabFolderPropUIWidgets *widgets;
	KolabFolderMetaUIData *meta_ui_data;
	KolabFolderPermUIData *perm_ui_data;
	KolabDataImapAccount *account;
};

static void
kolab_folder_prop_ui_widgets_enable (KolabFolderPropUIWidgets *widgets,
                                     gboolean enabled)
{
	g_return_if_fail (widgets != NULL);

	/* FIXME implement me */
	g_warning ("%s: FIXME implement me", __func__);
}

static KolabFolderPropUIData*
kolab_folder_prop_ui_data_new ()
{
	KolabFolderPropUIData *uidata = NULL;

	uidata = g_new0 (KolabFolderPropUIData, 1);
	uidata->widgets = g_new0 (KolabFolderPropUIWidgets, 1);
	uidata->meta_ui_data = NULL;
	uidata->perm_ui_data = NULL;
	uidata->account = NULL;

	return uidata;
}

static void
kolab_folder_prop_ui_data_free (KolabFolderPropUIData *uidata)
{
	if (uidata == NULL)
		return;

	/* the actual widgets will have been deleted already,
	 * so just deleting the struct shell here
	 */
	if (uidata->widgets != NULL)
		g_free (uidata->widgets);

	e_kolab_folder_metadata_ui_free (uidata->meta_ui_data);
	e_kolab_folder_permissions_ui_free (uidata->perm_ui_data);
	kolab_data_imap_account_free (uidata->account);

	g_free (uidata);
}

static void
kolab_folder_prop_ui_data_destroy (gpointer data)
{
	if (data == NULL)
		return;

	kolab_folder_prop_ui_data_free ((KolabFolderPropUIData *)data);
}

static void
kolab_folder_prop_ui_clear_all_entries (GObject *dialog)
{
	g_return_if_fail (dialog != NULL);

	/* FIXME implement me */
	g_warning ("%s: FIXME implement me", __func__);
}

static void
kolab_folder_prop_ui_response_cb (GObject *dialog,
                                  gint response_id)
{
	g_return_if_fail (dialog != NULL);

	if (response_id != GTK_RESPONSE_OK) {
		kolab_folder_prop_ui_clear_all_entries (dialog);
		gtk_widget_destroy (GTK_WIDGET (dialog));
		return;
	}

	/* FIXME implement me */
	g_warning ("%s: FIXME implement me", __func__);
}

/*----------------------------------------------------------------------------*/
/* internal statics (non-UI) */


/*----------------------------------------------------------------------------*/
/* internal statics (UI) */

static gboolean
kolab_plugin_ui_get_selected_source (EShellView *shell_view,
                                     ESource **selected_source)
{
	ESource *source = NULL;
	gchar *uri = NULL;
	EShellSidebar *shell_sidebar = NULL;
	ESourceSelector *selector = NULL;

	g_return_val_if_fail (shell_view != NULL, FALSE);
	g_return_val_if_fail (selected_source == NULL || *selected_source == NULL, FALSE);

	shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
	g_return_val_if_fail (shell_sidebar != NULL, FALSE);

	g_object_get (shell_sidebar, "selector", &selector, NULL);
	g_return_val_if_fail (selector != NULL, FALSE);

	source = e_source_selector_peek_primary_selection (selector);
	uri = source ? e_source_get_uri (source) : NULL;
	/* check whether we have a Kolab ESource selected */
	if (uri && g_str_has_prefix (uri, KOLAB_CAMEL_URI_PREFIX))
		source = g_object_ref (source);
	else
		source = NULL;

	g_free (uri);
	g_object_unref (selector);

	if (selected_source)
		*selected_source = source;
	else if (source)
		g_object_unref (source);

	return source != NULL;
}

static gchar*
kolab_plugin_ui_path_from_mail_view (EShellView *shell_view,
                                     gboolean *is_kolab_account_node,
                                     gboolean *is_kolab_folder_node)
{
	EShellSidebar *shell_sidebar = NULL;
	EMFolderTree *folder_tree = NULL;
	CamelStore *selected_store = NULL;
	gchar *selected_path = NULL;

	g_assert (E_IS_SHELL_VIEW (shell_view));

	shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
	g_object_get (shell_sidebar, "folder-tree", &folder_tree, NULL);
	if (em_folder_tree_get_selected (folder_tree, &selected_store, &selected_path) ||
	    em_folder_tree_store_root_selected (folder_tree, &selected_store)) {
		if (selected_store) {
			CamelProvider *provider = camel_service_get_provider (CAMEL_SERVICE (selected_store));

			if (provider && g_ascii_strcasecmp (provider->protocol, KOLAB_CAMEL_PROVIDER_PROTOCOL) == 0) {
				*is_kolab_account_node = !selected_path || !*selected_path;
				*is_kolab_folder_node = !*is_kolab_account_node;
			}

			g_object_unref (selected_store);
		}
	}
	g_object_unref (folder_tree);

	return selected_path;
}

static gchar*
kolab_plugin_ui_path_from_pim_view (EShellView *shell_view,
                                    gboolean *is_kolab_account_node,
                                    gboolean *is_kolab_folder_node)
{
	gchar *selected_path = NULL;
	ESource *source = NULL;
	gboolean is_source = FALSE;
	gchar *uri = NULL;
	gchar *proto = NULL;

	g_assert (E_IS_SHELL_VIEW (shell_view));

	*is_kolab_account_node = FALSE;
	*is_kolab_folder_node = FALSE;

	is_source = kolab_plugin_ui_get_selected_source (shell_view,
	                                                 &source);
	if (! is_source)
		goto exit;

	uri = e_source_get_uri (source);
	if (uri == NULL)
		goto exit;

	proto = kolab_util_backend_get_protocol_from_uri (uri);
	if (g_strcmp0 (proto, KOLAB_CAMEL_PROVIDER_PROTOCOL) != 0) {
		g_warning ("%s()[%u] got wrong protocol '%s'",
		           __func__, __LINE__, proto);
		goto exit;
	}

	selected_path = kolab_util_backend_get_relative_path_from_uri (uri);
	if (selected_path == NULL)
		g_warning ("%s()[%u] selected path is NULL", __func__, __LINE__);
	*is_kolab_folder_node = TRUE;

 exit:
	if (uri != NULL)
		g_free (uri);
	if (proto != NULL)
		g_free (proto);

	return selected_path;
}

static gchar*
kolab_plugin_ui_get_selected_path (EShellView *shell_view,
                                   gboolean *is_kolab_account_node,
                                   gboolean *is_kolab_folder_node)
{
	gchar *selected_path = NULL;
	const gchar *view_name = NULL;

	g_assert (E_IS_SHELL_VIEW (shell_view));

	/* TODO find a cleaner solution for this.
	 *
	 * Since it seems we cannot directly check for
	 * the EShellView subtype, we use the view name
	 * property to tell the types apart...
	 */
	view_name = e_shell_view_get_name (shell_view);

	if (g_strcmp0 (view_name, "mail") == 0)
		selected_path = kolab_plugin_ui_path_from_mail_view (shell_view,
		                                                     is_kolab_account_node,
		                                                     is_kolab_folder_node);
	else
		selected_path = kolab_plugin_ui_path_from_pim_view (shell_view,
		                                                    is_kolab_account_node,
		                                                    is_kolab_folder_node);
	return selected_path;
}

static GtkWidget*
kolab_plugin_ui_selected_folder_widget (GtkAction *action,
                                        EShellView *shell_view)
{
	GtkWidget *label = NULL;
	gchar *labeltext = NULL;
	gchar *foldername = NULL;
	gboolean is_kolab_account_node = FALSE;
	gboolean is_kolab_folder_node = FALSE;

	g_assert (action != NULL);
	g_assert (E_IS_SHELL_VIEW (shell_view));

	foldername = kolab_plugin_ui_get_selected_path (shell_view,
	                                                &is_kolab_account_node,
	                                                &is_kolab_folder_node);

	g_return_val_if_fail (foldername != NULL, NULL);
	g_return_val_if_fail (!is_kolab_account_node, NULL);
	g_return_val_if_fail (is_kolab_folder_node, NULL);

	label = gtk_label_new (NULL);
	labeltext = g_strconcat ("<b>", _("Selected Folder"), ": </b>", foldername, NULL);
	g_free (foldername);
	gtk_label_set_markup (GTK_LABEL (label), labeltext);
	g_free (labeltext);
	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);

	return label;
}

static void
kolab_plugin_ui_action_kolab_properties_cb (GtkAction *action,
                                            EShellView *shell_view)
{
	KolabFolderPropUIData *uidata = NULL;
	GObject *dialog = NULL;
	GtkWidget *content = NULL;
	GtkNotebook *notebook = NULL;

	uidata = kolab_folder_prop_ui_data_new ();

	uidata->widgets->selected_folder =
		kolab_plugin_ui_selected_folder_widget (action, shell_view);
	if (uidata->widgets->selected_folder == NULL) {
		/* TODO this should not happen.
		 *
		 * If the selected folder is NULL here, it means
		 * it is no Kolab folder node. There should not
		 * be a context menu entry in this case in the
		 * first place.
		 */
		g_warning ("%s()[%u]: Selected folder is no Kolab folder node",
		           __func__, __LINE__);
		kolab_folder_prop_ui_data_free (uidata);
		return;
	}

	uidata->widgets->dialog =
		gtk_dialog_new_with_buttons (_("Edit Kolab Folder Properties..."),
		                             NULL, /* parent */
		                             GTK_DIALOG_DESTROY_WITH_PARENT,
		                             GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
		                             GTK_STOCK_OK, GTK_RESPONSE_OK,
		                             NULL);
	gtk_window_set_resizable (GTK_WINDOW (uidata->widgets->dialog), FALSE);

	uidata->meta_ui_data = e_kolab_folder_metadata_ui_new ();
	uidata->perm_ui_data = e_kolab_folder_permissions_ui_new ();
	/* FIXME get account data here */
	uidata->account = kolab_data_imap_account_new ();

	dialog = G_OBJECT (uidata->widgets->dialog);
	g_signal_connect (dialog, "response", G_CALLBACK (kolab_folder_prop_ui_response_cb), NULL);
	g_object_set_data_full (dialog, E_KOLAB_PROP_DLG_UIDATA, uidata, kolab_folder_prop_ui_data_destroy);

	content = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
	gtk_container_add (GTK_CONTAINER (content), uidata->widgets->selected_folder);
	uidata->widgets->notebook = gtk_notebook_new ();
	notebook = GTK_NOTEBOOK (uidata->widgets->notebook);
	gtk_notebook_set_show_border (notebook, TRUE);
	gtk_container_add (GTK_CONTAINER (content),
	                   uidata->widgets->notebook);

	/* set notebook content */

	/* folder metadata notebook page */
	gtk_notebook_append_page (notebook,
	                          uidata->meta_ui_data->widgets->container,
	                          NULL);
	gtk_notebook_set_tab_label_text (notebook,
	                                 uidata->meta_ui_data->widgets->container,
	                                 _("IMAP Metadata"));

	/* folder permissions notebook page */
	gtk_notebook_append_page (notebook,
	                          uidata->perm_ui_data->widgets->container,
	                          NULL);
	gtk_notebook_set_tab_label_text (notebook,
	                                 uidata->perm_ui_data->widgets->container,
	                                 _("IMAP Access Control"));

	/* TODO connect signals */

	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);

	kolab_folder_prop_ui_widgets_enable (uidata->widgets, FALSE);

	gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
	                                   GTK_RESPONSE_OK,
	                                   FALSE);

	gtk_widget_show_all (content);
	gtk_widget_show (uidata->widgets->dialog);
}

static void
kolab_plugin_ui_enable_actions (GtkActionGroup *action_group,
                                const GtkActionEntry *entries,
                                guint n_entries,
                                gboolean can_show,
                                gboolean is_online)
{
	guint ii = 0;

	g_return_if_fail (action_group != NULL);
	g_return_if_fail (entries != NULL);

	for (ii = 0; ii < n_entries; ii++) {
		GtkAction *action;

		action = gtk_action_group_get_action (action_group, entries[ii].name);
		if (!action)
			continue;

		gtk_action_set_visible (action, can_show);
		if (can_show)
			gtk_action_set_sensitive (action, is_online);
	}
}

static void
kolab_plugin_ui_update_mail_entries_cb (EShellView *shell_view,
                                        GtkActionEntry *entries)
{
	EShellWindow *shell_window = NULL;
	GtkActionGroup *action_group = NULL;
	GtkUIManager *ui_manager = NULL;
	gchar *selected_path = NULL;
	gboolean is_kolab_account_node = FALSE;
	gboolean is_kolab_folder_node = FALSE;
	gboolean is_online = FALSE;

	g_assert (E_IS_SHELL_VIEW (shell_view));
	g_assert (entries != NULL);

	selected_path = kolab_plugin_ui_get_selected_path (shell_view,
	                                                   &is_kolab_account_node,
	                                                   &is_kolab_folder_node);
	g_free (selected_path);

	shell_window = e_shell_view_get_shell_window (shell_view);
	ui_manager = e_shell_window_get_ui_manager (shell_window);
	action_group = e_lookup_action_group (ui_manager, "mail");

	if (is_kolab_account_node || is_kolab_folder_node) {
		EShellBackend *backend = NULL;
		CamelSession *session = NULL;

		backend = e_shell_view_get_shell_backend (shell_view);
		g_object_get (G_OBJECT (backend), "session", &session, NULL);

		is_online = session && camel_session_get_online (session);

		if (session)
			g_object_unref (session);
	}

	kolab_plugin_ui_enable_actions (action_group,
	                                mail_folder_context_entries,
	                                KOLAB_CONTEXT_NUM_ENTRIES,
	                                is_kolab_folder_node,
	                                is_online);
}

static void
kolab_plugin_ui_update_source_entries_cb (EShellView *shell_view,
                                          GtkActionEntry *entries)
{
	GtkActionGroup *action_group = NULL;
	EShell *shell = NULL;
	EShellWindow *shell_window = NULL;
	const gchar *group = NULL;
	gboolean is_kolab_source = FALSE;
	gboolean is_online = FALSE;

	g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
	g_return_if_fail (entries != NULL);

	if (strstr (entries->name, "calendar") != NULL)
		group = "calendar";
	else if (strstr (entries->name, "tasks") != NULL)
		group = "tasks";
	else if (strstr (entries->name, "memos") != NULL)
		group = "memos";
	else if (strstr (entries->name, "contacts") != NULL)
		group = "contacts";
	else
		g_return_if_reached ();

	is_kolab_source = kolab_plugin_ui_get_selected_source (shell_view, NULL);
	shell_window = e_shell_view_get_shell_window (shell_view);
	shell = e_shell_window_get_shell (shell_window);

	/* this is a shortcut. we should actually query
	 * the online state from the backend
	 */
	is_online = shell && e_shell_get_online (shell);
	action_group = e_shell_window_get_action_group (shell_window, group);

	kolab_plugin_ui_enable_actions (action_group,
	                                entries,
	                                KOLAB_CONTEXT_NUM_ENTRIES,
	                                is_kolab_source,
	                                is_online);
}

static void
kolab_plugin_ui_setup_mail_actions (EShellView *shell_view)
{
	EShellWindow *shell_window;
	GtkActionGroup *action_group;

	g_assert (E_IS_SHELL_VIEW (shell_view));
	g_return_if_fail (G_N_ELEMENTS (mail_folder_context_entries) == KOLAB_CONTEXT_NUM_ENTRIES);

	shell_window = e_shell_view_get_shell_window (shell_view);
	action_group = e_shell_window_get_action_group (shell_window, "mail");

	/* Add actions to the "mail" action group. */
	e_action_group_add_actions_localized (action_group,
	                                      GETTEXT_PACKAGE,
	                                      mail_folder_context_entries,
	                                      KOLAB_CONTEXT_NUM_ENTRIES,
	                                      shell_view);

	/* Decide whether we want this option to be visible or not */
	g_signal_connect (shell_view,
	                  "update-actions",
	                  G_CALLBACK (kolab_plugin_ui_update_mail_entries_cb),
	                  shell_view);

	g_object_unref (action_group);
}

static void
kolab_plugin_ui_setup_source_actions (EShellView *shell_view,
                                      GtkActionEntry *entries,
                                      guint n_entries)
{
	EShellWindow *shell_window;
	const gchar *group;

	g_assert (E_IS_SHELL_VIEW (shell_view));
	g_return_if_fail (entries != NULL);
	g_return_if_fail (n_entries == KOLAB_CONTEXT_NUM_ENTRIES);

	if (strstr (entries->name, "calendar") != NULL)
		group = "calendar";
	else if (strstr (entries->name, "tasks") != NULL)
		group = "tasks";
	else if (strstr (entries->name, "memos") != NULL)
		group = "memos";
	else if (strstr (entries->name, "contacts") != NULL)
		group = "contacts";
	else
		g_return_if_reached ();

	shell_window = e_shell_view_get_shell_window (shell_view);

	e_action_group_add_actions_localized (e_shell_window_get_action_group (shell_window, group),
	                                      GETTEXT_PACKAGE,
	                                      entries,
	                                      KOLAB_CONTEXT_NUM_ENTRIES,
	                                      shell_view);

	g_signal_connect (shell_view,
	                  "update-actions",
	                  G_CALLBACK (kolab_plugin_ui_update_source_entries_cb),
	                  entries);
}

/*----------------------------------------------------------------------------*/
/* API functions (non-UI) */


/*----------------------------------------------------------------------------*/
/* API functions (UI) */

gboolean
e_kolab_plugin_ui_init_mail (GtkUIManager *ui_manager,
                             EShellView *shell_view)
{
	g_assert (GTK_IS_UI_MANAGER (ui_manager));
	g_assert (E_IS_SHELL_VIEW (shell_view));

	kolab_plugin_ui_setup_mail_actions (shell_view);
	return TRUE;
}

gboolean
e_kolab_plugin_ui_init_calendar (GtkUIManager *ui_manager,
                                 EShellView *shell_view)
{
	g_assert (GTK_IS_UI_MANAGER (ui_manager));
	g_assert (E_IS_SHELL_VIEW (shell_view));

	kolab_plugin_ui_setup_source_actions (shell_view,
	                                      calendar_context_entries,
	                                      G_N_ELEMENTS (calendar_context_entries));
	return TRUE;
}

gboolean
e_kolab_plugin_ui_init_tasks (GtkUIManager *ui_manager,
                              EShellView *shell_view)
{
	g_assert (GTK_IS_UI_MANAGER (ui_manager));
	g_assert (E_IS_SHELL_VIEW (shell_view));

	kolab_plugin_ui_setup_source_actions (shell_view,
	                                      tasks_context_entries,
	                                      G_N_ELEMENTS (tasks_context_entries));
	return TRUE;
}

gboolean
e_kolab_plugin_ui_init_memos (GtkUIManager *ui_manager,
                              EShellView *shell_view)
{
	g_assert (GTK_IS_UI_MANAGER (ui_manager));
	g_assert (E_IS_SHELL_VIEW (shell_view));

	kolab_plugin_ui_setup_source_actions (shell_view,
	                                      memos_context_entries,
	                                      G_N_ELEMENTS (memos_context_entries));
	return TRUE;
}

gboolean
e_kolab_plugin_ui_init_contacts (GtkUIManager *ui_manager,
                                 EShellView *shell_view)
{
	g_assert (GTK_IS_UI_MANAGER (ui_manager));
	g_assert (E_IS_SHELL_VIEW (shell_view));

	kolab_plugin_ui_setup_source_actions (shell_view,
	                                      contacts_context_entries,
	                                      G_N_ELEMENTS (contacts_context_entries));
	return TRUE;
}

/*----------------------------------------------------------------------------*/
