/* Notification plugin for Claws Mail
 * Copyright (C) 2005-2008 Holger Berndt
 *
 * 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 "pluginconfig.h"

#ifdef NOTIFICATION_BANNER

#include <gtk/gtk.h>

#include "gtk/gtkutils.h"

#include "prefs_common.h"
#include "mainwindow.h"
#include "menu.h"
#include "procmsg.h"
#include "messageview.h"
#include "compose.h"
#include "gettext.h"
#include "menu.h"

#include "notification_core.h"
#include "notification_prefs.h"
#include "notification_banner.h"

typedef struct {
  GtkWidget *table;
} NotificationBannerEntry;

typedef struct {
  GtkWidget *window;
  GtkWidget *scrolled_win;
	GtkWidget *viewport;

  NotificationBannerEntry *entries;
  guint timeout_id;
  gboolean scrolling;
} NotificationBanner;

typedef struct {
  gint banner_width;
  GtkAdjustment *adj;
} ScrollingData;


static void       notification_banner_create(GSList*);
static gboolean   scroller(gpointer data);
static GtkWidget* create_entrybox(GSList*);
static gboolean   notification_banner_configure(GtkWidget*, GdkEventConfigure*,
						gpointer);
static gboolean notification_banner_swap_colors(GtkWidget*,GdkEventCrossing*,gpointer);
static gboolean notification_banner_button_press(GtkWidget*,GdkEventButton*,gpointer);
static void notification_banner_show_popup(GtkWidget*,GdkEventButton*);
static void notification_banner_popup_done(GtkMenuShell*,gpointer);

static void banner_menu_reply_cb(GtkAction *,gpointer);


static NotificationBanner banner;
static ScrollingData      sdata;

static GtkWidget *banner_popup;
static GtkUIManager *banner_ui_manager;
static GtkActionGroup *banner_action_group;

static gboolean banner_popup_open = FALSE;

static MsgInfo *current_msginfo = NULL;

/* Corresponding mutexes */
G_LOCK_DEFINE_STATIC(banner);
G_LOCK_DEFINE_STATIC(sdata);

static GtkActionEntry banner_popup_entries[] = 
{
	{"BannerPopup",		NULL, "BannerPopup" },
	{"BannerPopup/Reply",	NULL, N_("_Reply"), NULL, NULL, G_CALLBACK(banner_menu_reply_cb) },
};


void notification_banner_show(GSList *msg_list)
{
  G_LOCK(banner);
  if((notify_config.banner_show != NOTIFY_BANNER_SHOW_NEVER) &&
     (g_slist_length(msg_list) ||
      (notify_config.banner_show == NOTIFY_BANNER_SHOW_ALWAYS)))
    notification_banner_create(msg_list);
  else 
    notification_banner_destroy();
  G_UNLOCK(banner);
}

void notification_banner_destroy(void)
{
  if(banner.window) {
    if(banner.entries) {
      g_free(banner.entries);
      banner.entries = NULL;
    }
    gtk_widget_destroy(banner.window);
    banner.window = NULL;
    G_LOCK(sdata);
    sdata.adj = NULL;
    sdata.banner_width = 0;
    G_UNLOCK(sdata);
    if(banner.timeout_id) {
      g_source_remove(banner.timeout_id);
      banner.timeout_id = 0;
    }
  }
}

static void notification_banner_create(GSList *msg_list)
{
  GtkRequisition requisition, requisition_after;
	GtkWidget *viewport;
	GtkWidget *hbox;
	GtkWidget *entrybox;
	GdkColor bg;
	gint banner_width;

  /* Window */
  if(!banner.window) {

    banner.window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "notification_banner");
    gtk_window_set_decorated(GTK_WINDOW(banner.window), FALSE);
		if(notify_config.banner_width > 0)
			gtk_widget_set_size_request(banner.window, notify_config.banner_width, -1);
		else
			gtk_widget_set_size_request(banner.window, gdk_screen_width(), -1);
    gtk_window_set_keep_above(GTK_WINDOW(banner.window), TRUE);
    gtk_window_set_accept_focus(GTK_WINDOW(banner.window), FALSE);
    gtk_window_set_skip_taskbar_hint(GTK_WINDOW(banner.window), TRUE);
    gtk_window_move(GTK_WINDOW(banner.window),
										notify_config.banner_root_x, notify_config.banner_root_y);
    g_signal_connect(banner.window, "configure-event",
										 G_CALLBACK(notification_banner_configure), NULL);
  }
  else {
    if(banner.entries) {
      g_free(banner.entries);
      banner.entries = NULL;
    }
    gtk_widget_destroy(banner.scrolled_win);
  }
  if(notify_config.banner_sticky)
    gtk_window_stick(GTK_WINDOW(banner.window));
  else
    gtk_window_unstick(GTK_WINDOW(banner.window));

  /* Scrolled window */
  banner.scrolled_win = gtk_scrolled_window_new(NULL, NULL);
  gtk_container_add(GTK_CONTAINER(banner.window), banner.scrolled_win);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(banner.scrolled_win),
																 GTK_POLICY_NEVER, GTK_POLICY_NEVER);

	/* Viewport */
	viewport = gtk_viewport_new(NULL,NULL);
	banner.viewport = viewport;
	gtk_container_add(GTK_CONTAINER(banner.scrolled_win),viewport);
	if(notify_config.banner_enable_colors) {
		gtkut_convert_int_to_gdk_color(notify_config.banner_color_bg,&bg);
		gtk_widget_modify_bg(viewport,GTK_STATE_NORMAL,&bg);
	}

  /* Hbox */
  hbox = gtk_hbox_new(FALSE, 5);
	gtk_container_add(GTK_CONTAINER(viewport),hbox);

  /* Entrybox */
  entrybox = create_entrybox(msg_list);
  gtk_box_pack_start(GTK_BOX(hbox), entrybox, FALSE, FALSE, 0);

  gtk_widget_show_all(banner.window);

  /* Scrolling */
  gtk_widget_size_request(hbox, &requisition);
  if(notify_config.banner_width > 0)
		banner_width = notify_config.banner_width;
	else
		banner_width = gdk_screen_width();
  if(requisition.width > banner_width) {
    /* Line is too big for screen! */
    /* Double the entrybox into hbox */
    GtkWidget *separator, *second_entrybox;

    separator = gtk_vseparator_new();
    gtk_box_pack_start(GTK_BOX(hbox), separator,
		       FALSE, FALSE, 0);
    second_entrybox = create_entrybox(msg_list);
    gtk_box_pack_start(GTK_BOX(hbox), second_entrybox, FALSE, FALSE, 0);

    gtk_widget_show_all(banner.window);
    gtk_widget_size_request(hbox, &requisition_after);

    G_LOCK(sdata);
    sdata.banner_width = requisition_after.width - requisition.width;
    sdata.adj =
      gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW
					  (banner.scrolled_win));
    G_UNLOCK(sdata);
    
    banner.scrolling = TRUE;
    if(banner.timeout_id) {
      g_source_remove(banner.timeout_id);
      banner.timeout_id = 0;
    }
    banner.timeout_id = 
      g_timeout_add(notify_config.banner_speed, scroller, NULL);
  }
  else {
    banner.scrolling = FALSE;
    if(banner.timeout_id) {
      g_source_remove(banner.timeout_id);
      banner.timeout_id = 0;
    }
    G_LOCK(sdata);
    sdata.banner_width = 0;
    sdata.adj = NULL;
    G_UNLOCK(sdata);
  }

	/* menu */
  banner_ui_manager = gtk_ui_manager_new();
  banner_action_group = cm_menu_create_action_group_full(banner_ui_manager,"BannerPopup", banner_popup_entries,
			G_N_ELEMENTS(banner_popup_entries), (gpointer)NULL);
  MENUITEM_ADDUI_MANAGER(banner_ui_manager, "/", "Menus", "Menus", GTK_UI_MANAGER_MENUBAR)
  MENUITEM_ADDUI_MANAGER(banner_ui_manager, "/Menus", "BannerPopup", "BannerPopup", GTK_UI_MANAGER_MENU)
  MENUITEM_ADDUI_MANAGER(banner_ui_manager, "/Menus/BannerPopup", "Reply", "BannerPopup/Reply", GTK_UI_MANAGER_MENUITEM)

  banner_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
				gtk_ui_manager_get_widget(banner_ui_manager, "/Menus/BannerPopup")) );
	g_signal_connect(banner_popup,"selection-done",
									 G_CALLBACK(notification_banner_popup_done), NULL);
}

static gboolean notification_banner_configure(GtkWidget *widget,
					      GdkEventConfigure *event,
					      gpointer data)
{
  gtk_window_get_position(GTK_WINDOW(gtk_widget_get_toplevel(widget)),
			  &(notify_config.banner_root_x),
			  &(notify_config.banner_root_y));
  return TRUE;
}

static gboolean scroller(gpointer data)
{
	// don't scroll during popup open
	if(banner_popup_open)
		return banner.scrolling;

	while(gtk_events_pending())
		gtk_main_iteration();
  G_LOCK(sdata);
  if(sdata.adj && GTK_IS_ADJUSTMENT(sdata.adj)) {
    if(sdata.adj->value != sdata.banner_width)
      gtk_adjustment_set_value(sdata.adj, sdata.adj->value + 1);
    else
      gtk_adjustment_set_value(sdata.adj, 0);
		gtk_adjustment_value_changed(sdata.adj);
  }
  G_UNLOCK(sdata);
	while(gtk_events_pending())
		gtk_main_iteration();
  return banner.scrolling;
}

static GtkWidget* create_entrybox(GSList *msg_list)
{
  GtkWidget *entrybox;
  GdkColor fg;
	GdkColor bg;
  gint list_length;

  list_length = g_slist_length(msg_list);

  if(notify_config.banner_enable_colors) {
    gtkut_convert_int_to_gdk_color(notify_config.banner_color_bg,&bg);
		gtkut_convert_int_to_gdk_color(notify_config.banner_color_fg,&fg);
  }

  if(banner.entries) {
    g_free(banner.entries);
    banner.entries = NULL;
  }

  entrybox = gtk_hbox_new(FALSE, 5);
  if(list_length) {
    GSList *walk;
    gint ii = 0;
    banner.entries = g_new(NotificationBannerEntry, list_length);
    for(walk = msg_list; walk != NULL; walk = g_slist_next(walk)) {
      GtkWidget *label1;
      GtkWidget *label2;
      GtkWidget *label3;
      GtkWidget *label4;
      GtkWidget *label5;
      GtkWidget *label6;
			GtkWidget *ebox;
      CollectedMsg *cmsg = walk->data;
      
      if(ii > 0) {
				GtkWidget *separator;
				separator = gtk_vseparator_new();
				gtk_box_pack_start(GTK_BOX(entrybox), separator, FALSE, FALSE, 0);
      }

			ebox = gtk_event_box_new();
			gtk_box_pack_start(GTK_BOX(entrybox), ebox, FALSE, FALSE, 0);
			gtk_widget_set_events(ebox,
														GDK_POINTER_MOTION_MASK |
														GDK_BUTTON_PRESS_MASK);

			if(notify_config.banner_enable_colors)
				gtk_widget_modify_bg(ebox,GTK_STATE_NORMAL,&bg);

      banner.entries[ii].table = gtk_table_new(3, 2, FALSE);
			gtk_container_add(GTK_CONTAINER(ebox),banner.entries[ii].table);
			g_signal_connect(ebox, "enter-notify-event",
											 G_CALLBACK(notification_banner_swap_colors),
											 banner.entries[ii].table);
			g_signal_connect(ebox, "leave-notify-event",
											 G_CALLBACK(notification_banner_swap_colors),
											 banner.entries[ii].table);
			g_signal_connect(ebox, "button-press-event",
											 G_CALLBACK(notification_banner_button_press),
											 cmsg);

      label1 = gtk_label_new(prefs_common_translated_header_name("From:"));
      gtk_misc_set_alignment(GTK_MISC(label1), 0, 0.5);
      gtk_table_attach_defaults(GTK_TABLE(banner.entries[ii].table), 
				label1, 0, 1, 0, 1);
      label2 = gtk_label_new(prefs_common_translated_header_name("Subject:"));
      gtk_misc_set_alignment(GTK_MISC(label2), 0, 0.5);
      gtk_table_attach_defaults(GTK_TABLE(banner.entries[ii].table),
				label2, 0, 1, 1, 2);
      label3 = gtk_label_new(_("Folder:"));
      gtk_misc_set_alignment(GTK_MISC(label3), 0, 0.5);
      gtk_table_attach_defaults(GTK_TABLE(banner.entries[ii].table),
				label3, 0, 1, 2, 3);
      
      label4 = gtk_label_new(cmsg->from);
      gtk_misc_set_alignment(GTK_MISC(label4), 0, 0.5);
      gtk_table_attach_defaults(GTK_TABLE(banner.entries[ii].table),
				label4, 1, 2, 0, 1);
      label5 = gtk_label_new(cmsg->subject);
      gtk_misc_set_alignment(GTK_MISC(label5), 0, 0.5);
      gtk_table_attach_defaults(GTK_TABLE(banner.entries[ii].table),
				label5, 1, 2, 1, 2);
      label6 = gtk_label_new(cmsg->folderitem_name);
      gtk_misc_set_alignment(GTK_MISC(label6), 0, 0.5);
      gtk_table_attach_defaults(GTK_TABLE(banner.entries[ii].table),
				label6, 1, 2, 2, 3);
      gtk_table_set_col_spacings(GTK_TABLE(banner.entries[ii].table), 5);
			ii++;
      /* Color */
      if(notify_config.banner_enable_colors) {
				gtk_widget_modify_fg(label1,GTK_STATE_NORMAL,&fg);
				gtk_widget_modify_fg(label2,GTK_STATE_NORMAL,&fg);
				gtk_widget_modify_fg(label3,GTK_STATE_NORMAL,&fg);
				gtk_widget_modify_fg(label4,GTK_STATE_NORMAL,&fg);
				gtk_widget_modify_fg(label5,GTK_STATE_NORMAL,&fg);
				gtk_widget_modify_fg(label6,GTK_STATE_NORMAL,&fg);
      }
    }
  }
  else {
    /* We have an empty list -- create an empty dummy element */
    GtkWidget *label;

    banner.entries = g_new(NotificationBannerEntry, 1);
    banner.entries[0].table = gtk_table_new(3, 1, FALSE);
    label = gtk_label_new("");
    gtk_table_attach_defaults(GTK_TABLE(banner.entries[0].table), 
			      label, 0, 1, 0, 1);
    label = gtk_label_new("");
    gtk_table_attach_defaults(GTK_TABLE(banner.entries[0].table), 
			      label, 0, 1, 1, 2);
    label = gtk_label_new("");
    gtk_table_attach_defaults(GTK_TABLE(banner.entries[0].table), 
			      label, 0, 1, 2, 3);
    gtk_box_pack_start(GTK_BOX(entrybox), banner.entries[0].table,
		       FALSE, FALSE, 0);
  }
  return entrybox;
}

static gboolean notification_banner_swap_colors(GtkWidget *widget,
																								GdkEventCrossing *event,
																								gpointer data)
{
	GList *children;
	GList *walk;
	GdkColor *old_bg;
	
	children = gtk_container_get_children(GTK_CONTAINER(data));

	old_bg = gdk_color_copy(&(gtk_widget_get_style(widget)->bg[GTK_STATE_NORMAL]));
	if(children)
		gtk_widget_modify_bg(widget,GTK_STATE_NORMAL,
												 &(gtk_widget_get_style(GTK_WIDGET(children->data))->fg[GTK_STATE_NORMAL]));
	
	for(walk = children; walk; walk = walk->next)
		gtk_widget_modify_fg(GTK_WIDGET(walk->data),GTK_STATE_NORMAL,old_bg);
	
	g_list_free(children);
	gdk_color_free(old_bg);
	return FALSE;
}

static gboolean notification_banner_button_press(GtkWidget *widget,
																								 GdkEventButton *button,
																								 gpointer data)
{
	gboolean done;
	done = FALSE;
	if(button->type == GDK_BUTTON_PRESS) {
		CollectedMsg *cmsg = (CollectedMsg*) data;
    if(button->button == 1) {
			/* jump to that message */
			if(cmsg->msginfo) {
				gchar *path;
				path = procmsg_get_message_file_path(cmsg->msginfo);
				mainwindow_jump_to(path, TRUE);
				g_free(path);
			}
			done = TRUE;
		}
		else if(button->button == 2) {
      gtk_window_begin_move_drag(GTK_WINDOW(gtk_widget_get_toplevel(widget)), 
																 button->button, button->x_root, button->y_root,
																 button->time);
		}
		else if(button->button == 3) {
			current_msginfo = cmsg->msginfo;
			notification_banner_show_popup(widget, button);
			banner_popup_open = TRUE;
			done = TRUE;
		}
	}
	return done;
}

static void notification_banner_show_popup(GtkWidget *widget,
																					 GdkEventButton *event)
{
  int button, event_time;

  if(event) {
		button = event->button;
		event_time = event->time;
	}
  else {
		button = 0;
		event_time = gtk_get_current_event_time();
	}

  gtk_menu_popup(GTK_MENU(banner_popup), NULL, NULL, NULL, NULL,
								 button, event_time);
}

static void notification_banner_popup_done(GtkMenuShell *menushell,
																					 gpointer      user_data)
{
	current_msginfo = NULL;
	banner_popup_open = FALSE;
}

static void banner_menu_reply_cb(GtkAction *action, gpointer data)
{
	MainWindow *mainwin;
	MessageView *messageview;
	GSList *msginfo_list = NULL;

	if(!(mainwin = mainwindow_get_mainwindow()))
		return;

	if(!(messageview = (MessageView*)mainwin->messageview))
		return;

	g_return_if_fail(current_msginfo);

	msginfo_list = g_slist_prepend(msginfo_list, current_msginfo);
	compose_reply_from_messageview(messageview, msginfo_list,
				       prefs_common_get_prefs()->reply_with_quote ?
				       COMPOSE_REPLY_WITH_QUOTE : COMPOSE_REPLY_WITHOUT_QUOTE);
	g_slist_free(msginfo_list);
}

#endif /* NOTIFICATION_BANNER */
