/*
    Copyright (C) 2008-2010 Stefan Haller

    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 3 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <config.h>
#include <stdlib.h>
#include <gtk/gtk.h>
#include <libintl.h>
#include <errno.h>
#include <dbus/dbus-glib.h>
#include "../misc/general.h"
#include "../misc/license.h"
#include "../misc/translators.h"
#include "../misc/xml.h"
#include "../dbus/dbus-services.h"
#include "../dbus/dbus-client-bindings.h"

#define NORMAL_ICON DATADIR "/desktopnova/" "tray-icons/desktopnova-tray-normal.svg"
#define ERROR_ICON  DATADIR "/desktopnova/" "tray-icons/desktopnova-tray-error.svg"

#define _(message) dgettext(GETTEXT_PACKAGE_TRAY, message)

enum {
	ITEM_NEXT,
	ITEM_PREVIOUS,
	ITEM_PREFERENCES,
	ITEM_INFO,
	ITEM_EXIT
};

GtkStatusIcon * status;
GtkWidget * menu;
GtkWidget * mi_next;
GtkWidget * mi_previous;
GtkWidget * mi_preferences;
GtkWidget * mi_info;
GtkWidget * mi_exit;

gchar * error = NULL;

gboolean enable_mouse_wheel;
GTimer * mouse_wheel_timer;

DBusGConnection * dbus_connection;
DBusGProxy * dbus_proxy;

void update_status();

/* copied from desktopnova.c */
void eval_system_call(int result)
{
	if ((result == -1) || (result == 127))
	{
		gchar * error = 0;
		gchar * error2 = 0;
		if (result == -1)
		{
			error = _("system() returned error-code (-1)!");
			error2 = g_strdup_printf(_("Error: %s"), g_strerror(errno));
		}
		else
		{
			error = _("system() returned error-code (127)!");
			error2 = _("Error: /bin/sh could not be executed.");
		}
		GtkWidget * dialog = gtk_message_dialog_new(NULL,
				GTK_DIALOG_MODAL,
				GTK_MESSAGE_ERROR,
				GTK_BUTTONS_OK,
				"%s",
				error);
		gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
				"%s",
				error2);
		gtk_dialog_run(GTK_DIALOG(dialog));
		gtk_widget_destroy(dialog);	
	}
}

void init_dbus()
{
	GError * err = NULL;
	//g_type_init();

	#ifdef DEBUG
	g_debug("Initializing D-Bus");
	#endif

	dbus_connection = dbus_g_bus_get(DBUS_BUS_SESSION, &err);
	if (dbus_connection == NULL)
	{
		if (error != NULL)
		{
			g_free(error);
		}
		error = g_strdup_printf("Failed to open connection to bus: %s",
		                        err->message);
		g_error_free(err);
		g_warning("%s", error);

		return;
	}

	#ifdef DEBUG
	g_debug("Got Session-Bus");
	#endif

	dbus_proxy = dbus_g_proxy_new_for_name(dbus_connection,
	                                       DESKTOPNOVA_DBUS_SERVICE,
	                                       DESKTOPNOVA_DBUS_PATH,
	                                       DESKTOPNOVA_DBUS_INTERFACE);
	#ifdef DEBUG
	g_debug("Got DesktopNova-Interface: %s", dbus_proxy != NULL ? "yes" : "no");
	#endif
}

void eval_dbus_method_call(gboolean result, GError * err)
{
	if (result)
	{
		#ifdef DEBUG
		g_debug("D-Bus method call succeded.");
		#endif

		if (error != NULL)
		{
			g_free(error);
		}
		error = NULL;
		update_status();
	}
	else
	{
		gchar * tmp_error = NULL;
		if (error != NULL)
		{
			g_free(error);
		}

		if (g_error_matches(err,
		                    dbus_g_error_quark(),
		                    DBUS_GERROR_SERVICE_UNKNOWN))
		{
			tmp_error = _("Couldn't connect to haliner.desktopnova. It is " \
			              "very likely that the DesktopNova-daemon is not " \
			              "running.");
		}
		else
		{
			tmp_error = err->message;
		}

		error = g_strdup_printf(_("D-Bus: Failed to call method: %s"),
		                        tmp_error);
		g_error_free(err);
		g_warning("D-Bus method call failed.\n%s", error);

		update_status();
		return;
	}
}

void next_wallpaper()
{
	gboolean result = TRUE;
	GError * err = NULL;

	result = haliner_DesktopNova_next(dbus_proxy, &err);
	eval_dbus_method_call(result, err);
}

void previous_wallpaper()
{
	gboolean result = TRUE;
	GError * err = NULL;

	result = haliner_DesktopNova_previous(dbus_proxy, &err);
	eval_dbus_method_call(result, err);
}

void status_on_popup(GtkStatusIcon * icon, guint button,
                   guint activate_time, gpointer data)
{
	/* MEMLEAK */
	gtk_menu_popup(GTK_MENU(menu),
	               NULL,
	               NULL,
	               gtk_status_icon_position_menu,
	               status,
	               button,
	               activate_time);
}

gboolean status_scrolled(GtkStatusIcon  *status_icon,
                         GdkEventScroll *event,
                         gpointer user_data)
{
	if (enable_mouse_wheel)
	{
		if (g_timer_elapsed(mouse_wheel_timer, NULL) > 0.5)
		{
			g_timer_start(mouse_wheel_timer);

			switch (event->direction)
			{
				case GDK_SCROLL_UP:
					previous_wallpaper();
					break;
				case GDK_SCROLL_DOWN:
					next_wallpaper();
					break;
				default:
					break;
			}
		}
	}

	return FALSE;
}

void menu_item_activated(GtkMenuItem * item,
                         gpointer user_data)
{
	const gchar * authors[2] = {"Stefan Haller <haliner@googlemail.com>", NULL};

	switch ((glong) user_data)
	{
		case (ITEM_NEXT):
			next_wallpaper();
			break;
		case ITEM_PREVIOUS:
			previous_wallpaper();
			break;
		case ITEM_PREFERENCES:
			eval_system_call(system(BINDIR "/desktopnova &"));
			break;
		case ITEM_INFO:
			gtk_show_about_dialog(NULL,
					"program-name", "DesktopNova-Tray",
					"logo", gtk_status_icon_get_pixbuf(status),
					"title", _("About DesktopNova"),
					"version", VERSION,
					"copyright", "Stefan Haller 2008-2009",
					"authors", authors,
					"license", LICENSE,
					"translator-credits", TRANSLATORS,
					"website", "https://launchpad.net/desktopnova",
					"comments", _("A Tray Icon for DesktopNova"),
					NULL);
			break;
		case ITEM_EXIT:
			gtk_main_quit();
			break;
		default:
			g_warn_if_reached();
	}
}

void update_status()
{
	gchar * tooltip = NULL;

	if (error != NULL)
	{
		tooltip = error;
		gtk_status_icon_set_from_file(status, ERROR_ICON);
	}
	else
	{
		tooltip = _("DesktopNova");
		gtk_status_icon_set_from_file(status, NORMAL_ICON);
	}

	gtk_status_icon_set_tooltip(status, tooltip);
}

void create_and_show_tray()
{
	status = gtk_status_icon_new_from_file(NORMAL_ICON);
	gtk_status_icon_set_visible(status, TRUE);

	mouse_wheel_timer = g_timer_new();

	g_signal_connect(G_OBJECT(status), "popup-menu", G_CALLBACK(status_on_popup), NULL);
	g_signal_connect(G_OBJECT(status), "scroll-event", G_CALLBACK(status_scrolled), NULL);
}

void create_menu()
{
	menu = gtk_menu_new();

	mi_next        = gtk_image_menu_item_new_from_stock(GTK_STOCK_MEDIA_NEXT, NULL);
	mi_previous    = gtk_image_menu_item_new_from_stock(GTK_STOCK_MEDIA_PREVIOUS, NULL);
	mi_preferences = gtk_image_menu_item_new_from_stock(GTK_STOCK_PREFERENCES, NULL);
	mi_info        = gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT, NULL);
	mi_exit        = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL);

	gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi_next);
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi_previous);
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new());
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi_preferences);
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new());
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi_info);
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new());
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi_exit);

	g_signal_connect(G_OBJECT(mi_next),        "activate", G_CALLBACK(menu_item_activated), (gpointer)ITEM_NEXT);
	g_signal_connect(G_OBJECT(mi_previous),    "activate", G_CALLBACK(menu_item_activated), (gpointer)ITEM_PREVIOUS);
	g_signal_connect(G_OBJECT(mi_preferences), "activate", G_CALLBACK(menu_item_activated), (gpointer)ITEM_PREFERENCES);
	g_signal_connect(G_OBJECT(mi_info),        "activate", G_CALLBACK(menu_item_activated), (gpointer)ITEM_INFO);
	g_signal_connect(G_OBJECT(mi_exit),        "activate", G_CALLBACK(menu_item_activated), (gpointer)ITEM_EXIT);

	gtk_widget_show_all(menu);
}

void load()
{
	struct settings * set = load_settings();
	enable_mouse_wheel = set->mouse_wheel;
	free_settings(set);
}

int main (int argc, char *argv[])
{
	/* Initialize i18n support */
	gtk_set_locale();
	bindtextdomain(GETTEXT_PACKAGE_TRAY, LOCALEDIR);
	/* Initialize the widget set */

	gtk_init (&argc, &argv);

	/* Maybe the app dir doesn't exist, so we must create it. */
	//check_app_dir();

	load();

	create_and_show_tray();
	create_menu();

	init_dbus();

	update_status();

	/* Enter the main event loop, and wait for user interaction */
	gtk_main ();

	return 0;
}

#undef _
