
#include <config.h>
#include <string.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <gconf/gconf-client.h>
#include <moko-finger-scroll.h>
#include <moko-stock.h>
#include <moko-search-bar.h>
#include <libtaku/launcher-util.h>
#include <libtaku/xutil.h>
#include <unistd.h>
#include <libjana/jana.h>
#include <libjana-ecal/jana-ecal.h>
#include <libjana-gtk/jana-gtk.h>
#include "today.h"
#include "today-utils.h"
#include "today-pim-journal.h"
#include "today-launcher.h"
#include "today-task-manager.h"

static void
today_notebook_add_page_with_icon (GtkWidget *notebook, GtkWidget *child,
				   const gchar *icon_name, int padding)
{
	GtkWidget *icon = gtk_image_new_from_icon_name (icon_name,
		GTK_ICON_SIZE_LARGE_TOOLBAR);
	GtkWidget *align = gtk_alignment_new (0.5, 0.5, 1, 1);

	gtk_alignment_set_padding (GTK_ALIGNMENT (align), padding,
		padding, padding, padding);
	gtk_container_add (GTK_CONTAINER (align), icon);
	gtk_widget_show_all (align);
	gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child, align);
	gtk_container_child_set (GTK_CONTAINER (notebook), child,
		"tab-expand", TRUE, NULL);
}

static void
today_dial_button_clicked_cb (GtkToolButton *button, TodayData *data)
{
	if (data->dialer_item) launcher_start (data->window, data->dialer_item,
		(gchar *[]){ "openmoko-dialer", NULL }, TRUE, TRUE);
}

static void
today_contacts_button_clicked_cb (GtkToolButton *button, TodayData *data)
{
	if (data->contacts_item) launcher_start (data->window, data->contacts_item,
		(gchar *[]){ "openmoko-contacts", NULL }, TRUE, TRUE);
}

static void
today_messages_button_clicked_cb (GtkToolButton *button, TodayData *data)
{
	if (data->messages_item) launcher_start (data->window,
		data->messages_item,
		(gchar *[]){ "openmoko-messages", NULL }, TRUE, TRUE);
}

static void
today_dates_button_clicked_cb (GtkToolButton *button, TodayData *data)
{
	if (data->dates_item) launcher_start (data->window, data->dates_item,
		(gchar *[]){ "openmoko-dates", NULL }, TRUE, TRUE);
}

static gboolean
bg_expose_cb (GtkWidget *widget, GdkEventExpose *event, TodayData *data)
{
	if (data->wallpaper)
		gdk_draw_drawable (widget->window, widget->style->black_gc,
			data->wallpaper, 0, 0, 0, 0, -1, -1);
	
	return FALSE;
}

static gboolean
bg_child_expose_cb (GtkWidget *widget, GdkEventExpose *event, TodayData *data)
{
	cairo_t *cr;
	
	if ((!GTK_WIDGET_VISIBLE (data->missed_calls_box)) &&
	    (!GTK_WIDGET_VISIBLE (data->unread_messages_box)) &&
	    (!GTK_WIDGET_VISIBLE (data->dates_box)) &&
	    (!GTK_WIDGET_VISIBLE (data->tasks_box))) return FALSE;
	
	/* Draw a semi-transparent rounded rectangle */
	cr = gdk_cairo_create (widget->window);
	cairo_translate (cr, widget->allocation.x, widget->allocation.y);
	cairo_new_path (cr);
	cairo_move_to (cr, 12, 6);
	cairo_rel_line_to (cr, widget->allocation.width - 24, 0);
	cairo_rel_curve_to (cr, 6, 0, 6, 6, 6, 6);
	cairo_rel_line_to (cr, 0, widget->allocation.height - 24);
	cairo_rel_curve_to (cr, 0, 6, -6, 6, -6, 6);
	cairo_rel_line_to (cr, -(widget->allocation.width - 24), 0);
	cairo_rel_curve_to (cr, -6, 0, -6, -6, -6, -6);
	cairo_rel_line_to (cr, 0, -(widget->allocation.height - 24));
	cairo_rel_curve_to (cr, 0, -6, 6, -6, 6, -6);
	cairo_close_path (cr);
	cairo_set_source_rgba (cr, 1, 1, 1, 0.5);
	cairo_fill (cr);
	cairo_destroy (cr);
	
	return FALSE;
}

static void
bg_size_allocate_cb (GtkWidget *widget, GtkAllocation *allocation,
		     TodayData *data)
{
	static gint width = 0, height = 0;
	
	/* Re-scale wallpaper */
	if ((width != allocation->width) || (height != allocation->height)) {
		width = allocation->width;
		height = allocation->height;
		gconf_client_notify (gconf_client_get_default (),
			GCONF_POKY_INTERFACE_PREFIX GCONF_POKY_WALLPAPER);
	}
}

static gboolean
set_time_idle (TodayData *data)
{
	JanaTime *time;
	gchar *date_str;
	
	time = jana_ecal_utils_time_now (data->location);
	jana_gtk_clock_set_time (JANA_GTK_CLOCK (data->clock), time);
	date_str = jana_utils_strftime (time, _("%A, %d. %B %Y"));
	gtk_label_set_text (GTK_LABEL (data->date_label), date_str);
	g_free (date_str);
	
	/* Update query every half-hour */
	if (data->dates_view && ((jana_time_get_minutes (time) % 30) == 0)) {
		JanaTime *end = jana_time_duplicate (time);
		jana_time_set_day (end, jana_time_get_day (end) + 1);
		jana_time_set_isdate (end, TRUE);
		jana_store_view_set_range (data->dates_view, time, end);
		g_object_unref (end);
	}
	
#if GLIB_CHECK_VERSION(2,14,0)
	g_timeout_add_seconds (60 - jana_time_get_seconds (time),
		(GSourceFunc)set_time_idle, data);
#else
	g_timeout_add ((60 - jana_time_get_seconds (time)) * 1000,
		(GSourceFunc)set_time_idle, data);
#endif

	g_object_unref (time);
	
	return FALSE;
}

static void
clock_clicked_cb (JanaGtkClock *clock, GdkEventButton *event, TodayData *data)
{
	/*if (data->clock_item) launcher_start (data->window, data->clock_item,
		(gchar *[]){ "openmoko-worldclock", NULL }, TRUE, TRUE);*/
}

static GtkWidget *
today_create_home_page (TodayData *data)
{
	GtkWidget *main_vbox, *align;
	
	/* Add home page */
	main_vbox = gtk_vbox_new (FALSE, 0);
		
	/* Toolbar */
	data->home_toolbar = gtk_toolbar_new ();
	gtk_box_pack_start (GTK_BOX (main_vbox), data->home_toolbar, FALSE, TRUE, 0);

	data->dates_button = today_toolbutton_new ("dates");
	gtk_toolbar_insert (GTK_TOOLBAR (data->home_toolbar),
		data->dates_button, 0);
	gtk_toolbar_insert (GTK_TOOLBAR (data->home_toolbar),
		gtk_separator_tool_item_new (), 0);
	g_signal_connect (G_OBJECT (data->dates_button), "clicked",
		G_CALLBACK (today_dates_button_clicked_cb), data);
	gtk_widget_set_sensitive (GTK_WIDGET (data->dates_button), FALSE);

	data->messages_button = today_toolbutton_new ("openmoko-messages");
	gtk_toolbar_insert (GTK_TOOLBAR (data->home_toolbar),
		data->messages_button, 0);
	gtk_toolbar_insert (GTK_TOOLBAR (data->home_toolbar),
		gtk_separator_tool_item_new (), 0);
	g_signal_connect (G_OBJECT (data->messages_button), "clicked",
		G_CALLBACK (today_messages_button_clicked_cb), data);
	gtk_widget_set_sensitive (GTK_WIDGET (data->messages_button), FALSE);

	data->contacts_button = today_toolbutton_new ("contacts");
	gtk_toolbar_insert (GTK_TOOLBAR (data->home_toolbar),
		data->contacts_button, 0);
	gtk_toolbar_insert (GTK_TOOLBAR (data->home_toolbar),
		gtk_separator_tool_item_new (), 0);
	g_signal_connect (G_OBJECT (data->contacts_button), "clicked",
		G_CALLBACK (today_contacts_button_clicked_cb), data);
	gtk_widget_set_sensitive (GTK_WIDGET (data->contacts_button), FALSE);

	data->dial_button = today_toolbutton_new ("openmoko-dialer");
	gtk_toolbar_insert (GTK_TOOLBAR (data->home_toolbar),
		data->dial_button, 0);
	gtk_widget_show_all (data->home_toolbar);
	g_signal_connect (G_OBJECT (data->dial_button), "clicked",
		G_CALLBACK (today_dial_button_clicked_cb), data);
	gtk_widget_set_sensitive (GTK_WIDGET (data->dial_button), FALSE);

	/* Create event box with background */
	data->bg_ebox = gtk_event_box_new ();
	gtk_widget_set_app_paintable (data->bg_ebox, TRUE);
	g_signal_connect (data->bg_ebox, "expose-event",
		G_CALLBACK (bg_expose_cb), data);
	g_signal_connect (data->bg_ebox, "size-allocate",
		G_CALLBACK (bg_size_allocate_cb), data);
	gtk_box_pack_start (GTK_BOX (main_vbox), data->bg_ebox, TRUE, TRUE, 0);
	gtk_widget_show (data->bg_ebox);
	
	/* Get location and create clock widget */
	data->location = jana_ecal_utils_guess_location ();
	data->clock = jana_gtk_clock_new ();
	jana_gtk_clock_set_draw_shadow (JANA_GTK_CLOCK (data->clock), TRUE);
	gtk_widget_show (data->clock);
	g_signal_connect (data->clock, "clicked",
		G_CALLBACK (clock_clicked_cb), data);
	g_object_ref_sink (data->clock);

	/* Pack widgets */
	align = gtk_alignment_new (0.5, 0, 1, 0);
	data->message_box = today_pim_journal_box_new (data);
	gtk_container_add (GTK_CONTAINER (align), data->message_box);
	gtk_widget_set_app_paintable (align, TRUE);
	g_signal_connect (align, "expose-event",
		G_CALLBACK (bg_child_expose_cb), data);
	gtk_widget_show (data->message_box);
	gtk_widget_show (align);
	
	data->home_vbox = gtk_vbox_new (FALSE, 6);
	gtk_alignment_set_padding (GTK_ALIGNMENT (align), 6, 6, 6, 6);
	gtk_box_pack_end (GTK_BOX (data->home_vbox), align, FALSE, TRUE, 0);
	gtk_container_add (GTK_CONTAINER (data->bg_ebox), data->home_vbox);
	gtk_widget_show (data->home_vbox);
	
	/* Set the time on the clock */
	set_time_idle (data);
	
	return main_vbox;
}

static void
wallpaper_notify (GConfClient *client, guint cnxn_id,
		  GConfEntry *entry, TodayData *data)
{
	gint width, height, pwidth, pheight;
	GdkPixbuf *pixbuf, *pixbuf_scaled;
	GConfValue *value;
	const gchar *path = NULL;
	gfloat scale;

	if (!GTK_WIDGET_REALIZED (data->bg_ebox))
		gtk_widget_realize (data->bg_ebox);

	/* Return if the background is tiny, we'll get called again when it 
	 * resizes anyway.
	 */
	width = data->bg_ebox->allocation.width;
	height = data->bg_ebox->allocation.height;
	if ((width <= 0) || (height <= 0)) return;
	
	value = gconf_entry_get_value (entry);
	if (value) path = gconf_value_get_string (value);
	if (!path || (!(pixbuf = gdk_pixbuf_new_from_file (path, NULL)))) {
		if (data->wallpaper) {
			g_object_unref (data->wallpaper);
			data->wallpaper = NULL;
			gtk_widget_queue_draw (data->bg_ebox);
		}
		return;
	}
	
	/* Create background pixmap */
	if (data->wallpaper) g_object_unref (data->wallpaper);
	data->wallpaper = gdk_pixmap_new (data->bg_ebox->window,
		width, height, -1);
	
	/* Scale and draw pixbuf */
	pwidth = gdk_pixbuf_get_width (pixbuf);
	pheight = gdk_pixbuf_get_height (pixbuf);
	if (((gfloat)pwidth / (gfloat)pheight) >
	    ((gfloat)width / (gfloat)height))
		scale = (gfloat)height/(gfloat)pheight;
	else
		scale = (gfloat)width/(gfloat)pwidth;
	pwidth *= scale;
	pheight *= scale;
	pixbuf_scaled = gdk_pixbuf_scale_simple (pixbuf, pwidth, pheight,
		GDK_INTERP_BILINEAR);
	if (pixbuf_scaled) {
		gdk_draw_pixbuf (data->wallpaper, NULL, pixbuf_scaled,
			0, 0, 0, 0, -1, -1, GDK_RGB_DITHER_MAX, 0, 0);
		g_object_unref (pixbuf_scaled);
	}
	g_object_unref (pixbuf);
	
	/* Redraw */
	gtk_widget_queue_draw (data->bg_ebox);
}

static void
digital_clock_notify (GConfClient *client, guint cnxn_id,
		      GConfEntry *entry, TodayData *data)
{
	GConfValue *value;

	value = gconf_entry_get_value (entry);
	if (value && (!gconf_value_get_bool (value))) {
		gtk_aspect_frame_set (GTK_ASPECT_FRAME (data->date_aspect),
			1.0, 0.5, 1.0, FALSE);
		jana_gtk_clock_set_digital (JANA_GTK_CLOCK (data->clock),
			FALSE);
	} else {
		gtk_aspect_frame_set (GTK_ASPECT_FRAME (data->date_aspect),
			1.0, 0.5, 2.0, FALSE);
		jana_gtk_clock_set_digital (JANA_GTK_CLOCK (data->clock),
			TRUE);
	}
}

static void
small_clock_notify (GConfClient *client, guint cnxn_id,
		    GConfEntry *entry, TodayData *data)
{
	GConfValue *value;
	GtkWidget *parent;

	if ((parent = gtk_widget_get_parent (data->clock)))
		gtk_container_remove (GTK_CONTAINER (parent), data->clock);
	
	value = gconf_entry_get_value (entry);
	if (value && (gconf_value_get_bool (value))) {
		gtk_container_add (GTK_CONTAINER (
			data->date_aspect), data->clock);
	} else {
		gtk_box_pack_start (GTK_BOX (data->home_vbox),
			data->clock, TRUE, TRUE, 0);
	}
}

static void
location_notify (GConfClient *client, guint cnxn_id,
		 GConfEntry *entry, TodayData *data)
{
	GConfValue *value;

	value = gconf_entry_get_value (entry);
	if (value) {
		const gchar *location = gconf_value_get_string (value);
		if (location) {
			g_free (data->location);
			data->location = g_strdup (location);
		}
	}
}

static void
reduced_notify (GConfClient *client, guint cnxn_id,
		GConfEntry *entry, TodayData *data)
{
	GConfValue *value;
	gboolean hide;
	
	value = gconf_entry_get_value (entry);
	hide = (value && gconf_value_get_bool (value)) ? TRUE : FALSE;
	g_object_set (G_OBJECT (data->clock), "visible", !hide, NULL);
	g_object_set (G_OBJECT (data->search_bar), "visible", !hide, NULL);
	g_object_set (G_OBJECT (data->date_button), "visible", !hide, NULL);
	g_object_set (G_OBJECT (data->home_toolbar), "visible", !hide, NULL);
	
	/* Unset application filter */
	if (hide) {
		gint rows;
		GtkTreeModel *model;
		GtkComboBox *combo = moko_search_bar_get_combo_box (
			MOKO_SEARCH_BAR (data->search_bar));
		GtkEntry *entry = moko_search_bar_get_entry (
			MOKO_SEARCH_BAR (data->search_bar));
		
		gtk_entry_set_text (entry, "");
		
		/* FIXME: Assuming last row is 'All' category... */
		model = gtk_combo_box_get_model (combo);
		rows = gtk_tree_model_iter_n_children (model, NULL);
		gtk_combo_box_set_active (combo, rows - 1);
	}
}

static gboolean active = TRUE;

static void
set_window_title (TodayData *data)
{
	gtk_window_set_title (GTK_WINDOW (data->window),
		(data->network_name && data->network_name[0]) ?
			data->network_name : "Registering...");
}

static void
is_active_notify (GObject *window, GParamSpec *arg1, TodayData *data)
{
	g_object_get (window, "is-active", &active, NULL);
	if (!active)
       	  gtk_window_set_title (GTK_WINDOW (data->window), _("Home"));
	else
		set_window_title (data);
}

static void
provider_changed_cb (DBusGProxy *proxy, const gchar *name, TodayData *data)
{
	g_free (data->network_name);
	data->network_name = g_strdup (name);
	
	if (active) set_window_title (data);
}

#ifndef STANDALONE
static GtkWidget *window;

static void
workarea_changed (int x, int y, int w, int h)
{
	gtk_window_resize (GTK_WINDOW (window), w, h);
	gtk_window_move (GTK_WINDOW (window), x, y);
}
#endif

int
main (int argc, char **argv)
{
	TodayData data;
	DBusGConnection *connection;
	GOptionContext *context;
	GtkWidget *widget;
#ifndef STANDALONE
	gint x, y, w, h;
#endif
	GError *error = NULL;
	
	static GOptionEntry entries[] = {
		{ NULL }
	};
	
	data.wallpaper = NULL;
	data.network_name = NULL;

	/* Initialise */
	bindtextdomain (GETTEXT_PACKAGE, TODAY_LOCALE_DIR);;
	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
	textdomain (GETTEXT_PACKAGE);

	context = g_option_context_new (_(" - Today's information summary"));
	g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
	g_option_context_add_group (context, gtk_get_option_group (TRUE));
	g_option_context_parse (context, &argc, &argv, NULL);

	/* init openmoko stock items */
	moko_stock_register ();

	/* Get phone-kit Network dbus proxy */
	connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
	if (!connection) {
		g_warning ("Failed to get dbus connection: %s", error->message);
		g_error_free (error);
		data.network_proxy = NULL;
	} else {
		data.network_proxy = dbus_g_proxy_new_for_name (connection,
			"org.openmoko.PhoneKit",
			"/org/openmoko/PhoneKit/Network",
			"org.openmoko.PhoneKit.Network");
		dbus_g_proxy_add_signal (data.network_proxy,
			"ProviderChanged", G_TYPE_STRING, G_TYPE_INVALID);
		dbus_g_proxy_connect_signal (data.network_proxy,
			"ProviderChanged", G_CALLBACK (provider_changed_cb),
			&data, NULL);
	}

	/* Create widgets */
	data.window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
	gtk_window_set_title (GTK_WINDOW (data.window), _("Home"));
	
	/* Notebook */
	data.notebook = gtk_notebook_new ();
	gtk_notebook_set_tab_pos (GTK_NOTEBOOK (data.notebook), GTK_POS_BOTTOM);
	gtk_container_add (GTK_CONTAINER (data.window), data.notebook);
	gtk_widget_show (data.notebook);

	/* Add home page */
	widget = today_create_home_page (&data);
	today_notebook_add_page_with_icon (data.notebook, widget,
		GTK_STOCK_HOME, 6);
	gtk_widget_show (widget);

	/* Add new launcher page */
	widget = today_launcher_page_create (&data);
	today_notebook_add_page_with_icon (data.notebook, widget,
		GTK_STOCK_ADD, 6);
	gtk_widget_show (widget);

	/* Add running tasks page */
	widget = today_task_manager_page_create (&data);
	today_notebook_add_page_with_icon (data.notebook, widget,
		GTK_STOCK_EXECUTE, 6);
	gtk_widget_show (widget);
	
	/* Connect up signals */
	g_signal_connect (G_OBJECT (data.window), "delete-event",
		G_CALLBACK (gtk_main_quit), NULL);
	
#if 0
	/* This block here to ease testing, please don't remove! */
	/* Force theme settings */
	g_object_set (gtk_settings_get_default (),
		"gtk-theme-name", "openmoko-standard-2",
		"gtk-icon-theme-name", "openmoko-standard",
		"gtk-xft-dpi", 285 * 1024,
		"gtk-font-name", "Sans 6",
		NULL);
#endif

#ifndef STANDALONE
	x = 0; y = 0; w = 480; h = 640;
	gtk_window_set_type_hint (GTK_WINDOW (data.window),
		GDK_WINDOW_TYPE_HINT_DESKTOP);
	gtk_window_set_skip_taskbar_hint (GTK_WINDOW (data.window), TRUE);
	window = data.window;
	x_monitor_workarea (gtk_widget_get_screen (window), workarea_changed);
#else
	gtk_window_set_default_size (GTK_WINDOW (data.window), 480, 600);
#endif
	
	/* Show and start */
	g_signal_connect (data.window, "notify::is-active",
		G_CALLBACK (is_active_notify), &data);
	gtk_widget_show (data.window);

	/* Listen to settings */
	gconf_client_add_dir (gconf_client_get_default (),
		JANA_ECAL_LOCATION_KEY_DIR, GCONF_CLIENT_PRELOAD_NONE, NULL);
	gconf_client_notify_add (gconf_client_get_default (),
		JANA_ECAL_LOCATION_KEY,
		(GConfClientNotifyFunc)location_notify,
		&data, NULL, NULL);
	
	gconf_client_add_dir (gconf_client_get_default (),
		GCONF_POKY_INTERFACE_PREFIX, GCONF_CLIENT_PRELOAD_NONE, NULL);
	gconf_client_notify_add (gconf_client_get_default (),
		GCONF_POKY_INTERFACE_PREFIX GCONF_POKY_WALLPAPER,
		(GConfClientNotifyFunc)wallpaper_notify,
		&data, NULL, NULL);
	gconf_client_notify_add (gconf_client_get_default (),
		GCONF_POKY_INTERFACE_PREFIX GCONF_POKY_DIGITAL,
		(GConfClientNotifyFunc)digital_clock_notify,
		&data, NULL, NULL);
	gconf_client_notify_add (gconf_client_get_default (),
		GCONF_POKY_INTERFACE_PREFIX GCONF_POKY_SMALLCLOCK,
		(GConfClientNotifyFunc)small_clock_notify,
		&data, NULL, NULL);
	gconf_client_notify_add (gconf_client_get_default (),
		GCONF_POKY_INTERFACE_PREFIX GCONF_POKY_REDUCED,
		(GConfClientNotifyFunc)reduced_notify,
		&data, NULL, NULL);
	
	/* Fire off signals */
	gconf_client_notify (gconf_client_get_default (),
		GCONF_POKY_INTERFACE_PREFIX GCONF_POKY_WALLPAPER);
	gconf_client_notify (gconf_client_get_default (),
		GCONF_POKY_INTERFACE_PREFIX GCONF_POKY_DIGITAL);
	gconf_client_notify (gconf_client_get_default (),
		GCONF_POKY_INTERFACE_PREFIX GCONF_POKY_SMALLCLOCK);
	gconf_client_notify (gconf_client_get_default (),
		GCONF_POKY_INTERFACE_PREFIX GCONF_POKY_REDUCED);

	gtk_main ();

	return 0;
}
