/*
 * notify-osd.c - xchat plugin which provides "OSD" like functionality through
 *                libnotify
 *
 * Copyright (C) 2005-2007 David Trowbridge
 *
 * 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
 * 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */

#include <config.h>
#include <libnotify/notify.h>
#include <string.h>
#include <glib/gi18n.h>
#include "xchat-plugin.h"
#include "xg-plugin.h"

#define NOTIFY_OSD_NAME        _("On-screen display")
#define NOTIFY_OSD_VERSION     "0.2"
#define NOTIFY_OSD_DESCRIPTION _("Pops up notification of important messages when XChat-GNOME doesn't have the focus")

int  xchat_gnome_plugin_init (xchat_gnome_plugin *xg_plugin);
void xchat_plugin_get_info   (char **plugin_name, char **plugin_desc, char **plugin_version, void **reserved);
int  xchat_plugin_init       (xchat_plugin *plugin_handle, char **plugin_name, char **plugin_desc, char **plugin_version, char *arg);
int  xchat_plugin_deinit     (void);

enum
{
	STRIP_COLORS = 1 << 0,
	STRIP_ATTRS  = 1 << 1,
};

static xchat_plugin       *ph;
static xchat_gnome_plugin *xgph;
static GtkWidget          *main_window;
static gboolean            focused = TRUE;
static GdkPixbuf          *notify_icon;
static GSList             *notifications = NULL;

static gboolean
notify_str_equal (gconstpointer a, gconstpointer b)
{
        return !( g_str_equal (a,b) == TRUE) ;
}

static gboolean
notify_manager_has_capability (const gchar *cap)
{                                                     
	gboolean ret;
	GList *list = NULL;

	list  =  notify_get_server_caps ();
	ret = ( g_list_find_custom ( list, cap, notify_str_equal) != NULL );

	g_list_free_full ( list, g_free);

	return ret;
}

static void
hide_notifications (NotifyNotification *notify)
{
	GError *error = NULL;
	if (!notify_notification_close (notify, &error)) {
		g_warning (_("Error closing notification: %s\n"), error->message);
		g_error_free (error);
	}
}

static void
add_notify (char *summary, char *message)
{
	NotifyNotification *notify = NULL;
	GError *error = NULL;
	gchar *escaped;

	escaped = g_markup_escape_text (message, strlen(message));
	notify = notify_notification_new (summary, escaped, NULL);

	notify_notification_set_urgency (notify, NOTIFY_URGENCY_NORMAL);
	notify_notification_set_icon_from_pixbuf (notify, notify_icon);

	if (notify_manager_has_capability ("x-canonical-append"))
		notify_notification_set_hint_string(notify, "x-canonical-append", "");

	if (!notify_notification_show (notify, &error)) {
		g_warning (_("Failed to send notification: %s\n"), error->message);
		g_error_free (error);
		return;
	}

	notifications = g_slist_prepend (notifications, notify);

	g_free (escaped);
}

static gboolean
got_focus_cb (GtkWidget *wigdet, GdkEventFocus *event, gpointer data)
{
	g_slist_foreach (notifications, (GFunc) hide_notifications, NULL);
	g_slist_free (notifications);
	notifications = NULL;
	focused = TRUE;
	return FALSE;
}

static gboolean
lost_focus_cb (GtkWidget *wigdet, GdkEventFocus *event, gpointer data)
{
	focused = FALSE;
	return FALSE;
}

static int
new_msg_cb (char *word[], gpointer data)
{
	const char *channel;
	gchar *stripped, *message, *summary;

	if (focused)
		return XCHAT_EAT_NONE;

	channel = xchat_get_info (ph, "channel");
	stripped = xchat_strip (ph, word[2], -1, STRIP_COLORS | STRIP_ATTRS);

	message = g_strdup_printf ("<%s> %s", word[1], stripped);

	if (channel[0] == '#')
		summary = g_strdup_printf (_("Message in %s"), channel);
	else
		summary = g_strdup_printf (_("Message from %s"), channel);

	add_notify (summary, message);

	xchat_free (ph, stripped);
	g_free (message);
	g_free (summary);
	return XCHAT_EAT_NONE;
}

static int
new_action_cb (char *word[], gpointer data)
{
	const char *channel;
	gchar *stripped, *message, *summary;

	if (focused)
		return XCHAT_EAT_NONE;

	channel = xchat_get_info (ph, "channel");
	stripped = xchat_strip (ph, word[2], -1, STRIP_COLORS | STRIP_ATTRS);

	message = g_strdup_printf ("* %s %s", word[1], stripped);
	if (channel[0] == '#')
		summary = g_strdup_printf (_("Message in %s"), channel);
	else
		summary = g_strdup_printf (_("Message from %s"), channel);

	add_notify (summary, message);

	xchat_free (ph, stripped);
	g_free (message);
	g_free (summary);
	return XCHAT_EAT_NONE;
}

static int
private_msg_cb (char *word[], gpointer data)
{
	gchar *message, *summary;

	if (focused)
		return XCHAT_EAT_NONE;

	message = xchat_strip (ph, word[2], -1, STRIP_COLORS | STRIP_ATTRS);
	summary = g_strdup_printf (_("Private Message from %s"), word[1]);

	add_notify (summary, message);

	xchat_free (ph, message);
	g_free (summary);
	return XCHAT_EAT_NONE;
}

int
xchat_gnome_plugin_init (xchat_gnome_plugin *xg_plugin)
{
	xgph = xg_plugin;

	/* Hook up focus callbacks */
	main_window = xg_get_main_window ();
	g_signal_connect (main_window, "focus-in-event",  G_CALLBACK (got_focus_cb),  NULL);
        g_signal_connect (main_window, "focus-out-event", G_CALLBACK (lost_focus_cb), NULL);

	return TRUE;
}

void
xchat_plugin_get_info (char **plugin_name, char **plugin_desc, char **plugin_version, void **reserved)
{
	*plugin_name    = NOTIFY_OSD_NAME;
	*plugin_desc    = NOTIFY_OSD_DESCRIPTION;
	*plugin_version = NOTIFY_OSD_VERSION;
}

int
xchat_plugin_init (xchat_plugin *plugin_handle, char **plugin_name, char **plugin_desc, char **plugin_version, char *arg)
{
	xchat_plugin_get_info (plugin_name, plugin_desc, plugin_version, NULL);

	ph = plugin_handle;

	if (notify_init ("XChat-GNOME OSD")) {
		/* FIXME: multi-head! */
		GtkIconTheme *theme = gtk_icon_theme_get_default ();
		notify_icon = gtk_icon_theme_load_icon (theme, "xchat-gnome", 48, 0, NULL);

		xchat_hook_print (ph, "Channel Msg Hilight",       XCHAT_PRI_NORM, new_msg_cb,     NULL);
		xchat_hook_print (ph, "Channel Action Hilight",    XCHAT_PRI_NORM, new_action_cb,  NULL);
		xchat_hook_print (ph, "Private Message",           XCHAT_PRI_NORM, private_msg_cb, NULL);
		xchat_hook_print (ph, "Private Message to Dialog", XCHAT_PRI_NORM, private_msg_cb, NULL);

		xchat_print (ph, _("OSD loaded\n"));

		return TRUE;
	} else {
		xchat_print (ph, _("OSD initialization failed\n"));
	}
	return FALSE;
}

int
xchat_plugin_deinit (void)
{
	got_focus_cb (main_window, NULL, NULL);

	notify_uninit ();

	if (notify_icon) {
		g_object_unref (notify_icon);
		notify_icon = NULL;
	}

	ph = NULL;

	return TRUE;
}
