/*
 *  Copyright (C) 2002  Ricardo Fernández Pascual
 *
 *  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.
 *
 *  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.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "bookmarks-smart-site-tb-widget.h"
#include "galeon-marshal.h"
#include "pixbuf-cache.h"
#include "gul-gobject-misc.h"
#include "gul-gui.h"
#include "bookmarks-widgets-private.h"
#include "bookmarks-single-editor.h"
#include "bookmarks-dnd.h"
#include "galeon-dnd.h"
#include "prefs-strings.h"
#include "eel-gconf-extensions.h"

#include <gtk/gtktable.h>
#include <gtk/gtkbutton.h>
#include <gtk/gtkhbox.h>
#include <gtk/gtkimage.h>
#include <gtk/gtkcomboboxentry.h>
#include <gdk/gdkkeysyms.h>
#include <gtk/gtkmain.h>
#include <gtk/gtkmenuitem.h>
#include <gtk/gtkentry.h>
#include <gtk/gtkeditable.h>

#include <glib/gi18n.h>

/**
 * Private data
 */
struct _GbSmartSiteTbWidgetPrivate {
	GtkWidget *mainwid;
	GtkWidget *main_button;
	GtkWidget *smart_box;
	gint num_entries;
	GtkWidget **entries;
	GtkWidget **combos;
	gint *entries_sizes;
	GtkWidget *fold_button;
	GtkWidget *unfold_button;
	GtkWidget *popup_menu;     
};

static GSList *all_instances = NULL;

const GtkTargetEntry text_drop_types[] =
{
	/* Drop targets copied from gtkentry.c */
	{ "UTF8_STRING",   0, 0 },
	{ "COMPOUND_TEXT", 0, 0 },
	{ "TEXT",	   0, 0 },
	{ "STRING",	   0, 0 },
	/* And the one that mozilla support */
	{ GALEON_DND_TEXT_TYPE, 0, GALEON_DND_TEXT },
};


/**
 * Private functions, only availble from this file
 */
static void		gb_smart_site_tb_widget_class_init	(GbSmartSiteTbWidgetClass *klass);
static void		gb_smart_site_tb_widget_init		(GbSmartSiteTbWidget *w);
static void		gb_smart_site_tb_widget_finalize_impl	(GObject *o);
static void		gb_smart_site_tb_widget_rebuild_impl	(GbTbWidget *w);
static void		gb_smart_site_tb_widget_build_smart_box (GbSmartSiteTbWidget *w);
static void		gb_smart_site_tb_widget_clicked_cb	(GtkButton *button, GbSmartSiteTbWidget *w);
static void		gb_smart_site_tb_widget_fold_cb		(GtkWidget *button, GbSmartSiteTbWidget *w);
static void		gb_smart_site_tb_widget_unfold_cb	(GtkWidget *button, GbSmartSiteTbWidget *w);
static void		gb_smart_site_tb_widget_visibility_changed_cb (GbSmartSite *b, 
								       GbSmartSiteTbWidget *w);
static gboolean		gb_smart_site_tb_widget_key_press_event_cb (GtkWidget *entry, GdkEventKey *event,
								    GbSmartSiteTbWidget *w);
static void		gb_smart_site_tb_widget_entry_width_changed_cb (GbSmartSite *b, gint index,
									guint width, 
									GbSmartSiteTbWidget *w);
static void		gb_smart_site_tb_widget_history_changed_cb (GbSmartSite *b,
								    GbSmartSiteTbWidget *w);
static void		gb_smart_site_tb_widget_conf_changed_cb	(GConfClient* client,
								 guint cnxn_id,
								 GConfEntry *entry,
								 gpointer user_data);
static gboolean         gb_smart_site_tb_widget_button_press_cb (GtkWidget *wid, 
                                                                 GdkEventButton *event, 
                                                                 GbSmartSiteTbWidget *w);
static void		gb_smart_site_tb_widget_drag_data_received_cb (GtkWidget *widget,
								       GdkDragContext *dc,
								       gint x, gint y,
								       GtkSelectionData *selection_data,
								       guint info,
								       guint t,
								       GbSmartSiteTbWidget *w);


static gpointer gb_tb_widget_class;

/**
 * GbSmartSiteTbWidget object
 */

MAKE_GET_TYPE (gb_smart_site_tb_widget, "GbSmartSiteTbWidget", GbSmartSiteTbWidget, 
	       gb_smart_site_tb_widget_class_init, 
	       gb_smart_site_tb_widget_init, GB_TYPE_TB_WIDGET);

static void
gb_smart_site_tb_widget_class_init (GbSmartSiteTbWidgetClass *klass)
{
	G_OBJECT_CLASS (klass)->finalize = gb_smart_site_tb_widget_finalize_impl;
	GB_TB_WIDGET_CLASS (klass)->rebuild = gb_smart_site_tb_widget_rebuild_impl;
	gb_tb_widget_class = g_type_class_peek_parent (klass);

	eel_gconf_notification_add 
		(CONF_BOOKMARKS_HISTORY, gb_smart_site_tb_widget_conf_changed_cb, NULL);
	eel_gconf_notification_add 
		(CONF_BOOKMARKS_SMARTBOOKMARK_HIDE_ARROWS, gb_smart_site_tb_widget_conf_changed_cb, NULL);
}

static void 
gb_smart_site_tb_widget_init (GbSmartSiteTbWidget *w)
{
	GbSmartSiteTbWidgetPrivate *p = g_new0 (GbSmartSiteTbWidgetPrivate, 1);
	w->priv = p;

	all_instances = g_slist_prepend (all_instances, w);
}

static void
gb_smart_site_tb_widget_finalize_impl (GObject *o)
{
	GbSmartSiteTbWidget *w = GB_SMART_SITE_TB_WIDGET (o);
	GbSmartSiteTbWidgetPrivate *p = w->priv;
	
	all_instances = g_slist_remove (all_instances, w);
	
	g_free (p->entries);
	g_free (p->combos);
	g_free (p->entries_sizes);

	g_free (p);
	
	G_OBJECT_CLASS (gb_tb_widget_class)->finalize (o);
}

GbSmartSiteTbWidget *
gb_smart_site_tb_widget_new (GbSmartSite *site)
{
	GbSmartSiteTbWidget *ret = g_object_new (GB_TYPE_SMART_SITE_TB_WIDGET,
						 "bookmark", site, NULL);
	return ret;
}

static GList *
gslist_to_glist (GSList *l)
{
	GList *ret = NULL;
	GSList *li;
	for (li = l; li; li = li->next)
	{
		ret = g_list_prepend (ret, li->data);
	}
	return g_list_reverse (ret);
}

static void
gb_smart_site_tb_widget_build_smart_box (GbSmartSiteTbWidget *w)
{
	static GdkPixbuf *smart_bm_fold_pixbuf_data = NULL;
	static GdkPixbuf *smart_bm_unfold_pixbuf_data = NULL;

	GbSmartSiteTbWidgetPrivate *p = w->priv;
	GbSmartSite *ss = GB_SMART_SITE (gb_tb_widget_get_bookmark (GB_TB_WIDGET (w)));
	int num_entries = gb_smart_site_get_num_fields (ss);
	gboolean hide_arrows = eel_gconf_get_boolean (CONF_BOOKMARKS_SMARTBOOKMARK_HIDE_ARROWS);
	int i;

	p->num_entries = num_entries;

	if (!smart_bm_unfold_pixbuf_data)
	{
		smart_bm_fold_pixbuf_data = gul_pixbuf_cache_get ("smart-bm-fold.png");
		smart_bm_unfold_pixbuf_data = gul_pixbuf_cache_get ("smart-bm-unfold.png");
	}

	if (p->smart_box)
	{
		gtk_container_remove (GTK_CONTAINER (p->mainwid), p->smart_box);
	}
	g_free (p->entries);
	g_free (p->combos);
	g_free (p->entries_sizes);

	p->smart_box = gtk_hbox_new (FALSE, 2);
	gtk_table_attach_defaults (GTK_TABLE (p->mainwid), p->smart_box, 1, 2, 0, 1);
	gtk_widget_show (p->smart_box);

	if (!eel_gconf_get_boolean (CONF_BOOKMARKS_SMARTBOOKMARK_HIDE_ARROWS))
	{
		GtkWidget *fim;
		GtkWidget *ufim;
		p->unfold_button = gtk_button_new ();
		p->fold_button = gtk_button_new ();
		gtk_box_pack_start (GTK_BOX (p->smart_box), p->unfold_button, TRUE, TRUE, 0);
		gtk_box_pack_start (GTK_BOX (p->smart_box), p->fold_button, TRUE, TRUE, 0);
		fim = gtk_image_new_from_pixbuf (smart_bm_fold_pixbuf_data);
		ufim = gtk_image_new_from_pixbuf (smart_bm_unfold_pixbuf_data);
		gtk_container_add (GTK_CONTAINER (p->unfold_button), ufim);
		gtk_container_add (GTK_CONTAINER (p->fold_button), fim);
		gtk_button_set_relief (GTK_BUTTON (p->fold_button), GTK_RELIEF_NONE);
		GTK_WIDGET_SET_FLAGS (GTK_BUTTON (p->fold_button), GTK_CAN_FOCUS);
		gtk_button_set_relief (GTK_BUTTON (p->unfold_button), GTK_RELIEF_NONE);
		GTK_WIDGET_SET_FLAGS (GTK_BUTTON (p->unfold_button), GTK_CAN_FOCUS);
	}

	p->entries = g_new0 (GtkWidget *, num_entries + 1);
	p->combos = g_new0 (GtkWidget *, num_entries + 1);
	p->entries_sizes = g_new0 (gint, num_entries + 1);
	for (i = 0; i < num_entries; i++)
	{
		if (eel_gconf_get_boolean (CONF_BOOKMARKS_HISTORY))
		{
			GSList *history = gb_smart_site_get_history (ss, i);
			GList *l, *history_l = gslist_to_glist (history);

			history_l = g_list_prepend (history_l, "");
			p->combos[i] = gtk_combo_box_entry_new_text();
			p->entries[i] = GTK_BIN(p->combos[i])->child;

			for (l = history_l; l; l = l->next)
			{
				gtk_combo_box_append_text(GTK_COMBO_BOX(p->combos[i]),
				                          (const gchar *)l->data);
			}

			g_slist_foreach (history, (GFunc) g_free, NULL);
			g_slist_free (history);
			g_list_free (history_l);
		}
		else
		{
			p->combos[i] = NULL;
			p->entries[i] = gtk_entry_new ();
		}

		p->entries_sizes[i] = gb_smart_site_get_entry_size (ss, i);
		if (!ss->folded || hide_arrows)
		{
			gtk_widget_show (p->combos[i] ? p->combos[i] : p->entries[i]);
		}
		gtk_box_pack_start (GTK_BOX (p->smart_box), 
				    p->combos[i] ? p->combos[i] : p->entries[i], TRUE, TRUE, 0);
		gtk_widget_set_size_request (p->entries[i], p->entries_sizes[i], -1);
		g_signal_connect (p->entries[i], "key-press-event", 
				  G_CALLBACK (gb_smart_site_tb_widget_key_press_event_cb), w);
	}
	p->entries[num_entries] = NULL;
	p->combos[num_entries] = NULL;

	if (!hide_arrows)
	{

		if (ss->folded)
		{
			gtk_widget_show_all (p->unfold_button);
		}
		else
		{
			gtk_widget_show_all (p->fold_button);
		}

		g_signal_connect (p->fold_button, "clicked", G_CALLBACK (gb_smart_site_tb_widget_fold_cb), w);
		g_signal_connect (p->unfold_button, "clicked", G_CALLBACK (gb_smart_site_tb_widget_unfold_cb), w);
	}

	g_signal_connect (ss, "visibility-changed", 
			  G_CALLBACK (gb_smart_site_tb_widget_visibility_changed_cb), w);
	g_signal_connect (ss, "history-changed", 
			  G_CALLBACK (gb_smart_site_tb_widget_history_changed_cb), w);
	g_signal_connect (ss, "entry-width-changed", 
			  G_CALLBACK (gb_smart_site_tb_widget_entry_width_changed_cb), w);
}

static void
gb_smart_site_tb_widget_rebuild_impl (GbTbWidget *w)
{

	GbSmartSite *site = GB_SMART_SITE (gb_tb_widget_get_bookmark (w));
	GbSmartSiteTbWidgetPrivate *p = GB_SMART_SITE_TB_WIDGET (w)->priv;

	if (!p->mainwid)
	{
		p->mainwid = gtk_table_new (2, 2, FALSE);
		gtk_widget_show (p->mainwid);
		gtk_box_pack_start (GTK_BOX (w), p->mainwid, FALSE, FALSE, 0);
	}

	if (p->main_button)
	{
		gtk_container_remove (GTK_CONTAINER (p->mainwid), p->main_button);
	}

	p->main_button = gtk_button_new ();
	g_signal_connect (p->main_button, "clicked", 
			  G_CALLBACK (gb_smart_site_tb_widget_clicked_cb), w);
	g_signal_connect (p->main_button, "button_press_event",
			  G_CALLBACK (gb_smart_site_tb_widget_button_press_cb), w);

	gtk_button_set_relief (GTK_BUTTON (p->main_button), GTK_RELIEF_NONE);
	GTK_WIDGET_SET_FLAGS (GTK_BUTTON (p->main_button), GTK_CAN_FOCUS);
	gtk_table_attach_defaults (GTK_TABLE (p->mainwid), p->main_button, 0, 1, 0, 1);
	gtk_widget_show (GTK_WIDGET (p->main_button));
	gb_widgets_fill_tb_item (GTK_CONTAINER (p->main_button), GB_BOOKMARK (site), GB_SITE (site)->url);

	gb_tb_widget_setup_context_menu (w, p->main_button);
	gb_bookmark_dnd_drag_source_set (GTK_BIN (p->main_button)->child, GB_BOOKMARK (site));

	if (gb_smart_site_get_num_fields (site) == 1 )
	{
		gtk_drag_dest_set (p->main_button, GTK_DEST_DEFAULT_ALL,
				   text_drop_types, G_N_ELEMENTS (text_drop_types),
				   GDK_ACTION_COPY);

		g_signal_connect (p->main_button, "drag_data_received",
				  G_CALLBACK (gb_smart_site_tb_widget_drag_data_received_cb), w);
	}

	if (!p->smart_box)
	{
		gb_smart_site_tb_widget_build_smart_box (GB_SMART_SITE_TB_WIDGET (w));
	}
}

static void
gb_smart_site_tb_widget_fold_cb (GtkWidget *button, GbSmartSiteTbWidget *w)
{
	GbSmartSite *ss = GB_SMART_SITE (gb_tb_widget_get_bookmark (GB_TB_WIDGET (w)));
	gb_smart_site_set_folded (ss, TRUE);
}

static void
gb_smart_site_tb_widget_unfold_cb (GtkWidget *button, GbSmartSiteTbWidget *w)
{
	GbSmartSite *ss = GB_SMART_SITE (gb_tb_widget_get_bookmark (GB_TB_WIDGET (w)));
	gb_smart_site_set_folded (ss, FALSE);
	/* bug 89338 */
	gtk_widget_grab_focus (w->priv->entries[0]);
}

static void
gb_smart_site_tb_widget_visibility_changed_cb (GbSmartSite *ss, GbSmartSiteTbWidget *w)
{
	GbSmartSiteTbWidgetPrivate *p = w->priv;
	gint i;
	gboolean hide_arrows = eel_gconf_get_boolean (CONF_BOOKMARKS_SMARTBOOKMARK_HIDE_ARROWS);

	g_return_if_fail (gb_tb_widget_get_bookmark (GB_TB_WIDGET (w)) == GB_BOOKMARK (ss));
	g_return_if_fail (p->entries && p->combos);

	for (i = 0; p->entries[i]; i++)
	{
		if (!ss->folded || hide_arrows)
		{
			gtk_widget_show (p->combos[i] ? p->combos[i] : p->entries[i]);
		}
		else
		{
			gtk_widget_hide (p->combos[i] ? p->combos[i] : p->entries[i]);
		}
	}
	
	if (!hide_arrows)
	{
		if (ss->folded)
		{
			gtk_widget_hide (p->fold_button);
			gtk_widget_show_all (p->unfold_button);
		}
		else
		{
			gtk_widget_hide (p->unfold_button);
			gtk_widget_show_all (p->fold_button);
		}
	} 
	else
	{
		gtk_widget_hide (p->fold_button);
		gtk_widget_hide (p->unfold_button);
	}
}

static void
gb_smart_site_tb_widget_do_the_smart_thing (GbSmartSiteTbWidget *w, 
					     GbBookmarkActivatedFlags flags)
{
	GbSmartSiteTbWidgetPrivate *p = w->priv;
	gchar *url;
	gchar **args;
	gint num_args;
	gint i;
	GbSmartSite *ss = GB_SMART_SITE (gb_tb_widget_get_bookmark (GB_TB_WIDGET (w)));

	num_args = gb_smart_site_get_num_fields (ss);
	args = g_new0 (char *, num_args + 1);
	for (i = 0; i < num_args; i++)
	{
		args[i] = gtk_editable_get_chars (GTK_EDITABLE (p->entries[i]), 0, -1);
		gb_smart_site_prepend_history (ss, i, args[i]);
                gtk_entry_set_text (GTK_ENTRY(p->entries[i]), "");
	}
	args[num_args] = NULL;

	url = gb_smart_site_subst_args (ss, args);
	gb_activated_activate (w, GB_BOOKMARK (ss), url, flags);
	g_free (url);

	for (i = 0; i < num_args; i++)
	{
		g_free (args[i]);
	}
	g_free (args);
}

static gboolean 
gb_smart_site_tb_widget_entries_empty (GbSmartSiteTbWidget *w)
{
	GbSmartSiteTbWidgetPrivate *p = w->priv;
	GbSmartSite *ss = GB_SMART_SITE (gb_tb_widget_get_bookmark (GB_TB_WIDGET (w)));
	guint num_args;
	guint i;
	gboolean ret = TRUE;
	
	num_args = gb_smart_site_get_num_fields (ss);
	for (i = 0; i < num_args; i++)
	{
		gchar *s = gtk_editable_get_chars (GTK_EDITABLE (p->entries[i]), 0, -1);
		ret = ret && s && s[0] != '\0';
		g_free (s);
		if (!ret)
		{
			return ret;
		}
	}
	return ret;
}

static gboolean
gb_smart_site_tb_widget_key_press_event_cb (GtkWidget *entry, GdkEventKey *event, GbSmartSiteTbWidget *w)
{
	GbBookmarkActivatedFlags flags;

	if (!(event->keyval == GDK_Return || event->keyval == GDK_KP_Enter))
	{
		return FALSE;
	}

	flags = GB_BAF_DEFAULT;
	if (event->state & GDK_CONTROL_MASK)
		flags = GB_BAF_NEW_TAB_OR_WINDOW;

	if (gb_smart_site_tb_widget_entries_empty (w))
	{
		gb_smart_site_tb_widget_do_the_smart_thing (w, flags);
	}
	else
	{
		GbBookmark *b = gb_tb_widget_get_bookmark (GB_TB_WIDGET (w));
		gb_activated_activate (w, b, GB_SITE (b)->url, flags);
	}

	return TRUE;
}

static void
gb_smart_site_tb_widget_clicked_cb (GtkButton *button, GbSmartSiteTbWidget *w)
{
	GbBookmark *b = gb_tb_widget_get_bookmark (GB_TB_WIDGET (w));
	if (b)
	{
		if (gb_smart_site_tb_widget_entries_empty (w))
		{
			gb_smart_site_tb_widget_do_the_smart_thing (w, GB_BAF_DEFAULT);
		}
		else
		{
			gb_activated_activate (w, b, GB_SITE (b)->url, GB_BAF_DEFAULT);
		}
	}
}

static void
gb_smart_site_tb_widget_entry_width_changed_cb (GbSmartSite *b, gint index, guint width, 
						GbSmartSiteTbWidget *w)
{
	GbSmartSiteTbWidgetPrivate *p = w->priv;
	g_return_if_fail (index < p->num_entries);
	p->entries_sizes[index] = width;
	gtk_widget_set_size_request (p->entries[index], p->entries_sizes[index], -1);
}


static gboolean
gb_smart_site_tb_widget_button_press_cb (GtkWidget *wid, 
					 GdkEventButton *event, 
					 GbSmartSiteTbWidget *w)
{
	GbBookmark *b = gb_tb_widget_get_bookmark (GB_TB_WIDGET (w));
	if (b && event->button == 2)
	{
		if (gb_smart_site_tb_widget_entries_empty (w))
		{
			gb_smart_site_tb_widget_do_the_smart_thing (w, GB_BAF_NEW_TAB_OR_WINDOW);
		}
		else
		{
			gb_activated_event (w, b, GB_SITE (b)->url, 
					    GB_BAF_NEW_TAB_OR_WINDOW, (GdkEvent *) event);
		}
		return TRUE;
	}
	return FALSE;
}

static void
gb_smart_site_tb_widget_history_changed_cb (GbSmartSite *ss, GbSmartSiteTbWidget *w)
{
	GbSmartSiteTbWidgetPrivate *p = w->priv;
	GSList *history;
	GList *history_l;
	int i;

	for (i = 0; i < p->num_entries; ++i)
		if (p->combos[i])
		{
			GList *l;

			history = gb_smart_site_get_history (ss, i);
			history_l = gslist_to_glist (history);
			history_l = g_list_prepend (history_l, "");

			gtk_combo_box_set_active(GTK_COMBO_BOX(p->combos[i]), -1);
			gtk_list_store_clear(GTK_LIST_STORE(
			    gtk_combo_box_get_model(GTK_COMBO_BOX(p->combos[i]))));

			for (l = history_l; l; l = l->next)
			{
				gtk_combo_box_append_text(GTK_COMBO_BOX(p->combos[i]),
				                          (const gchar *)l->data);
			}

			g_slist_foreach (history, (GFunc) g_free, NULL);
			g_slist_free (history);
			g_list_free (history_l);
		}
}

static void
gb_smart_site_tb_widget_conf_changed_cb (GConfClient* client,
					 guint cnxn_id,
					 GConfEntry *entry,
					 gpointer user_data)
{
	GSList *li;
	for (li = all_instances; li; li = li->next)
	{
		GbSmartSiteTbWidget *w = li->data;
		g_return_if_fail (GB_IS_SMART_SITE_TB_WIDGET (w));
		gb_smart_site_tb_widget_build_smart_box (w);
	}
}



static void
gb_smart_site_tb_widget_drag_data_received_cb (GtkWidget *widget,
					       GdkDragContext *dc,
					       gint x, gint y,
					       GtkSelectionData *selection_data,
					       guint info,
					       guint t,
					       GbSmartSiteTbWidget *w)
{
	GbSmartSite *ss = GB_SMART_SITE (gb_tb_widget_get_bookmark (GB_TB_WIDGET (w)));
	gchar *url, *str;
	gchar *args[2];

	g_return_if_fail (gb_smart_site_get_num_fields (ss) == 1);

	if (info == GALEON_DND_TEXT)
	{
		str = g_strdup (selection_data->data);
	} 
	else
	{
		str = gtk_selection_data_get_text (selection_data);
	}

	if (str == NULL || str[0] == '\0') return;

	args[0] = str;
	args[1] = NULL;

	gb_smart_site_prepend_history (ss, 0, str);

	url = gb_smart_site_subst_args (ss, args);
	gb_activated_activate (w, GB_BOOKMARK (ss), url, GB_BAF_DEFAULT);
	g_free (url);
	g_free (str);
}

