/* -*- mode:C; tab-width:4; -*- */
/* 
 *  Author: Tomas Frydrych <tf@o-hand.com>
 *
 *  Copyright (c) 2005 - 2006 OpenedHand Ltd - http://o-hand.com
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, 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 General Public License for more details.
 *
 */
#include "dates_platform.h"
#include "dates_types.h"
#include "dates_callbacks.h"
#include "dates_navigator.h"

#include <libmokoui/moko-application.h>
#include <libmokoui/moko-paned-window.h>
#include <libmokoui/moko-tool-box.h>
#include <libmokoui/moko-tree-view.h>
#include <libmokoui/moko-details-window.h>
#include <libmokoui/moko-dialog.h>
#include <libmokoui/moko-message-dialog.h>
#include <libmokoui/moko-scrolled-pane.h>

#include <libecal/e-cal.h>
#include <libecal/e-cal-time-util.h>
#include <libical/ical.h>

#include <string.h>

#define DATES_ZOOM_DAY 2
#define DATES_ZOOM_WEEK 9
#define DATES_ZOOM_MONTH 11
#define DATES_ZOOM_YEAR 16

#define DATES_FILTER_DAY    0
#define DATES_FILTER_WEEK   1
#define DATES_FILTER_MONTH  2
#define DATES_FILTER_YEAR   3
#define DATES_FILTER_SEARCH 4
#define DATES_FILTER_TODO   5

void dates_omoko_date_changed_cb (DatesView *view, DatesData *d);

static void
navigator_changed_cb (GtkTreeSelection* selection, DatesData* d)
{
    g_debug("navigator selection changed");
	
    GtkTreeModel * model;
    GtkTreeIter    iter;
	
    gboolean has_selection = gtk_tree_selection_get_selected (selection,
															  &model, &iter );

	gchar * uid = NULL;
	if (has_selection)
        gtk_tree_model_get (model, &iter, DN_Uid, &uid, -1);

	if (uid)
	{
		if (d->uri_uid)
			g_free (d->uri_uid);
		
		d->uri_uid = uid;

		g_idle_add (dates_select_event_idle_cb, d);
	}
}


static guint
count_tree_rows (DatesData * d)
{
	return gtk_tree_model_iter_n_children (GTK_TREE_MODEL (d->navigator),
                                           NULL);
}

static void
update_status_bar (DatesData * d)
{
#if 0
	char buf[20];
	guint filter_count = count_tree_rows (d);
	/* the status bar is a separate app that we will communicate with over
	 * debus, see http://wiki.openmoko.org/index.php/Footer
	 */
	gtk_statusbar_pop (GTK_STATUSBAR (d->status_bar), 1);

	snprintf (buf, sizeof (buf), "%d", filter_count);

	gtk_statusbar_push (GTK_STATUSBAR (d->status_bar), 1, buf);
#endif
}

static void
populate_navigator (DatesData * d)
{
	gchar         * query  = NULL;
	DNTimeFormat    format = DN_DateAndTime;
	
	if (d->active_filter <= DATES_FILTER_YEAR)
	{
		gchar               * start_str, * end_str;
		struct icaltimetype   start;
		struct icaltimetype   end;
		icaltimezone        * zone = NULL;
		
		dates_view_get_visible_span (d->view, &start, &end);
	
		start_str =
			isodate_from_time_t(icaltime_as_timet_with_zone (start,zone));
		end_str   =
			isodate_from_time_t(icaltime_as_timet_with_zone (end,zone));

		query = g_strdup_printf ("(occur-in-time-range? "
								 "(make-time \"%s\") (make-time \"%s\"))",
								 start_str, end_str);

		if (d->active_filter == DATES_FILTER_DAY)
			format = DN_TimeOnly;
	}
	else if (d->active_filter == DATES_FILTER_SEARCH)
	{
		query = g_strdup ("#t");
	}
	else /* TODO */
	{
		g_debug ("quering for TODO");
		query = g_strdup_printf ("(is-vtype? %d)", (int)E_CAL_COMPONENT_TODO);
	}

	dates_navigator_model_populate (DATES_NAVIGATOR_MODEL (d->navigator),
									d->dcal, query, format);
	
	g_free (query);
}

static gboolean
dates_is_row_visible_cb (GtkTreeModel * model, GtkTreeIter * iter,
						 DatesData * d)
{
	if (d->active_filter != DATES_FILTER_SEARCH)
		return TRUE;
	
	gboolean retval = FALSE;
	
	GtkWidget * entry;
	entry = moko_tool_box_get_entry (MOKO_TOOL_BOX (d->current_toolbar));

	if (!entry)
		return TRUE;
	
	gchar * what = NULL;
	gchar * what_lc = NULL;
	const gchar * etext = gtk_entry_get_text (GTK_ENTRY(entry));
	gchar * etext_lc = NULL;
	
	if (!etext || !*etext)
		return TRUE;

	gtk_tree_model_get (model, iter, DN_Name, &what, -1);

	if (!what)
		return FALSE;

	etext_lc = g_utf8_casefold (etext, -1);
	what_lc  = g_utf8_casefold (what, -1);
	
	if (what_lc && etext_lc && strstr (what_lc, etext_lc))
		retval = TRUE;
	
	g_free (what);
	g_free (what_lc);
	g_free (etext_lc);
	
	return retval;
}

static void        
row_activated_cb (GtkTreeView       *tree_view,
                  GtkTreePath       *path,
                  GtkTreeViewColumn *column,
                  gpointer           user_data)
{
  DatesData *d = user_data;
  
  /* Call the event-clicked callback directly to save duplication */
  dates_edit_cb (NULL, d);
}

static GtkWidget *
create_navigation_area( DatesData* d )
{
  d->navigator = GTK_TREE_MODEL (dates_navigator_model_new ());
	
	gtk_tree_model_filter_set_visible_func (
		GTK_TREE_MODEL_FILTER (d->navigator),
		(GtkTreeModelFilterVisibleFunc) dates_is_row_visible_cb,
		d, NULL);
	
    MokoTreeView * treeview =
		MOKO_TREE_VIEW(moko_tree_view_new_with_model(GTK_TREE_MODEL(d->navigator)));

	GtkWidget *scrolled_pane = moko_scrolled_pane_new ();
	moko_scrolled_pane_pack (MOKO_SCROLLED_PANE (scrolled_pane), GTK_WIDGET(treeview));

    GtkCellRenderer* ren = gtk_cell_renderer_text_new ();
    GtkTreeViewColumn* col =
		gtk_tree_view_column_new_with_attributes(_("What"), ren, "text",
												 DN_Name, NULL);
	moko_tree_view_append_column (treeview, col);
	
	ren = gtk_cell_renderer_text_new ();
    col = gtk_tree_view_column_new_with_attributes(_("When"), ren, "text",
												   DN_Time, NULL);
	moko_tree_view_append_column (treeview, col);

    GtkTreeSelection* selection =
		gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));

    g_signal_connect( G_OBJECT(selection), "changed",
					  G_CALLBACK(navigator_changed_cb), d);

    g_signal_connect (treeview, "row-activated", G_CALLBACK (row_activated_cb), d);

	gtk_widget_show (GTK_WIDGET (treeview));
	return scrolled_pane;
}

static gboolean
moko_filter_changed (GtkWidget* widget, gchar* text, DatesData * d)
{
	guint old_zoom = d->zoom;
	
	if (!strcmp (text, _("Day")))
	{
		d->zoom = DATES_ZOOM_DAY; /* 1 day 24 hours */
		d->active_filter = DATES_FILTER_DAY;
	}
	else if (!strcmp (text, _("Week")))
	{
		d->zoom = DATES_ZOOM_WEEK; /* 7 days 24 hours */
		d->active_filter = DATES_FILTER_WEEK;
	}
	else if (!strcmp (text, _("Month")))
	{
		d->zoom = DATES_ZOOM_MONTH; /* 1 month 7 days 24 hours */
		d->active_filter = DATES_FILTER_MONTH;
	}
	else if (!strcmp (text, _("Year")))
	{
		d->zoom = DATES_ZOOM_YEAR; /* 12 months 7 days 24 hours */
		d->active_filter = DATES_FILTER_YEAR;
	}
	else if (!strcmp (text, _("To Do")))
	{
		d->active_filter = DATES_FILTER_TODO;
	}
	else if (!strcmp (text, _("Search")))
	{
		d->active_filter = DATES_FILTER_SEARCH;
		
		GtkWidget * entry =
			moko_tool_box_get_entry (MOKO_TOOL_BOX (d->current_toolbar));

		GtkWidget * page = gtk_widget_get_parent (GTK_WIDGET (entry));
		
		gint cur_page =
			gtk_notebook_get_current_page (GTK_NOTEBOOK (d->current_toolbar));
		
		gint my_page =
			gtk_notebook_page_num (GTK_NOTEBOOK (d->current_toolbar),
								   page);

		if (cur_page != my_page)
			gtk_notebook_set_current_page (GTK_NOTEBOOK (d->current_toolbar),
										   my_page);

		gtk_widget_grab_focus(GTK_WIDGET (entry));
	}

	if (old_zoom != d->zoom)
	{
		dates_zoom_change (d->zoom, d->view);
	}
	
	populate_navigator (d);
							  
	return FALSE;
}

static void
menu_quit_cb (GtkMenuItem *menuitem, gpointer user_data)
{
	DatesData *d = (DatesData *)user_data;
	gtk_widget_destroy (d->main_window);
}

#define DATES_PLATFORM_dates_platform_calendars_dlg
void dates_platform_calendars_dlg (DatesData *d, gboolean show)
{
	if (show)
		moko_dialog_run (MOKO_DIALOG(d->calendars_dialog));
	else
		gtk_widget_hide (d->calendars_dialog);
}

static GtkWidget *
create_app_menu (DatesData *d)
{
    GtkWidget * appmenu = gtk_menu_new();
	GtkWidget * menuitem;

	menuitem = gtk_menu_item_new_with_label(_("Help"));
	gtk_menu_shell_append(GTK_MENU_SHELL (appmenu), menuitem);
	g_signal_connect (G_OBJECT (menuitem), "activate",
					  G_CALLBACK (dates_about_cb), d);

	menuitem = gtk_menu_item_new_with_label(_("Calendars"));
	gtk_menu_shell_append(GTK_MENU_SHELL (appmenu), menuitem);
	g_signal_connect (G_OBJECT (menuitem), "activate",
			G_CALLBACK (dates_calendars_dialog_cb), d);


	menuitem = gtk_menu_item_new_with_label(_("Quit"));
	gtk_menu_shell_append(GTK_MENU_SHELL (appmenu), menuitem);
	g_signal_connect (G_OBJECT (menuitem), "activate",
					  G_CALLBACK (menu_quit_cb), d);

	gtk_widget_show (appmenu);
	return appmenu;
}

static void
entry_changed_cb (GtkEntry *entry, gpointer data)
{
	DatesData * d = data;

	if (d->active_filter != DATES_FILTER_SEARCH)
	{
		d->active_filter = DATES_FILTER_SEARCH;
		
		GtkWidget * menubox =
			moko_paned_window_get_menubox(MOKO_PANED_WINDOW(d->main_window));

		moko_menu_box_set_active_filter(MOKO_MENU_BOX(menubox), _("Search"));
	}
		
	gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (d->navigator));
	update_status_bar (d);
}

void static
connect_search_box (DatesData * d, GtkWidget * toolbar)
{
	GtkWidget * entry = moko_tool_box_get_entry (MOKO_TOOL_BOX (toolbar));

	g_signal_connect (entry, "changed",
					  G_CALLBACK (entry_changed_cb), d);
}

static GtkWidget *
create_details_toolbar (DatesData *  d)
{
	GtkWidget * toolbar = moko_tool_box_new_with_search();
	GtkWidget * button;
    gtk_widget_grab_focus(toolbar);
	gtk_widget_show (toolbar);

	d->TBDelete =
		GTK_WIDGET (moko_tool_box_add_action_button (MOKO_TOOL_BOX (toolbar)));
	gtk_button_set_label (GTK_BUTTON (d->TBDelete), _("Delete"));
	gtk_widget_show (d->TBDelete);

	g_signal_connect (G_OBJECT (d->TBDelete), "clicked",
					  G_CALLBACK (dates_delete_cb), d);

	button =
		GTK_WIDGET (moko_tool_box_add_action_button (MOKO_TOOL_BOX (toolbar)));
	
	gtk_button_set_label (GTK_BUTTON (button), _("Cancel"));
	gtk_widget_show (button);
	
	g_signal_connect (G_OBJECT (button), "clicked",
					  G_CALLBACK (dates_details_cancel_cb), d);

	button =
		GTK_WIDGET (moko_tool_box_add_action_button (MOKO_TOOL_BOX (toolbar)));
	
	gtk_button_set_label (GTK_BUTTON (button), _("OK"));
	gtk_widget_show (button);
	
	g_signal_connect (G_OBJECT (button), "clicked",
					  G_CALLBACK (dates_details_ok_cb), d);

	connect_search_box (d, toolbar);
	
	gtk_widget_show_all (toolbar);
	return toolbar;
}


static void
set_active_filter (DatesData *d)
{
	GtkWidget * menubox =
		moko_paned_window_get_menubox(MOKO_PANED_WINDOW(d->main_window));

	if (d->zoom == DATES_ZOOM_DAY)
		moko_menu_box_set_active_filter(MOKO_MENU_BOX(menubox), _("Day"));
	else if (d->zoom == DATES_ZOOM_WEEK)
		moko_menu_box_set_active_filter(MOKO_MENU_BOX(menubox), _("Week"));
	else if (d->zoom == DATES_ZOOM_MONTH)
		moko_menu_box_set_active_filter(MOKO_MENU_BOX(menubox), _("Month"));
	else if (d->zoom == DATES_ZOOM_YEAR)
		moko_menu_box_set_active_filter(MOKO_MENU_BOX(menubox), _("Year"));
	else
		g_warning ("%s: zoom %d", __FUNCTION__, d->zoom);
}

#define DATES_PLATFORM_create_main_window
static GtkWidget *
create_main_window (DatesData * d, GtkWidget * toolbar,
					GtkWidget * menu, GtkAccelGroup * accel_group)
{
	GtkWidget    * appmenu;
	GtkWidget    * menubox;
	GtkWidget    * navigator;
	GtkWidget    * details;
    
    /* Temporary hack */
	GtkSettings *settings = gtk_settings_get_default ();
	g_object_set (settings,
			"gtk-theme-name", "openmoko-standard",
			NULL);

    d->main_window = moko_paned_window_new();

	navigator = create_navigation_area (d);
	moko_paned_window_set_navigation_pane (MOKO_PANED_WINDOW (d->main_window), navigator);
	
	gtk_widget_show (menu);
    moko_paned_window_set_filter_menu(MOKO_PANED_WINDOW (d->main_window),
									  GTK_MENU(menu));

    menubox = moko_paned_window_get_menubox(MOKO_PANED_WINDOW(d->main_window));
	
	appmenu = create_app_menu (d);
    moko_paned_window_set_application_menu(MOKO_PANED_WINDOW (d->main_window),
										   GTK_MENU (appmenu));

	d->calendar_toolbar = d->current_toolbar = toolbar;
	gtk_widget_ref (toolbar);
	
	moko_paned_window_add_toolbox(MOKO_PANED_WINDOW (d->main_window),
								  MOKO_TOOL_BOX (toolbar));

	d->details_toolbar = create_details_toolbar (d);
	gtk_widget_ref (d->details_toolbar);
	
	d->header_eventbox = gtk_event_box_new ();

	d->header_label = gtk_label_new (_("<big><b>Dates</b></big>"));
	gtk_widget_show (d->header_label);
	gtk_container_add (GTK_CONTAINER (d->header_eventbox), d->header_label);
	gtk_label_set_use_markup (GTK_LABEL (d->header_label), TRUE);

	gtk_widget_show (GTK_WIDGET (d->view));
	
	details = moko_scrolled_pane_new ();

	moko_scrolled_pane_pack (MOKO_SCROLLED_PANE (details), GTK_WIDGET(d->view));

        moko_paned_window_set_details_pane(MOKO_PANED_WINDOW (d->main_window),
									 details);

	
	GTK_WIDGET_SET_FLAGS (d->view, GTK_CAN_FOCUS);
	GTK_WIDGET_UNSET_FLAGS (d->view, GTK_CAN_DEFAULT);

	gtk_widget_grab_focus (GTK_WIDGET (d->view));

	/* Set nice colours for full-screen date header */
	gtk_widget_set_state (d->header_eventbox, GTK_STATE_SELECTED);
	gtk_widget_set_state (d->header_label, GTK_STATE_SELECTED);

	g_signal_connect (G_OBJECT (d->main_window), "window_state_event",
					  G_CALLBACK (dates_window_state_cb), d);
	g_signal_connect (G_OBJECT (d->main_window), "key_press_event",
					  G_CALLBACK (dates_key_press_cb), d);

    g_signal_connect( G_OBJECT(menubox), "filter_changed",
					  G_CALLBACK(moko_filter_changed), d );

	/* 
	 * Connect the DatesView date_changed signal to call the
	 * populate_navigator so that the navigator gets updated.
	 */
	g_signal_connect (G_OBJECT (d->view), "date_changed",
			  G_CALLBACK (dates_omoko_date_changed_cb), d);

	gtk_widget_show_all (d->main_window);
	
	return d->main_window;
}

#define DATES_PLATFORM_create_main_menu
static GtkWidget *
create_main_menu (DatesData * d, GtkAccelGroup ** accel_group)
{
	GtkWidget     * menuitem;

	*accel_group = NULL;
	d->main_menu = gtk_menu_new ();

	menuitem = gtk_menu_item_new_with_label (_("Day"));
	gtk_widget_show (menuitem);
	gtk_container_add (GTK_CONTAINER (d->main_menu), menuitem);

	menuitem = gtk_menu_item_new_with_label (_("Week"));
	gtk_widget_show (menuitem);
	gtk_container_add (GTK_CONTAINER (d->main_menu), menuitem);

	menuitem = gtk_menu_item_new_with_label (_("Month"));
	gtk_widget_show (menuitem);
	gtk_container_add (GTK_CONTAINER (d->main_menu), menuitem);

	menuitem = gtk_menu_item_new_with_label (_("Year"));
	gtk_widget_show (menuitem);
	gtk_container_add (GTK_CONTAINER (d->main_menu), menuitem);

	menuitem = gtk_menu_item_new_with_label (_("To Do"));
	gtk_widget_show (menuitem);
	gtk_container_add (GTK_CONTAINER (d->main_menu), menuitem);

	menuitem = gtk_menu_item_new_with_label (_("Search"));
	gtk_widget_show (menuitem);
	gtk_container_add (GTK_CONTAINER (d->main_menu), menuitem);
	
	return d->main_menu;
}

static void
today_cb (GtkButton *button, DatesData *data)
{
	dates_today_cb (button, data);
	populate_navigator (data);
}

#define DATES_PLATFORM_create_toolbar
static GtkWidget *
create_toolbar (DatesData *  d)
{
	GtkWidget * toolbar = moko_tool_box_new_with_search();
	
    gtk_widget_grab_focus(toolbar);
	gtk_widget_show (toolbar);


	d->TBForward =
		GTK_WIDGET (moko_tool_box_add_action_button (MOKO_TOOL_BOX (toolbar)));

	moko_pixmap_button_set_center_stock (MOKO_PIXMAP_BUTTON (d->TBForward),
						       GTK_STOCK_GO_FORWARD);
	
	gtk_widget_show (d->TBForward);
	gtk_button_set_focus_on_click (GTK_BUTTON (d->TBForward), FALSE);

	g_signal_connect (G_OBJECT (d->TBForward), "clicked",
					  G_CALLBACK (dates_forward_cb), d);

	d->TBToday =
		GTK_WIDGET (moko_tool_box_add_action_button (MOKO_TOOL_BOX (toolbar)));
	
	moko_pixmap_button_set_center_stock (MOKO_PIXMAP_BUTTON (d->TBToday),
						       GTK_STOCK_HOME);
	
	gtk_widget_show (d->TBToday);
	gtk_button_set_focus_on_click (GTK_BUTTON (d->TBToday), FALSE);

	g_signal_connect (G_OBJECT (d->TBToday), "clicked",
					  G_CALLBACK (today_cb), d);

	d->TBBack =
		GTK_WIDGET (moko_tool_box_add_action_button (MOKO_TOOL_BOX (toolbar)));

	moko_pixmap_button_set_center_stock (MOKO_PIXMAP_BUTTON (d->TBBack),
						       GTK_STOCK_GO_BACK);

	gtk_widget_show (d->TBBack);
	gtk_button_set_focus_on_click (GTK_BUTTON (d->TBBack), FALSE);

	g_signal_connect (G_OBJECT (d->TBBack), "clicked",
					  G_CALLBACK (dates_back_cb), d);

	d->TBNew =
		GTK_WIDGET (moko_tool_box_add_action_button (MOKO_TOOL_BOX (toolbar)));

	moko_pixmap_button_set_center_stock (MOKO_PIXMAP_BUTTON (d->TBNew),
						       GTK_STOCK_NEW);
	gtk_widget_show (d->TBNew);
	gtk_button_set_focus_on_click (GTK_BUTTON (d->TBNew), FALSE);

	g_signal_connect (G_OBJECT (d->TBNew), "clicked",
					  G_CALLBACK (dates_new_cb), d);

	connect_search_box (d, toolbar);
	
	gtk_widget_show_all (toolbar);
	return toolbar;
}

#if 0
static GtkWidget *
create_todo_dialog (DatesData * d)
{
	GtkWidget *vbox;
	GtkWidget *notebook;
	GtkWidget *summary_table;
	GtkWidget *details_calendar_label;
	GtkWidget *label;
	GtkWidget *alignment;
	GtkWidget *hbox;
	GtkWidget *details_end_button;
	GtkWidget *details_table;
	GtkWidget *scrolledwindow1;
	GtkWidget *togglebutton;
	GtkWidget *image;
	GtkWidget *todo_summary_entry;
	GtkWidget *todo_calendar_combobox;
	
	vbox = gtk_vbox_new (FALSE, 0);
	d->details_dialog = vbox;
	gtk_widget_ref (vbox);
	
	gtk_widget_show (vbox);

	notebook = gtk_notebook_new ();
	gtk_widget_show (notebook);
	gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0);

	summary_table = gtk_table_new (3, 2, FALSE);
	gtk_widget_show (summary_table);
	gtk_container_add (GTK_CONTAINER (notebook), summary_table);
	gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (notebook), summary_table,
										TRUE, TRUE, GTK_PACK_START);
	gtk_container_set_border_width (GTK_CONTAINER (summary_table), 12);
	gtk_table_set_row_spacings (GTK_TABLE (summary_table), 6);
	gtk_table_set_col_spacings (GTK_TABLE (summary_table), 6);

	details_calendar_label = gtk_label_new (_("Calendar:"));
	gtk_widget_show (details_calendar_label);
	gtk_table_attach (GTK_TABLE (summary_table), details_calendar_label,
					  0, 1, 0, 1,
					  (GtkAttachOptions) (GTK_FILL),
					  (GtkAttachOptions) (0), 0, 0);
	
	gtk_misc_set_alignment (GTK_MISC (details_calendar_label), 0, 0.5);

	todo_calendar_combobox = gtk_combo_box_new_text ();
	gtk_widget_show (todo_calendar_combobox);
	gtk_table_attach (GTK_TABLE (summary_table), todo_calendar_combobox,
					  1, 2, 0, 1,
					  (GtkAttachOptions) (GTK_FILL),
					  (GtkAttachOptions) (GTK_FILL), 0, 0);
	gtk_combo_box_set_focus_on_click (GTK_COMBO_BOX (todo_calendar_combobox),
									  FALSE);

	label = gtk_label_new (_("Summary:"));
	gtk_widget_show (label);
	gtk_table_attach (GTK_TABLE (summary_table), label, 0, 1, 1, 2,
					  (GtkAttachOptions) (GTK_FILL),
					  (GtkAttachOptions) (0), 0, 0);
	gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);

	todo_summary_entry = gtk_entry_new ();
	gtk_widget_show (todo_summary_entry);
	gtk_table_attach (GTK_TABLE (summary_table), todo_summary_entry,
					  1, 2, 1, 2,
					  (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
					  (GtkAttachOptions) (0), 0, 0);
	gtk_entry_set_activates_default (GTK_ENTRY (todo_summary_entry),
									 TRUE);

	label = gtk_label_new (_("Time:"));
	gtk_widget_show (label);
	gtk_table_attach (GTK_TABLE (summary_table), label, 0, 1, 2, 3,
					  (GtkAttachOptions) (GTK_FILL),
					  (GtkAttachOptions) (0), 0, 0);
	gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);

	alignment = gtk_alignment_new (0.5, 0.5, 0, 1);
	gtk_widget_show (alignment);
	gtk_table_attach (GTK_TABLE (summary_table), alignment, 1, 2, 2, 3,
					  (GtkAttachOptions) (GTK_FILL),
					  (GtkAttachOptions) (GTK_FILL), 0, 0);


	details_end_button = gtk_button_new ();
	gtk_widget_show (details_end_button);
	gtk_container_add (GTK_CONTAINER (alignment), hbox);

	label = gtk_label_new (_("Summary"));
	gtk_widget_show (label);
	gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook),
								gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 0),
								label);

	details_table = gtk_table_new (1, 2, FALSE);
	gtk_widget_show (details_table);
	gtk_container_add (GTK_CONTAINER (notebook), details_table);
	gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (notebook), details_table,
										TRUE, TRUE, GTK_PACK_START);
	gtk_container_set_border_width (GTK_CONTAINER (details_table), 12);
	gtk_table_set_row_spacings (GTK_TABLE (details_table), 6);
	gtk_table_set_col_spacings (GTK_TABLE (details_table), 6);

	label = gtk_label_new (_("Details:"));
	gtk_widget_show (label);
	gtk_table_attach (GTK_TABLE (details_table), label, 0, 1, 0, 1,
					  (GtkAttachOptions) (GTK_FILL),
					  (GtkAttachOptions) (0), 0, 0);
	gtk_misc_set_alignment (GTK_MISC (label), 0, 0);

	scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
	gtk_widget_show (scrolledwindow1);
	gtk_table_attach (GTK_TABLE (details_table), scrolledwindow1, 1, 2, 0, 1,
					  (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
					  (GtkAttachOptions) (GTK_EXPAND | GTK_SHRINK | GTK_FILL),
					  0, 0);
	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1),
									GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(scrolledwindow1),
										 GTK_SHADOW_IN);

	d->details_textview = gtk_text_view_new ();
	gtk_widget_show (d->details_textview);
	gtk_container_add (GTK_CONTAINER (scrolledwindow1), d->details_textview);
	gtk_text_view_set_accepts_tab (GTK_TEXT_VIEW (d->details_textview), FALSE);
	gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (d->details_textview),
								 GTK_WRAP_WORD);

	label = gtk_label_new (_("Details"));
	gtk_widget_show (label);
	gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook),
								gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 1),
								label);

	gtk_widget_grab_focus (todo_summary_entry);
  
	g_signal_connect (G_OBJECT (d->details_dialog), "delete_event",
					  G_CALLBACK (dates_todo_close_cb), d);
	g_signal_connect (G_OBJECT (todo_calendar_combobox), "changed",
					  G_CALLBACK (dates_calendar_combo_changed_cb), d);

    /* FIXME */
	g_signal_connect (G_OBJECT (details_end_button), "clicked",
					  G_CALLBACK (dates_details_time_end_cb), d);

	return d->details_dialog;
}
#endif

#define DATES_PLATFORM_create_details_dialog

GList *contacts_set_widgets_desensitive (GtkWidget *widget);

static void
dates_details_delete_cb (GtkWidget *source, DatesData *d)
{
	ECalComponentText summary;
	GtkWidget *dialog;
	const char *summary_text;
	gchar *prompt;

	e_cal_component_get_summary (d->comp, &summary);
	dialog = d->details_dialog;
	if (GTK_WIDGET_VISIBLE (dialog))
		summary_text = gtk_entry_get_text (GTK_ENTRY (d->details_summary_entry));
	else if (summary.value)
		summary_text = summary.value;
	else if (summary.altrep)
		summary_text = summary.altrep;
	else {
		g_warning ("Deleting event with no summary");
		summary_text = "Unknown event";
	}
	
	prompt = g_strdup_printf (_("Are you sure you want to delete event '%s'?"), summary_text);

	dialog = moko_message_dialog_new ();
	moko_message_dialog_set_message (MOKO_MESSAGE_DIALOG (dialog), prompt);

	g_free (prompt);

	moko_message_dialog_set_image_from_stock (MOKO_MESSAGE_DIALOG (dialog), 
				GTK_STOCK_DIALOG_QUESTION);
			
	gtk_dialog_add_buttons (GTK_DIALOG (dialog),
			    _("Keep event"), GTK_RESPONSE_NO,
			    _("Delete event"), GTK_RESPONSE_YES,
			    NULL);

	if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES)
	{
		/* Reset event type, in case this was a new event */
		d->event_type = NORMAL;
		
		if (d->waiting == NONE) {
			const char *uid = NULL;
			e_cal_component_get_uid (d->comp, &uid);
			e_cal_remove_object (d->cal, uid, NULL);

			/* Hide the details dialog, in case we deleted
			 * * from there.
			 * */
			dates_platform_details_dlg (d, FALSE);
		} else {
			d->widgets = contacts_set_widgets_desensitive (
					d->details_dialog);
			d->waiting = PENDING_DELETE;
		}
	}
	gtk_widget_destroy (dialog);
}

static GtkWidget *
create_details_dialog (DatesData * d)
{
	GtkWidget *vbox;
	GtkWidget *notebook;
	GtkWidget *summary_table;
	GtkWidget *details_calendar_label;
	GtkWidget *label;
	GtkWidget *alignment;
	GtkWidget *hbox;
	GtkWidget *details_start_button;
	GtkWidget *details_end_button;
	GtkWidget *details_table;
	GtkWidget *scrolledwindow1;

	GtkWidget *details_cancel_button;
	GtkWidget *details_ok_button;

	d->details_dialog = moko_dialog_new ();
	moko_dialog_set_title (MOKO_DIALOG (d->details_dialog), _("Details"));

	vbox = MOKO_DIALOG (d->details_dialog)->vbox;
	gtk_widget_show (vbox);

	notebook = gtk_notebook_new ();
	d->details_notebook = notebook;

	gtk_widget_show (notebook);
	gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0);

	summary_table = gtk_table_new (3, 2, FALSE);
	gtk_widget_show (summary_table);
	gtk_container_add (GTK_CONTAINER (notebook), summary_table);
	gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (notebook), summary_table,
										TRUE, TRUE, GTK_PACK_START);
	gtk_container_set_border_width (GTK_CONTAINER (summary_table), 12);
	gtk_table_set_row_spacings (GTK_TABLE (summary_table), 6);
	gtk_table_set_col_spacings (GTK_TABLE (summary_table), 6);

	details_calendar_label = gtk_label_new (_("Calendar:"));
	gtk_widget_show (details_calendar_label);
	gtk_table_attach (GTK_TABLE (summary_table), details_calendar_label,
					  0, 1, 0, 1,
					  (GtkAttachOptions) (GTK_FILL),
					  (GtkAttachOptions) (0), 0, 0);
	
	gtk_misc_set_alignment (GTK_MISC (details_calendar_label), 0, 0.5);

	d->details_calendar_combobox = gtk_combo_box_new_text ();
	gtk_widget_show (d->details_calendar_combobox);
	gtk_table_attach (GTK_TABLE (summary_table), d->details_calendar_combobox,
					  1, 2, 0, 1,
					  (GtkAttachOptions) (GTK_FILL),
					  (GtkAttachOptions) (GTK_FILL), 0, 0);
	gtk_combo_box_set_focus_on_click (GTK_COMBO_BOX (d->details_calendar_combobox),
									  FALSE);

	label = gtk_label_new (_("Summary:"));
	gtk_widget_show (label);
	gtk_table_attach (GTK_TABLE (summary_table), label, 0, 1, 1, 2,
					  (GtkAttachOptions) (GTK_FILL),
					  (GtkAttachOptions) (0), 0, 0);
	gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);

	d->details_summary_entry = gtk_entry_new ();
	gtk_widget_show (d->details_summary_entry);
	gtk_table_attach (GTK_TABLE (summary_table), d->details_summary_entry,
					  1, 2, 1, 2,
					  (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
					  (GtkAttachOptions) (0), 0, 0);
	gtk_entry_set_activates_default (GTK_ENTRY (d->details_summary_entry),
									 TRUE);

	label = gtk_label_new (_("Time:"));
	gtk_widget_show (label);
	gtk_table_attach (GTK_TABLE (summary_table), label, 0, 1, 2, 3,
					  (GtkAttachOptions) (GTK_FILL),
					  (GtkAttachOptions) (0), 0, 0);
	gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);

	alignment = gtk_alignment_new (0.5, 0.5, 0, 1);
	gtk_widget_show (alignment);
	gtk_table_attach (GTK_TABLE (summary_table), alignment, 1, 2, 2, 3,
					  (GtkAttachOptions) (GTK_FILL),
					  (GtkAttachOptions) (GTK_FILL), 0, 0);

	hbox = gtk_hbox_new (FALSE, 6);
	gtk_widget_show (hbox);
	gtk_container_add (GTK_CONTAINER (alignment), hbox);

	details_start_button = gtk_button_new ();
	gtk_widget_show (details_start_button);
	gtk_box_pack_start (GTK_BOX (hbox), details_start_button, TRUE, TRUE, 0);

	d->details_start_label = gtk_label_new (_("Start"));
	gtk_widget_show (d->details_start_label);
	gtk_container_add (GTK_CONTAINER (details_start_button),
					   d->details_start_label);
	gtk_label_set_use_markup (GTK_LABEL (d->details_start_label), TRUE);
	gtk_label_set_justify (GTK_LABEL (d->details_start_label),
						   GTK_JUSTIFY_CENTER);
	gtk_misc_set_padding (GTK_MISC (d->details_start_label), 3, 3);

	label = gtk_label_new (_("to"));
	gtk_widget_show (label);
	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);

	details_end_button = gtk_button_new ();
	gtk_widget_show (details_end_button);
	gtk_box_pack_start (GTK_BOX (hbox), details_end_button, TRUE, TRUE, 0);

	d->details_end_label = gtk_label_new (_("End"));
	gtk_widget_show (d->details_end_label);
	gtk_container_add (GTK_CONTAINER (details_end_button),
					   d->details_end_label);
	gtk_label_set_justify (GTK_LABEL (d->details_end_label),
						   GTK_JUSTIFY_CENTER);
	gtk_misc_set_padding (GTK_MISC (d->details_end_label), 3, 3);

	label = gtk_label_new (_("Summary"));
	gtk_widget_show (label);
	gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook),
								gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 0),
								label);

	details_table = gtk_table_new (1, 2, FALSE);
	gtk_widget_show (details_table);
	gtk_container_add (GTK_CONTAINER (notebook), details_table);
	gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (notebook), details_table,
										TRUE, TRUE, GTK_PACK_START);
	gtk_container_set_border_width (GTK_CONTAINER (details_table), 12);
	gtk_table_set_row_spacings (GTK_TABLE (details_table), 6);
	gtk_table_set_col_spacings (GTK_TABLE (details_table), 6);

	label = gtk_label_new (_("Details:"));
	gtk_widget_show (label);
	gtk_table_attach (GTK_TABLE (details_table), label, 0, 1, 0, 1,
					  (GtkAttachOptions) (GTK_FILL),
					  (GtkAttachOptions) (0), 0, 0);
	gtk_misc_set_alignment (GTK_MISC (label), 0, 0);

	scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
	gtk_widget_show (scrolledwindow1);
	gtk_table_attach (GTK_TABLE (details_table), scrolledwindow1, 1, 2, 0, 1,
					  (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
					  (GtkAttachOptions) (GTK_EXPAND | GTK_SHRINK | GTK_FILL),
					  0, 0);
	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow1),
									GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(scrolledwindow1),
										 GTK_SHADOW_IN);

	d->details_textview = gtk_text_view_new ();
	gtk_widget_show (d->details_textview);
	gtk_container_add (GTK_CONTAINER (scrolledwindow1), d->details_textview);
	gtk_text_view_set_accepts_tab (GTK_TEXT_VIEW (d->details_textview), FALSE);
	gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (d->details_textview),
								 GTK_WRAP_WORD);

	label = gtk_label_new (_("Details"));
	gtk_widget_show (label);
	gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook),
								gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 1),
								label);


	d->details_delete_button = moko_dialog_add_button_secondary (MOKO_DIALOG (d->details_dialog),
			"gtk-delete", GTK_RESPONSE_CLOSE);

	details_cancel_button = moko_dialog_add_button (MOKO_DIALOG (d->details_dialog),
			"gtk-cancel", GTK_RESPONSE_CANCEL);

	details_ok_button = moko_dialog_add_button (MOKO_DIALOG (d->details_dialog),
			"gtk-ok", GTK_RESPONSE_OK);

	gtk_widget_grab_focus (d->details_summary_entry);

	GTK_WIDGET_SET_FLAGS (details_ok_button, GTK_CAN_DEFAULT);
	gtk_widget_grab_default (details_ok_button);
  
	g_signal_connect (G_OBJECT (d->details_dialog), "delete_event",
					  G_CALLBACK (dates_details_close_cb),
					  d);
	g_signal_connect (G_OBJECT (d->details_calendar_combobox), "changed",
					  G_CALLBACK (dates_calendar_combo_changed_cb),
					  d);
	g_signal_connect (G_OBJECT (details_start_button), "clicked",
					  G_CALLBACK (dates_details_time_start_cb),
					  d);
	g_signal_connect (G_OBJECT (details_end_button), "clicked",
					  G_CALLBACK (dates_details_time_end_cb),
					  d);
	g_signal_connect (G_OBJECT (d->details_delete_button), "clicked",
					  G_CALLBACK (dates_details_delete_cb),
					  d);
	g_signal_connect (G_OBJECT (details_cancel_button), "clicked",
					  G_CALLBACK (dates_details_cancel_cb),
					  d);
	g_signal_connect (G_OBJECT (details_ok_button), "clicked",
					  G_CALLBACK (dates_details_ok_cb),
					  d);

	return d->details_dialog;
}

#define DATES_PLATFORM_dates_platform_init
void
dates_platform_init (DatesData * d)
{
    d->app = MOKO_APPLICATION(moko_application_get_instance());
    g_set_application_name( "Calendar" );
}

#define DATES_PLATFORM_dates_platform_cal_open
void dates_platform_cal_open (DatesData * d)
{
	populate_navigator (d);
}

#define DATES_PLATFORM_dates_platform_pre_show
void
dates_platform_pre_show (DatesData *d)
{
	set_active_filter (d);
}

void
dates_omoko_date_changed_cb (DatesView *view, DatesData *d)
{
	/* Update the navigator on the change of date in the DatesView widget */
	populate_navigator (d);
}


#define DATES_RESPONSE_DELETE 1

#define DATES_PLATFORM_new_calendar_dialog
static void
entry_changed (GtkEditable *editable, gpointer user_data)
{
	/* 
	 * User data is the okay button. We want to set it insensitive if the
	 * contents of the text entry is empty.
	 */
	GtkWidget *button = GTK_WIDGET (user_data);
	gchar *text = NULL;

	text = g_strdup(gtk_entry_get_text (GTK_ENTRY (editable)));

	g_strstrip (text);

	if (strlen (text) == 0)
		gtk_widget_set_sensitive (button, FALSE);
	else
		gtk_widget_set_sensitive (button, TRUE);

	g_free (text);
}

static void
combo_box_changed (GtkComboBox *widget, gpointer user_data)
{
	/* The user_data is the hbox for the URI. We need to decide whether to
	 * show or hide it */
	GtkTreeModel *model;
	GtkTreeIter iter;
	GtkWidget *hbox = *((GtkWidget **)user_data);

	model = gtk_combo_box_get_model (widget);

	if (gtk_combo_box_get_active_iter (widget, &iter))
	{
		ESourceGroup *group;
		const gchar *base_uri;
		gtk_tree_model_get (model, &iter, 1, &group, -1);

		base_uri = e_source_group_peek_base_uri (group);
		
		if (strncmp (base_uri, "webcal://", 9) == 0)
		{
			gtk_widget_show_all (GTK_WIDGET (hbox));
		} else {
			gtk_widget_hide_all (GTK_WIDGET (hbox));
		}
	}
}

void
calendar_do_new_dialog (GtkWindow *parent, DatesData *d)
{
	GtkWidget *dialog = NULL;
	GtkWidget *frame = NULL;
	GtkWidget *name_entry = NULL;
	GtkWidget *uri_entry = NULL;
	GtkWidget *vbox = NULL;
	GtkWidget *hbox = NULL;
	GtkWidget *uri_hbox = NULL;
	GtkWidget *label = NULL;
	GtkWidget *type_combo = NULL;
	GtkWidget *color_button = NULL;
	GtkWidget *okay_button = NULL;

	GtkSizeGroup *horizontal_size;

	GSList *group_list = NULL;
	GSList *cur_entry = NULL;

	GtkListStore *type_store = NULL;
	GtkCellRenderer *renderer = NULL;

	GdkColor colour;

	const gchar *uri = NULL;

	gint res; /* result for the dialog */

	dialog = moko_dialog_new ();
	moko_dialog_set_title (MOKO_DIALOG (dialog), _("New calendar"));

	moko_dialog_add_button (MOKO_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
	okay_button = moko_dialog_add_button (MOKO_DIALOG (dialog), GTK_STOCK_OK, GTK_RESPONSE_OK);

	/* Make okay insentive by default */
	gtk_widget_set_sensitive (okay_button, FALSE);

	/* Create the frame */
	frame = gtk_frame_new (NULL);

	/* Remove the shadow */
	gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);

	/* Set a border of 12 (HIG) */
	gtk_container_set_border_width (GTK_CONTAINER (frame), 12);

	/* Place the frame inside the dialog */
	gtk_box_pack_start (GTK_BOX(MOKO_DIALOG (dialog)->vbox), frame, FALSE, FALSE, 6);

	/* Create the vbox for inside the frame */
	vbox = gtk_vbox_new (FALSE, 6);

	/* Set a border of 12 (HIG) */
	gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);

	/* Place the vbox inside the frame */
	gtk_container_add (GTK_CONTAINER (frame), vbox);

	/* Create a size group for the labels on the left hand side */
	horizontal_size = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);

	/* Stuff for the type */

	/* Create hbox for the type */
	hbox = gtk_hbox_new (FALSE, 6);

	/* Create the label for the type */
	label = gtk_label_new (_("Type:"));

	/* Align the text in the label to the left */
	gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);

	/* Add the label to the size group */
	gtk_size_group_add_widget (horizontal_size, label);

	/* Add the label to the hbox */
	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);

	/* Create the model for the combo box */
	type_store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_POINTER);

	/* Get the list of groups from the list of sources */
	group_list = e_source_list_peek_groups (d->source_list);

	for (cur_entry = group_list; cur_entry != NULL; cur_entry = g_slist_next (cur_entry))
	{
		ESourceGroup *group = (ESourceGroup *)(cur_entry->data);
		const gchar *base_uri = e_source_group_peek_base_uri (group);

		if (strncmp (base_uri, "webcal://", 9) == 0 || 
				strncmp (base_uri, "file://", 7) == 0)
		{
			GtkTreeIter iter;
			gtk_list_store_append (type_store, &iter);
			gtk_list_store_set (type_store, &iter, 
					0, e_source_group_peek_name (group),
					1, group,
					-1);
		}
	}
	

	/* Create the combo for the type */
	type_combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL(type_store));

	/* Create a renderer for the column */
	renderer = gtk_cell_renderer_text_new ();
	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (type_combo), renderer, TRUE);
	gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (type_combo), renderer,
			"text", 0,
			NULL);

	g_signal_connect (type_combo, "changed", (GCallback)combo_box_changed, &uri_hbox);

	/* Add the combo */
	gtk_box_pack_start (GTK_BOX (hbox), type_combo, TRUE, TRUE, 0);

	/* Add the hbox to the vbox */
	gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);

	/* Stuff for the name label/entry */

	/* Create the hbox for the name */
	hbox = gtk_hbox_new (FALSE, 6);

	/* Create the label for the name */
	label = gtk_label_new_with_mnemonic (_("_Name:"));

	/* Align the text in the label to the left */
	gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);

	/* Create the text entry for the name of the calendar */
	name_entry = gtk_entry_new ();

	/* Mark the mnemonic for the label to the entry widget */
	gtk_label_set_mnemonic_widget (GTK_LABEL(label), name_entry);

	/* Add the label to the hbox */
	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);

	/* Add the entry to the hbox */
	gtk_box_pack_start (GTK_BOX (hbox), name_entry, TRUE, TRUE, 0);

	/* 
	 * Connect a signal handler onto the entry's changed signal to
	 * control whether to turn on the OK button.
	 */
	g_signal_connect (name_entry, "changed", (GCallback)entry_changed, okay_button);

	/* Add the label to the size group */
	gtk_size_group_add_widget (horizontal_size, label);

	/* Add the hbox to the vbox */
	gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);


	/* Create the hbox for the colour */
	hbox = gtk_hbox_new (FALSE, 6);

	/* Create the label for the name */
	label = gtk_label_new_with_mnemonic (_("_Colour:"));

	/* Align the text in the label to the left */
	gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);

	/* Create a new color button with this colour */
	color_button = gtk_color_button_new ();

	/* Add the label to the hbox */
	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);

	/* Add the label to the size group */
	gtk_size_group_add_widget (horizontal_size, label);
	

	/* Add the color button to the hbox */
	gtk_box_pack_start (GTK_BOX (hbox), color_button, TRUE, TRUE, 0);

	/* Add the hbox to the vbox */
	gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);

	/* Make the internal vbox visible */
	gtk_widget_show_all (MOKO_DIALOG (dialog)->vbox);

	/* Stuff for the uri. Note that we show everything else before this
	 * since we want to control the visibility based on combo */

	/* Create the hbox for the uri */
	uri_hbox = gtk_hbox_new (FALSE, 6);

	/* Create the label for the uri */
	label = gtk_label_new_with_mnemonic (_("_Location:"));

	/* Align the text in the label to the left */
	gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);

	/* Create the text entry for the uri of the calendar */
	uri_entry = gtk_entry_new ();

	/* Mark the mnemonic for the label to the entry widget */
	gtk_label_set_mnemonic_widget (GTK_LABEL(label), uri_entry);

	/* Add the label to the hbox */
	gtk_box_pack_start (GTK_BOX (uri_hbox), label, FALSE, FALSE, 0);

	/* Add the label to the size group */
	gtk_size_group_add_widget (horizontal_size, label);

	/* Add the entry to the hbox */
	gtk_box_pack_start (GTK_BOX (uri_hbox), uri_entry, TRUE, TRUE, 0);

	/* Add the hbox to the vbox */
	gtk_box_pack_start (GTK_BOX (vbox), uri_hbox, TRUE, TRUE, 0);


	/* Make the dialog non-resizeable */
	gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);

	/* Show the dialog and capture the response */
	res = moko_dialog_run (MOKO_DIALOG (dialog));

	switch (res)
	{
		case GTK_RESPONSE_OK:
		{
			ESource *source;
			const gchar *name =  NULL;
			ESourceGroup *group;
			GtkTreeIter iter;
			GError *error = NULL;
			const gchar *relative_uri;
			guint32 new_colour;

			/* Get the name from the text entry */
			name = gtk_entry_get_text (GTK_ENTRY(name_entry));

			/* Get the appropriate group from the combo box */
			if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX(type_combo), &iter))
			{
				gtk_tree_model_get (GTK_TREE_MODEL(type_store), &iter, 1, &group, -1);
			}
			
			if (strncmp (e_source_group_peek_base_uri (group), "webcal://", 9) == 0)
			{
				/* Get the uri from the text entry */
				uri = gtk_entry_get_text (GTK_ENTRY(uri_entry));

				if (strncmp (uri, "webcal://", 9) == 0)
				{
					relative_uri = &uri[9];
				} else {
					if (strncmp (uri, "http://", 7) == 0)
					{
						relative_uri = &uri[7];
					} else {
						relative_uri = uri;
					}
				}
			} else {
				relative_uri = e_cal_component_gen_uid ();
			}

			/* Create a new source to use */
			source = e_source_new (name, relative_uri);

			gtk_color_button_get_color (GTK_COLOR_BUTTON(color_button), &colour);
			
			new_colour = (guint8)(colour.red >> 8);
			new_colour <<= 8;
			new_colour |= (guint8)(colour.green >> 8);
			new_colour <<= 8;
			new_colour |= (guint8)(colour.blue >> 8);
			new_colour <<= 8;

			/* Set the colour */
			e_source_set_color (source, new_colour);

			/* Set the group for the source */
			e_source_set_group (source, group);
			e_source_group_add_source (group, source, 0);

			/* 
			 * We must sync our list of sources with the version
			 * in gconf.
			 */
			if (!e_source_list_sync (d->source_list, &error))
			{
				g_warning ("Error syncing ESourceList: %s",
					   error->message);
				g_error_free (error);
			}
		}
	}

	gtk_widget_destroy (dialog);
}

#define DATES_PLATFORM_calendar_edit_dialog

/* 
 * We need to explicitly hook into the response signal to deal with the delete
 * case since if the user hits cancel we need to stop the signal in its tracks
 * so that the user can use the other buttons in the dialog if they decide to
 * cancel the delete.
 */
static void
calendar_do_edit_dialog_response_cb (GtkDialog *dialog, gint response_id, gpointer user_data)
{
	if (response_id == DATES_RESPONSE_DELETE)
	{
		GtkWidget *delete_dialog;
		gint res;
		gchar *prompt = NULL;

		gchar *name = (gchar *)user_data;

		prompt = g_strdup_printf (_("Are you sure you want to delete the calendar named '%s'?"), name);

		delete_dialog = moko_message_dialog_new ();
		moko_message_dialog_set_message (MOKO_MESSAGE_DIALOG (delete_dialog), prompt);
		moko_message_dialog_set_image_from_stock (MOKO_MESSAGE_DIALOG (delete_dialog), GTK_STOCK_DIALOG_QUESTION);

		g_free (prompt);

		gtk_dialog_add_buttons (GTK_DIALOG (delete_dialog), 
				GTK_STOCK_CANCEL,
				GTK_RESPONSE_CANCEL,
				GTK_STOCK_DELETE,
				DATES_RESPONSE_DELETE,
				NULL);

		res = gtk_dialog_run (GTK_DIALOG (delete_dialog));

		if (res == DATES_RESPONSE_DELETE)
		{
			/* Let gtk_dialog_run return and then deal with stuff there */
			return;
		} else {
			/* 
			 * Stop the 'response' signal in its tracks
			 * and therefore continue to keep the other
			 * buttons in them main dialog responsive
			 */
			g_signal_stop_emission_by_name (dialog, "response");
			gtk_widget_destroy (delete_dialog);
		}
	}

}

void
calendar_do_edit_dialog (GtkWindow *parent, ESource *source, DatesData *d)
{
	GtkWidget *dialog = NULL;
	GtkWidget *frame = NULL;
	GtkWidget *name_entry = NULL;
	GtkWidget *uri_entry = NULL;
	GtkWidget *vbox = NULL;
	GtkWidget *hbox = NULL;
	GtkWidget *label = NULL;
	GtkWidget *type_label = NULL;
	GtkWidget *color_button = NULL;
	GtkWidget *okay_button = NULL;

	GtkSizeGroup *horizontal_size;

	ESourceGroup *group;

	GdkColor colour;
	guint32 raw_colour;

	const gchar *name = NULL;
	const gchar *uri = NULL;
	gchar *type = NULL;

	gboolean remote = FALSE;

	gint res; /* result for the dialog */

	dialog = moko_dialog_new ();
	moko_dialog_set_title (MOKO_DIALOG (dialog), _("Edit calendar"));

	moko_dialog_add_button (MOKO_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);

	/* 
	 * Add the OK button separately so that we can keep a pointer to the
	 * widget
	 */
	okay_button = moko_dialog_add_button (MOKO_DIALOG (dialog), GTK_STOCK_OK, GTK_RESPONSE_OK);

	/* 
	 * Check if this is the system calendar or not. We shouldn't let it be
	 * deleted.
	 */

	if (!(strncmp (e_source_peek_relative_uri (source), "system", 6) == 0))
	{
		moko_dialog_add_button_secondary (MOKO_DIALOG (dialog), GTK_STOCK_DELETE, DATES_RESPONSE_DELETE);
	}

	/* Get the group for the source */
	group = e_source_peek_group (source);

	/* Create the frame */
	frame = gtk_frame_new (NULL);

	/* Remove the shadow */
	gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);

	/* Set a border of 12 (HIG) */
	gtk_container_set_border_width (GTK_CONTAINER (frame), 12);

	/* Place the alignment inside the dialog */
	gtk_box_pack_start (GTK_BOX (MOKO_DIALOG (dialog)->vbox), frame, FALSE, FALSE, 6);

	/* Create the vbox for inside the frame */
	vbox = gtk_vbox_new (FALSE, 6);

	/* Set a border of 12 (HIG) */
	gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);

	/* Place the vbox inside the frame */
	gtk_container_add (GTK_CONTAINER (frame), vbox);

	/* Create a size group for the labels on the left hand side */
	horizontal_size = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);

	/* Stuff for the type */

	/* Create hbox for the type */
	hbox = gtk_hbox_new (FALSE, 6);

	/* Create the label for the type */
	label = gtk_label_new (_("Type:"));

	/* Align the text in the label to the left */
	gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);

	/* Grab the type from the group name */
	type = g_strdup_printf ("<b>%s</b>", e_source_group_peek_name (group));

	/* Create a second label for the type string itself */
	type_label = gtk_label_new (type);

	/* Turn on the markup for the label */
	gtk_label_set_use_markup (GTK_LABEL (type_label), TRUE);

	/* Align the text in the label to the left */
	gtk_misc_set_alignment (GTK_MISC (type_label), 0, 0.5);

	/* Add the label to the size group */
	gtk_size_group_add_widget (horizontal_size, label);

	/* Add the two labels to the hbox */
	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
	gtk_box_pack_start (GTK_BOX (hbox), type_label, TRUE, TRUE, 0);

	/* Add the hbox to the vbox */
	gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);

	/* Stuff for the name label/entry */

	/* Create the hbox for the name */
	hbox = gtk_hbox_new (FALSE, 6);

	/* Create the label for the name */
	label = gtk_label_new_with_mnemonic (_("_Name:"));

	/* Align the text in the label to the left */
	gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);

	/* Create the text entry for the name of the calendar */
	name_entry = gtk_entry_new ();

	/* Mark the mnemonic for the label to the entry widget */
	gtk_label_set_mnemonic_widget (GTK_LABEL(label), name_entry);

	/* Add the label to the hbox */
	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);

	/* Add the entry to the hbox */
	gtk_box_pack_start (GTK_BOX (hbox), name_entry, TRUE, TRUE, 0);

	/* Add the label to the size group */
	gtk_size_group_add_widget (horizontal_size, label);

	/* Add the hbox to the vbox */
	gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);

	/* Get the name from the source */
	name = e_source_peek_name (source);

	/* Set the entry to the name */
	gtk_entry_set_text (GTK_ENTRY (name_entry), name);

	/* 
	 * Connect a signal handler onto the entry's changed signal to
	 * control whether to turn on the OK button.
	 */
	g_signal_connect (name_entry, "changed", (GCallback)entry_changed, okay_button);

	/* Stuff for the colour button */

	/* Create the hbox for the colour */
	hbox = gtk_hbox_new (FALSE, 6);

	/* Create the label for the name */
	label = gtk_label_new_with_mnemonic (_("_Colour:"));

	/* Align the text in the label to the left */
	gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);

	/* Get the colour from the the source */
	e_source_get_color (source, &raw_colour);

	/* Munge this into something usable */
	colour.red = (guint16)(((raw_colour & 0xff0000) >> 16) << 8);
	colour.green = (guint16)(((raw_colour & 0xff00) >> 8) << 8);
	colour.blue = (guint16)(((raw_colour & 0xff) << 8));

	/* Now we need to allocate the colour */
	gdk_colormap_alloc_color (gdk_colormap_get_system (), &colour, TRUE, TRUE);
	
	/* Create a new color button with this colour */
	color_button = gtk_color_button_new_with_color (&colour);

	/* Add the label to the hbox */
	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);

	/* Add the label to the size group */
	gtk_size_group_add_widget (horizontal_size, label);
	

	/* Add the color button to the hbox */
	gtk_box_pack_start (GTK_BOX (hbox), color_button, TRUE, TRUE, 0);

	/* Add the hbox to the vbox */
	gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);

	/* Stuff for the uri label/entry */

	/* 
	 * We only want to show the URI iff the source is from a webcal://
	 * based group
	 */

	if (strncmp (e_source_group_peek_base_uri (group), "webcal://", 9) == 0)
	{
		remote = TRUE;
		
		/* Create the hbox for the uri */
		hbox = gtk_hbox_new (FALSE, 6);

		/* Create the label for the uri */
		label = gtk_label_new_with_mnemonic (_("_Location:"));

		/* Align the text in the label to the left */
		gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);

		/* Create the text entry for the uri of the calendar */
		uri_entry = gtk_entry_new ();

		/* Mark the mnemonic for the label to the entry widget */
		gtk_label_set_mnemonic_widget (GTK_LABEL(label), uri_entry);

		/* Add the label to the hbox */
		gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);

		/* Add the label to the size group */
		gtk_size_group_add_widget (horizontal_size, label);

		/* Add the entry to the hbox */
		gtk_box_pack_start (GTK_BOX (hbox), uri_entry, TRUE, TRUE, 0);

		/* Add the hbox to the vbox */
		gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);

		/* Get the URI */
		uri = g_strdup_printf ("%s%s", e_source_group_peek_base_uri (group), 
				e_source_peek_relative_uri (source));

		/* Set the entry to the uri */
		gtk_entry_set_text (GTK_ENTRY (uri_entry), uri);
	}

	/* Make the internal vbox visible */
	gtk_widget_show_all (MOKO_DIALOG (dialog)->vbox);

	/* Make the dialog non-resizeable */
	gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);

	/* Connect a signal handler to the response signal to deal with
	 * bringing up a confirmation dialog for the delete button.
	 */

	g_signal_connect (dialog, "response", 
			G_CALLBACK(calendar_do_edit_dialog_response_cb), (gpointer)name);

	/* Show the dialog and capture the response */
	res = moko_dialog_run (MOKO_DIALOG (dialog));

	switch (res)
	{
		case GTK_RESPONSE_OK:
		{
			/* 
			 * Next we need to pack the GDK colour into guint32
			 * for eds
			 */
			guint32 new_colour = 0;

			GError *error = NULL;

			gtk_color_button_get_color (GTK_COLOR_BUTTON(color_button), &colour);
			
			new_colour = (guint8)(colour.red >> 8);
			new_colour <<= 8;
			new_colour |= (guint8)(colour.green >> 8);
			new_colour <<= 8;
			new_colour |= (guint8)(colour.blue >> 8);
			new_colour <<= 8;

			/* Update the colour */
			e_source_set_color (source, new_colour);

			/* And the name */
			e_source_set_name (source, (gtk_entry_get_text (GTK_ENTRY (name_entry))));

			if (remote)
			{
				const gchar *new_uri = gtk_entry_get_text (GTK_ENTRY(uri_entry));

				/* e_source_set_absolute_uri doesn't work. */

				/* Support webcal links */
				if (strncmp (new_uri, "webcal://", 9) == 0)
				{
					e_source_set_relative_uri (source, &new_uri[9]);
					printf ("%s\n", &new_uri[9]);
				} else {
					/* But also support http links */
					if (strncmp (new_uri, "http://", 7) == 0)
					{
						e_source_set_relative_uri (source, &new_uri[7]);
					} else {
						e_source_set_relative_uri (source, new_uri);
					}
				}
			}

			gtk_widget_destroy (dialog);

			/* 
			 * We must sync our list of sources with the version
			 * in gconf.
			 */
			if (!e_source_list_sync (d->source_list, &error))
			{
				g_warning ("Error syncing ESourceList: %s",
					   error->message);
				g_error_free (error);
			}


			break;
		}

		case DATES_RESPONSE_DELETE:
		{
			GError *error = NULL;
			/* Delete this one */
			e_source_list_remove_source_by_uid (d->source_list,e_source_peek_uid (source));

			/* 
			 * We must sync our list of sources with the version
			 * in gconf.
			 */
			if (!e_source_list_sync (d->source_list, &error))
			{
				g_warning ("Error syncing ESourceList: %s",
					   error->message);
				g_error_free (error);
			}

			gtk_widget_destroy (dialog);

			break;
		}
		default:
			gtk_widget_destroy (dialog);
			break;
	}

	g_free (type);
}


#define DATES_PLATFORM_calendars_dialog

enum {
	CALENDARS_DLG_NEW,
	CALENDARS_DLG_EDIT,
	CALENDARS_DLG_DELETE,
	CALENDARS_DLG_CLOSE	
};

static void
calendars_response_cb (GtkDialog *dialog, gint id, gpointer data)
{
	DatesData * d = data;

	switch (id)
	{
		case CALENDARS_DLG_NEW:
			calendar_do_new_dialog (GTK_WINDOW(d->main_window), d);
			break;
		case CALENDARS_DLG_EDIT:
		{
			GtkTreeSelection *selection = NULL; 
			GtkTreeIter iter;
			GtkTreeModel *model = NULL;
			
			/* First get the selection from the tree view */
			selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(d->cal_tree_view));
			
			/* If there is something selected */
			if (gtk_tree_selection_get_selected (selection, &model, &iter))
			{
				ECal *ecal;
				ESource *source;
				gtk_tree_model_get (model, &iter, COL_CALPTR, &ecal, -1);
				
				if (ecal != NULL)
				{
					source = e_cal_get_source (ecal);
					calendar_do_edit_dialog (GTK_WINDOW(d->main_window), source, d);
				}
			}
			break;
		}
		case CALENDARS_DLG_CLOSE:
		case GTK_RESPONSE_NONE:
		case GTK_RESPONSE_DELETE_EVENT:
			dates_platform_calendars_dlg (d, FALSE);
			break;

		default:
			g_debug ("Unknown/unimplemented response signal %d", id);
	}

}

static GtkWidget *
create_calendars_dialog (DatesData * d)
{
	GtkWidget *vbox;
	GtkWidget *scrolledwindow;
	GtkWidget *cal_new_button;
	GtkWidget *cal_edit_button;
	GtkWidget *cal_close_button;
	GtkWidget *frame;

	d->calendars_dialog = moko_dialog_new ();
	moko_dialog_set_title (MOKO_DIALOG (d->calendars_dialog), Q_("Calendars"));
	gtk_window_set_position (GTK_WINDOW (d->calendars_dialog),
							 GTK_WIN_POS_CENTER_ON_PARENT);

	vbox = MOKO_DIALOG (d->calendars_dialog)->vbox;

	scrolledwindow = gtk_scrolled_window_new (NULL, NULL);

	frame = gtk_frame_new (NULL);
	gtk_container_set_border_width (GTK_CONTAINER (frame), 12);
	gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 6);

	GTK_WIDGET_UNSET_FLAGS (scrolledwindow, GTK_CAN_FOCUS);
	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
			GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow),
			GTK_SHADOW_IN);

	d->cal_tree_view = gtk_tree_view_new ();
	gtk_container_add (GTK_CONTAINER (scrolledwindow), d->cal_tree_view);

	GTK_WIDGET_UNSET_FLAGS (d->cal_tree_view, GTK_CAN_FOCUS);
	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (d->cal_tree_view),
									   FALSE);

	cal_new_button = moko_dialog_add_button_secondary (MOKO_DIALOG (d->calendars_dialog),
			"gtk-new", CALENDARS_DLG_NEW);

	cal_edit_button = moko_dialog_add_button_secondary (MOKO_DIALOG (d->calendars_dialog),
			"gtk-edit", CALENDARS_DLG_EDIT);

	cal_close_button = moko_dialog_add_button (MOKO_DIALOG (d->calendars_dialog),
			"gtk-close", CALENDARS_DLG_CLOSE);

	g_signal_connect (G_OBJECT (d->calendars_dialog), "delete_event",
					  G_CALLBACK (gtk_widget_hide), d);

	g_signal_connect (G_OBJECT (d->calendars_dialog), "response",
					  G_CALLBACK (calendars_response_cb), d);

	gtk_container_add (GTK_CONTAINER (frame), scrolledwindow);

	gtk_widget_show_all (vbox);

	return d->calendars_dialog;
}

/* The rest we 'inherit' */
#include "dates_gtk.c"
