/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */

/*
 *  Copyright (C) 2004 Hiroyuki Ikezoe
 *  Copyright (C) 2003 - 2004 Takuro Ashie
 *  Copyright (C) 2004 Hidetaka Iwai
 *
 *  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.
 */

#include "kz-smart-bookmark-action.h"

#include <gdk/gdkkeysyms.h>
#include <glib/gi18n.h>

#include "kazehakase.h"
#include "kz-smart-bookmark.h"
#include "utils/utils.h"
#include "utils/gtk-utils.h"
#include "kz-entry.h"
#include "kz-actions.h"
#include "kz-icons.h"

#define KZ_SMART_BOOKMARK_ACTION_BOOKMARK_KEY "KzSmartBookmarkAction::Bookmark"

enum {
	PROP_0,
	PROP_KZ_WINDOW,
	PROP_KZ_BOOKMARK
};

static void dispose      (GObject *obj);
static void set_property (GObject      *object,
                          guint         prop_id,
                          const GValue *value,
                          GParamSpec   *pspec);
static void get_property (GObject      *object,
                          guint         prop_id,
                          GValue       *value,
                          GParamSpec   *pspec);

static void activate     (GtkAction    *action);

static GtkWidget *create_tool_item                (GtkAction    *action);
static void       connect_proxy                   (GtkAction    *action,
						   GtkWidget    *proxy);
static void       disconnect_proxy                (GtkAction    *action,
						   GtkWidget    *proxy);
static gboolean   cb_entry_key_press              (GtkWidget *widget,
						   GdkEventKey *event,
						   KzSmartBookmarkAction *action);
static void       cb_entry_populate_popup         (GtkEntry *entry,
						   GtkMenu *menu,
	  			    	 	   KzSmartBookmarkAction *action);
static void       cb_entry_icon_pressed           (GtkEntry *entry,
						   GdkEventButton *event,
	  			    	 	   KzSmartBookmarkAction *action);
static void       cb_menuitem_activate            (GtkWidget *menuitem,
	  			    	 	   KzSmartBookmarkAction *action);

static void       cb_bookmark_notify             (GObject     *object,
						  GParamSpec  *pspec,
	  			    	 	  KzSmartBookmarkAction *action);
static void       cb_bookmark_updated            (KzBookmark *folder,
						  KzSmartBookmarkAction *action);
static void       cb_bookmark_remove_child       (KzBookmark *folder,
						  KzBookmark *child,
	  			    	 	  KzSmartBookmarkAction *action);
static void       cb_bookmark_insert_child  	 (KzBookmark *folder,
						  KzBookmark *child,
						  KzBookmark *sibling,
	  			    	 	  KzSmartBookmarkAction *action);
static void       open_smart_uris                (KzSmartBookmarkAction *action);
static gchar     *get_smart_uri                  (KzSmartBookmarkAction *action);
static gchar    **get_smart_uris                 (KzSmartBookmarkAction *action);

static void       update_icon_and_bgtext         (KzSmartBookmarkAction *action);

G_DEFINE_TYPE(KzSmartBookmarkAction, kz_smart_bookmark_action, KZ_TYPE_ENTRY_ACTION)

static void
kz_smart_bookmark_action_class_init (KzSmartBookmarkActionClass *klass)
{
	GObjectClass *object_class;
	GtkActionClass *action_class;
	KzEntryActionClass *entry_class;

	object_class  = G_OBJECT_CLASS(klass);
	action_class  = GTK_ACTION_CLASS(klass);
	entry_class   = KZ_ENTRY_ACTION_CLASS(klass);

	object_class->set_property     = set_property;
	object_class->get_property     = get_property;
	object_class->dispose          = dispose;

	action_class->activate         = activate;
	action_class->connect_proxy    = connect_proxy;
	action_class->disconnect_proxy = disconnect_proxy;
	action_class->create_tool_item = create_tool_item;

	g_object_class_install_property
		(object_class,
		 PROP_KZ_WINDOW,
		 g_param_spec_object ("kz-window",
				      _("KzWindow"),
				      _("The KzWindow"),
				      KZ_TYPE_WINDOW,
				      G_PARAM_READWRITE |
				      G_PARAM_CONSTRUCT_ONLY));
	g_object_class_install_property
		(object_class,
		 PROP_KZ_BOOKMARK,
		 g_param_spec_object ("kz-bookmark",
				      _("KzBookmark"),
				      _("The Bookmark object"),
				      KZ_TYPE_BOOKMARK,
				      G_PARAM_READWRITE |
				      G_PARAM_CONSTRUCT_ONLY));
}


static void
kz_smart_bookmark_action_init (KzSmartBookmarkAction *action)
{
	action->kz            = NULL;
	action->bookmark      = NULL;
	action->menu          = NULL;
	action->menulist      = NULL;
}


static void
dispose (GObject *obj)
{
	KzSmartBookmarkAction *action = KZ_SMART_BOOKMARK_ACTION(obj);

	if (action->kz)
	{
		g_object_unref(action->kz);
		action->kz = NULL;
	}
	if (action->bookmark)
	{
	/*	g_signal_handlers_disconnect_by_func
			(action->bookmark,
			 G_CALLBACK(cb_bookmark_updated),
			 action);*/
		g_signal_handlers_disconnect_by_func
			(action->bookmark,
			 G_CALLBACK(cb_bookmark_insert_child),
			 action);
		g_signal_handlers_disconnect_by_func
			(action->bookmark,
			 G_CALLBACK(cb_bookmark_remove_child),
			 action);
		g_object_unref(action->bookmark);
		action->bookmark = NULL;
	}
	if (action->menu)
	{
		gtk_widget_destroy(action->menu);
		action->menu = NULL;
	}
	if (action->menulist)
	{
		g_list_free(action->menulist);
		action->menulist = NULL;
	}

	if (G_OBJECT_CLASS(kz_smart_bookmark_action_parent_class)->dispose)
		G_OBJECT_CLASS(kz_smart_bookmark_action_parent_class)->dispose(obj);
}


static void
set_property (GObject         *object,
              guint            prop_id,
              const GValue    *value,
              GParamSpec      *pspec)
{
	KzSmartBookmarkAction *action = KZ_SMART_BOOKMARK_ACTION(object);
  
	switch (prop_id)
	{
	case PROP_KZ_WINDOW:
		action->kz = g_object_ref(g_value_get_object(value));
		break;
	case PROP_KZ_BOOKMARK:
		action->bookmark = g_object_ref(g_value_get_object(value));
		/* if bookmark is a folder, connect signals */
		if (kz_bookmark_is_folder(action->bookmark))
		{
			cb_bookmark_updated(action->bookmark, action);
	/*		g_signal_connect(bookmark, "children-reordered",
					 G_CALLBACK(cb_bookmark_updated),
					 action);*/
			g_signal_connect_after(action->bookmark, "insert-child",
					 G_CALLBACK(cb_bookmark_insert_child),
					 action);
			g_signal_connect(action->bookmark, "remove-child",
					 G_CALLBACK(cb_bookmark_remove_child),
					 action);	
		}
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
		break;
	}
}


static void
get_property (GObject         *object,
              guint            prop_id,
              GValue          *value,
              GParamSpec      *pspec)
{
	KzSmartBookmarkAction *action = KZ_SMART_BOOKMARK_ACTION(object);

	switch (prop_id)
	{
	case PROP_KZ_WINDOW:
		g_value_set_object(value, action->kz);
		break;
	case PROP_KZ_BOOKMARK:
		g_value_set_object(value, action->bookmark);
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
		break;
	}
}


static void
activate (GtkAction *action)
{
	KzSmartBookmarkAction *smart_action;
	gchar *smart_uri;
	gboolean new_tab;

	g_return_if_fail(KZ_IS_SMART_BOOKMARK_ACTION(action));

	if (GTK_ACTION_CLASS(kz_smart_bookmark_action_parent_class)->activate)
		GTK_ACTION_CLASS(kz_smart_bookmark_action_parent_class)->activate(action);

	smart_action = KZ_SMART_BOOKMARK_ACTION(action);

	if (kz_bookmark_is_folder(smart_action->bookmark) &&
	    kz_bookmark_is_folder(smart_action->menulist->data))
	{
		open_smart_uris(smart_action);	
		return;
	}

	smart_uri = get_smart_uri(smart_action);

	KZ_CONF_GET("Global", "entry_open_in_new_tab", new_tab, BOOL);
	if (new_tab)
		kz_window_open_new_tab(smart_action->kz, smart_uri);
	else	
		kz_window_load_url(smart_action->kz, smart_uri);
	
	g_free(smart_uri);
}


static GtkWidget *
create_tool_item (GtkAction *action)
{
	GtkWidget *widget;

	widget = (*GTK_ACTION_CLASS(kz_smart_bookmark_action_parent_class)->create_tool_item) (action);
	gtk_tool_item_set_expand (GTK_TOOL_ITEM(widget), FALSE);

	return widget;
}


static void
connect_proxy (GtkAction *action, GtkWidget *proxy)
{
	GtkEntry *entry;

	GTK_ACTION_CLASS (kz_smart_bookmark_action_parent_class)->connect_proxy (action, proxy);

	entry = kz_entry_action_get_entry_widget(KZ_ENTRY_ACTION(action), proxy);
	if (entry)
	{
		KzSmartBookmarkAction *smart_action;
		KzBookmark *bookmark;

		smart_action = KZ_SMART_BOOKMARK_ACTION(action);
		bookmark = smart_action->bookmark;
		g_signal_connect(entry, "key-press-event",
				 G_CALLBACK(cb_entry_key_press), action);
		g_signal_connect(entry, "populate-popup",
				 G_CALLBACK(cb_entry_populate_popup), action);
		g_signal_connect(entry, "icon-pressed",
				 G_CALLBACK(cb_entry_icon_pressed), action);
	
		g_signal_connect(bookmark, "notify",
			 	 G_CALLBACK(cb_bookmark_notify), action);
		update_icon_and_bgtext(KZ_SMART_BOOKMARK_ACTION(action));
	}
}


static void
disconnect_proxy (GtkAction *action, GtkWidget *proxy)
{
	GtkEntry *entry;

	entry = kz_entry_action_get_entry_widget(KZ_ENTRY_ACTION(action), proxy);
	if (entry)
	{
		g_signal_handlers_disconnect_by_func
			(entry,
			 G_CALLBACK(cb_entry_key_press),
			 action);
		g_signal_handlers_disconnect_by_func
			(entry,
			 G_CALLBACK(cb_entry_populate_popup),
			 action);
		g_signal_handlers_disconnect_by_func
			(entry,
			 G_CALLBACK(cb_entry_icon_pressed),
			 action);
	}

	GTK_ACTION_CLASS (kz_smart_bookmark_action_parent_class)->disconnect_proxy (action, proxy);
}


KzSmartBookmarkAction *
kz_smart_bookmark_action_new (KzWindow *kz, KzBookmark *bookmark)
{
	KzSmartBookmarkAction *action;
	gchar *name;
	const gchar *title, *link;

	title = kz_bookmark_get_title(bookmark);
	link = kz_bookmark_get_link(bookmark);

	if (title && g_str_has_prefix(title, "LocationEntry"))
		name = g_strdup("LocationEntry");
	else if (link &&
		g_str_has_prefix(link, "history-search:") &&
		!KZ_GET_SEARCH)
	{
		return NULL;
	}
	else
		name = g_strdup_printf("SmartBookmark:%p", bookmark);

	action = g_object_new(KZ_TYPE_SMART_BOOKMARK_ACTION,
			      "name",        name,
			      "label",       _("Entry"),
			      "tooltip",     NULL,
			      "stock_id",    KZ_STOCK_SEARCH,
			      "kz-window",   kz,
			      "kz-bookmark", bookmark,
			      NULL);
	g_free(name);

	return action;
}


static void
cb_activate_edit_bookmark (GtkMenuItem *menuitem,
			   KzSmartBookmarkAction *action)
{
	GtkAction *edit_action;
	KzWindow *kz = action->kz;

	kz_actions_set_bookmark_for_action(kz, action->bookmark);
	edit_action = gtk_action_group_get_action(kz->actions,
					     	  "EditBookmarks");
	if (edit_action)
		gtk_action_activate(edit_action);
	kz_actions_set_bookmark_for_action(kz, NULL);
}


static gboolean
cb_entry_key_press (GtkWidget *widget, GdkEventKey *event,
		    KzSmartBookmarkAction *action)
{
	guint new_tab_mask = GDK_CONTROL_MASK;

	KZ_CONF_GET("Tab" , "new_tab_mask" , new_tab_mask , INT);

	if ((event->keyval == GDK_Return || event->keyval == GDK_ISO_Enter)
	    && (event->state & new_tab_mask))
	{
		gboolean newtab;
		gchar *smart_uri;

		if (kz_bookmark_is_folder(action->bookmark) &&
		    kz_bookmark_is_folder(action->menulist->data))
		{
			open_smart_uris(action);
			return TRUE;
		}
		
		KZ_CONF_GET("Global", "entry_open_in_new_tab", newtab, BOOL);

		smart_uri = get_smart_uri(action);

		if (newtab)
			kz_window_load_url(action->kz, smart_uri);
		else 
			kz_window_open_new_tab(action->kz, smart_uri);
		
		g_free(smart_uri);

		return TRUE;
	}

	return FALSE;
}


static void 
cb_entry_populate_popup (GtkEntry *entry, GtkMenu *menu,
		    	 KzSmartBookmarkAction *action)
{
	GtkWidget *separator, *menuitem;

	separator = gtk_separator_menu_item_new();
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), separator);
	gtk_widget_show(separator);

	menuitem = gtk_menu_item_new_with_mnemonic(_("_Edit Smart Bookmark"));
	g_signal_connect(menuitem, "activate",
			 G_CALLBACK(cb_activate_edit_bookmark), action);
	gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
	gtk_widget_show(menuitem);
}



static void
cb_bookmark_notify (GObject *object,
		    GParamSpec *pspec,
	  	    KzSmartBookmarkAction *action)
{
	KzBookmark *bookmark;
	const gchar *prop;
        GValue value = { 0 };

	g_return_if_fail(KZ_IS_BOOKMARK(object));
	g_return_if_fail(KZ_IS_SMART_BOOKMARK_ACTION(action));

	bookmark = KZ_BOOKMARK(object);

	prop = g_param_spec_get_name(pspec);
	g_return_if_fail(prop);

        g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec));
        g_object_get_property(object, prop, &value);

	if (!strcmp(prop, "title"))
	{
		GSList *node, *proxies;
		gchar *title = g_value_dup_string(&value);

		proxies = gtk_action_get_proxies(GTK_ACTION(action));
		for (node = proxies; node; node = g_slist_next(node))
		{
			GtkWidget *proxy;
			GtkEntry *entry;
			if (!GTK_IS_WIDGET(node->data))
				continue;
			proxy = GTK_WIDGET(node->data);
			entry = kz_entry_action_get_entry_widget(KZ_ENTRY_ACTION(action),
								 proxy);

			if (KZ_IS_ENTRY(entry))
			{
				kz_entry_set_backtext(KZ_ENTRY(entry),
						      title);
			}
		}
		g_free(title);
	}
	g_value_unset(&value);
}


static GtkWidget *
create_menu_item (KzSmartBookmarkAction *action, KzBookmark *bookmark)
{
	GtkWidget *menuitem, *image;
	const gchar *title, *stock_id, *link;
	GdkPixbuf *favicon;
	KzFavicon *kzfav = KZ_GET_FAVICON;
	gboolean is_folder;

	is_folder = kz_bookmark_is_folder(bookmark);

	title = kz_bookmark_get_title(bookmark);
	link = kz_bookmark_get_link(bookmark);

	if (is_folder)
		title = _("Open all smart bookmarks");

	menuitem = gtk_image_menu_item_new_with_label(title);

	/* attempt to get favicon */
	favicon = kz_favicon_get_pixbuf(kzfav, link, GTK_ICON_SIZE_MENU);

	if (!favicon)
	{
		if (link && g_str_has_prefix(link, "history-search:"))
			stock_id = KZ_STOCK_HISTORY;
		else if (link && g_str_has_prefix(link, "http://www.amazon.com/"))
			stock_id = KZ_STOCK_BOOK_SEARCH;
		else
			stock_id = KZ_STOCK_SEARCH;
		if (kz_bookmark_is_folder(bookmark))
			stock_id = KZ_STOCK_FOLDER_SEARCH;
		image = gtk_image_new_from_stock(stock_id,
						 GTK_ICON_SIZE_MENU);
	}
	else
	{
		image = gtk_image_new_from_pixbuf(favicon);
		g_object_unref(favicon);
	}

	gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem),
				      image);
	g_object_set_data(G_OBJECT(menuitem),
			  KZ_SMART_BOOKMARK_ACTION_BOOKMARK_KEY,
			  bookmark);
	gtk_widget_show(menuitem);

	g_signal_connect (menuitem, "activate",
			  G_CALLBACK(cb_menuitem_activate), action);
	
	return menuitem;
}

static void
insert_child (KzSmartBookmarkAction *action, KzBookmark *child,
	      GtkWidget *menuitem, guint pos)
{
	gtk_menu_shell_insert(GTK_MENU_SHELL(action->menu),
			      menuitem, pos);
	action->menulist = g_list_insert(action->menulist, child, pos);
	if (pos == 0)
		update_icon_and_bgtext(action);
}

static void
cb_bookmark_updated (KzBookmark *folder, KzSmartBookmarkAction *action)
{
	GList *children, *node;
	GtkWidget *menuitem;
	int i;
	guint folder_pos;

	if (action->menu)
		gtk_widget_destroy(action->menu);
	action->menu = gtk_menu_new();
	
	/* folder menu */
	menuitem = create_menu_item(action, folder);
	gtk_menu_shell_append(GTK_MENU_SHELL(action->menu),
			      menuitem);
	if (action->menulist)
		g_list_free(action->menulist);
	action->menulist = g_list_append(NULL, folder);

	update_icon_and_bgtext(action);

	/* children */
	children = kz_bookmark_get_children(folder);
	folder_pos = kz_bookmark_get_current(folder);
	for (node = children, i = 0; node; node = g_list_next(node), i++)
	{
		KzBookmark *child = node->data;

		if (!KZ_IS_SMART_BOOKMARK(child)) continue;

		menuitem = create_menu_item(action, child);
		if (!menuitem) continue;

		if (i < folder_pos)
			insert_child(action, child, menuitem, i);
		else
			insert_child(action, child, menuitem, i + 1);
	}
	g_list_free(children);
}


static void
cb_bookmark_remove_child (KzBookmark *folder,
			  KzBookmark *child,
	  		  KzSmartBookmarkAction *action)
{
	GList *children, *menuitems;
	GtkWidget *widget;
	gint pos;

	children = kz_bookmark_get_children(folder);
	if (!children) return;

	menuitems = gtk_container_get_children(GTK_CONTAINER(action->menu));
	if (!menuitems) return;

	pos = g_list_index(action->menulist, child);
	action->menulist = g_list_remove(action->menulist, child);

	widget = GTK_WIDGET(g_list_nth_data(menuitems, pos));
	if (widget)
	{
		g_signal_handlers_disconnect_by_func
			(widget,
			 G_CALLBACK(cb_menuitem_activate),
			 child);
		gtk_widget_destroy(widget);
	}

	if (pos == 0)
		update_icon_and_bgtext(action);

	g_list_free(menuitems);
	g_list_free(children);
}


static void
cb_bookmark_insert_child (KzBookmark *folder,
			  KzBookmark *child,
			  KzBookmark *sibling,
	  		  KzSmartBookmarkAction *action)
{
	GtkWidget *menuitem;

	if (!KZ_IS_SMART_BOOKMARK(child)) return;
	
	menuitem = create_menu_item(action, child);
	if (!menuitem) return;

	if (!sibling)
	{
		GList *children;
		guint pos;

		children = kz_bookmark_get_children(folder);
		pos = g_list_index(children, child);
		if (pos < kz_bookmark_get_current(folder))
			insert_child(action, child, menuitem, pos);
		else
			insert_child(action, child, menuitem, pos + 1);
		g_list_free(children);
	}
	else
	{
		GList *children;
		gint pos;
		children = kz_bookmark_get_children(folder);
		
		pos = g_list_index(children, sibling);
		gtk_menu_shell_insert(GTK_MENU_SHELL(action->menu),
				      menuitem, pos - 1);
		action->menulist = g_list_insert(action->menulist, child, pos - 1);
		kz_bookmark_set_current(folder, pos);

		if (pos == 1)
		{
			/* update icon and background text */
			update_icon_and_bgtext(action);
		}
		g_list_free(children);
	}
}


static void
cb_menuitem_activate (GtkWidget *menuitem, KzSmartBookmarkAction *action)
{
	KzBookmark *parent, *bookmark;

	bookmark = g_object_get_data(G_OBJECT(menuitem),
				     KZ_SMART_BOOKMARK_ACTION_BOOKMARK_KEY);

	if (kz_bookmark_is_folder(bookmark))
	{
		/* bookmark moves to the top of the menu */
		gint index;
		index = g_list_index(action->menulist, bookmark);
		if (index == -1) return;

		gtk_menu_reorder_child(GTK_MENU(action->menu),
				       menuitem,
				       0);
		action->menulist = g_list_remove(action->menulist,
						 bookmark);
		action->menulist = g_list_prepend(action->menulist,
						  bookmark);
		kz_bookmark_set_current(bookmark, 0);
		update_icon_and_bgtext(action);
		return;
	}

	parent = kz_bookmark_get_parent(bookmark);

	/* remove bookmark */
	g_object_ref(bookmark);
	kz_bookmark_remove(parent, bookmark);

	/* insert bookmark */
	kz_bookmark_prepend(parent, bookmark);

	/* now, current bookmark is top of the parent */
	kz_bookmark_set_current(parent,
				g_list_index(action->menulist, parent));

	g_object_unref(bookmark);
}



static void
menu_position_under_widget (GtkMenu *menu, gint *x, gint *y,
			    gboolean *push_in, gpointer user_data)
{
	GtkWidget *w = GTK_WIDGET(user_data);
	gint wheight;

	gdk_window_get_origin(w->window, x, y);
	wheight = w->requisition.height;

	*y = *y + wheight;
}

static void
cb_entry_icon_pressed  (GtkEntry *entry, GdkEventButton *event,
	  	    	KzSmartBookmarkAction *action)
{
	if (!kz_bookmark_is_folder(action->bookmark)) return;
	
	/* open popup menu */
	gtk_menu_popup(GTK_MENU(action->menu), NULL, NULL, 
		       menu_position_under_widget,
		       GTK_WIDGET(entry),
		       0, 0);
}


static void
open_smart_uris (KzSmartBookmarkAction *action)
{
	gchar **smart_uris;
	gint i = 0;
	
	smart_uris = get_smart_uris(action);
	if (!smart_uris) return;

	while (smart_uris[i])
	{
		kz_window_open_new_tab(action->kz,
				       smart_uris[i]);
		i++;
	}
	g_strfreev(smart_uris);
}


static gchar *
get_smart_uri (KzSmartBookmarkAction *action)
{
	KzBookmark *bookmark;
	const gchar *uri;
	gchar *smart_uri;

	if (kz_bookmark_is_folder(action->bookmark))
		bookmark = KZ_BOOKMARK(action->menulist->data);
	else
		bookmark = action->bookmark;
	
	uri = kz_entry_action_get_text(KZ_ENTRY_ACTION(action));
	smart_uri = kz_smart_bookmark_get_smart_uri(KZ_SMART_BOOKMARK(bookmark), uri);

	return smart_uri;
}


static gchar **
get_smart_uris (KzSmartBookmarkAction *action)
{
	KzBookmark *bookmark = action->bookmark;
	const gchar *uri;
	guint n_children, i = 0;
	gchar **smart_uris;
	GList *children, *node;
	
	g_return_val_if_fail(kz_bookmark_is_folder(bookmark), NULL);

	children = kz_bookmark_get_children(bookmark);
	if (!children) return NULL;

	n_children = g_list_length(children);	
	smart_uris = g_new0(gchar*, n_children + 1);

	uri = kz_entry_action_get_text(KZ_ENTRY_ACTION(action));
	for (node = children; node; node = g_list_next(node))
	{
		KzSmartBookmark *bookmark = node->data;
		
		smart_uris[i] = kz_smart_bookmark_get_smart_uri(bookmark, uri);
		i++;
	}
	g_list_free(children);

	return smart_uris;
}

static void
update_icon_and_bgtext(KzSmartBookmarkAction *action)
{
	KzBookmark *bookmark;
	const gchar *title, *stock_id = NULL, *link;
	gboolean is_folder;
	GSList *node, *proxies;
	GdkPixbuf *favicon;
	KzFavicon *kzfav = KZ_GET_FAVICON;

	is_folder = kz_bookmark_is_folder(action->bookmark);
	if (is_folder)
		bookmark = KZ_BOOKMARK(action->menulist->data);
	else
		bookmark = action->bookmark;

	title = kz_bookmark_get_title(bookmark);
	link = kz_bookmark_get_link(bookmark);

	/* attempt to get favicon */
	favicon = kz_favicon_get_pixbuf(kzfav, link, GTK_ICON_SIZE_MENU);

	if (!favicon)
	{
		if (link && g_str_has_prefix(link, "history-search:"))
			stock_id = KZ_STOCK_HISTORY;
		else if (link && g_str_has_prefix(link, "http://www.amazon.com/"))
			stock_id = KZ_STOCK_BOOK_SEARCH;
		else
			stock_id = KZ_STOCK_SEARCH;
		if (kz_bookmark_is_folder(bookmark))
			stock_id = KZ_STOCK_FOLDER_SEARCH;
	}

	proxies = gtk_action_get_proxies(GTK_ACTION(action));
	for (node = proxies; node; node = g_slist_next(node))
	{
		GtkWidget *proxy;
		GtkEntry *entry;
		if (!GTK_IS_WIDGET(node->data))
			continue;
		proxy = GTK_WIDGET(node->data);
		entry = kz_entry_action_get_entry_widget(KZ_ENTRY_ACTION(action),
							 proxy);

		if (KZ_IS_ENTRY(entry))
		{
			kz_entry_set_backtext(KZ_ENTRY(entry),
					      title);
			kz_entry_set_arrow(KZ_ENTRY(entry),
					   is_folder);
	
			if (favicon)
			{
				kz_entry_set_icon_from_pixbuf(KZ_ENTRY(entry),
							      favicon);
				g_object_unref(favicon);
			}
			else
			{
				kz_entry_set_icon_from_stock(KZ_ENTRY(entry),
					     		     stock_id,
				     			     GTK_ICON_SIZE_MENU);
			}
			gtk_widget_queue_resize(GTK_WIDGET(entry));
		}
	}
}

