#include "pluma-file-browser-messages.h"
#include "pluma-file-browser-store.h"
#include <pluma/pluma-message.h>

#define MESSAGE_OBJECT_PATH 	"/plugins/filebrowser"
#define WINDOW_DATA_KEY	       	"PlumaFileBrowserMessagesWindowData"

#define BUS_CONNECT(bus, name, data) pluma_message_bus_connect(bus, MESSAGE_OBJECT_PATH, #name, (PlumaMessageCallback)  message_##name##_cb, data, NULL)

typedef struct
{
	PlumaWindow *window;	
	PlumaMessage *message;
} MessageCacheData;

typedef struct
{
	guint row_inserted_id;
	guint row_deleted_id;
	guint root_changed_id;
	guint begin_loading_id;
	guint end_loading_id;

	GList *merge_ids;
	GtkActionGroup *merged_actions;
	
	PlumaMessageBus *bus;
	PlumaFileBrowserWidget *widget;
	GHashTable *row_tracking;
	
	GHashTable *filters;
} WindowData;

typedef struct
{
	gulong id;
	
	PlumaWindow *window;
	PlumaMessage *message;
} FilterData;

static WindowData *
window_data_new (PlumaWindow            *window,
		 PlumaFileBrowserWidget *widget)
{
	WindowData *data = g_slice_new (WindowData);
	GtkUIManager *manager;
	GList *groups;
	
	data->bus = pluma_window_get_message_bus (window);
	data->widget = widget;
	data->row_tracking = g_hash_table_new_full (g_str_hash, 
						    g_str_equal,
						    (GDestroyNotify)g_free,
						    (GDestroyNotify)gtk_tree_row_reference_free);

	data->filters = g_hash_table_new_full (g_str_hash,
					       g_str_equal,
					       (GDestroyNotify)g_free,
					       NULL);
	
	manager = pluma_file_browser_widget_get_ui_manager (widget);

	data->merge_ids = NULL;
	data->merged_actions = gtk_action_group_new ("MessageMergedActions");
	
	groups = gtk_ui_manager_get_action_groups (manager);
	gtk_ui_manager_insert_action_group (manager, data->merged_actions, g_list_length (groups));
	
	g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, data);

	return data;
}

static WindowData *
get_window_data (PlumaWindow * window)
{
	return (WindowData *) (g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY));
}

static void
window_data_free (PlumaWindow *window)
{
	WindowData *data = get_window_data (window);
	GtkUIManager *manager;
	GList *item;
		
	g_hash_table_destroy (data->row_tracking);	
	g_hash_table_destroy (data->filters);

	manager = pluma_file_browser_widget_get_ui_manager (data->widget);
	gtk_ui_manager_remove_action_group (manager, data->merged_actions);
	
	for (item = data->merge_ids; item; item = item->next)
		gtk_ui_manager_remove_ui (manager, GPOINTER_TO_INT (item->data));

	g_list_free (data->merge_ids);
	g_object_unref (data->merged_actions);

	g_slice_free (WindowData, data);

	g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, NULL);
}

static FilterData *
filter_data_new (PlumaWindow  *window,  
		 PlumaMessage *message)
{
	FilterData *data = g_slice_new (FilterData);
	WindowData *wdata;
	
	data->window = window;
	data->id = 0;
	data->message = message;
	
	wdata = get_window_data (window);
	
	g_hash_table_insert (wdata->filters, 
			     pluma_message_type_identifier (pluma_message_get_object_path (message),
			                                    pluma_message_get_method (message)),
			     data);

	return data;
}

static void
filter_data_free (FilterData *data)
{
	WindowData *wdata = get_window_data (data->window);
	gchar *identifier;
	
	identifier = pluma_message_type_identifier (pluma_message_get_object_path (data->message),
			                            pluma_message_get_method (data->message));
			                            
	g_hash_table_remove (wdata->filters, identifier);
	g_free (identifier);

	g_object_unref (data->message);
	g_slice_free (FilterData, data);
}

static GtkTreePath *
track_row_lookup (WindowData  *data, 
		  const gchar *id)
{
	GtkTreeRowReference *ref;
	
	ref = (GtkTreeRowReference *)g_hash_table_lookup (data->row_tracking, id);
	
	if (!ref)
		return NULL;
	
	return gtk_tree_row_reference_get_path (ref);
}

static void
message_cache_data_free (MessageCacheData *data)
{
	g_object_unref (data->message);
	g_slice_free (MessageCacheData, data);
}

static MessageCacheData *
message_cache_data_new (PlumaWindow            *window,
			PlumaMessage           *message)
{
	MessageCacheData *data = g_slice_new (MessageCacheData);
	
	data->window = window;
	data->message = message;
	
	return data;
}

static void
message_get_root_cb (PlumaMessageBus *bus,
		     PlumaMessage    *message,
		     WindowData      *data)
{
	PlumaFileBrowserStore *store;
	gchar *uri;
	
	store = pluma_file_browser_widget_get_browser_store (data->widget);
	uri = pluma_file_browser_store_get_virtual_root (store);
	
	pluma_message_set (message, "uri", uri, NULL);
	g_free (uri);
}

static void
message_set_root_cb (PlumaMessageBus *bus,
		     PlumaMessage    *message,
		     WindowData      *data)
{
	gchar *root = NULL;
	gchar *virtual = NULL;
	
	pluma_message_get (message, "uri", &root, NULL);
	
	if (!root)
		return;
	
	if (pluma_message_has_key (message, "virtual"))
		pluma_message_get (message, "virtual", &virtual, NULL);

	if (virtual)
		pluma_file_browser_widget_set_root_and_virtual_root (data->widget, root, virtual);
	else
		pluma_file_browser_widget_set_root (data->widget, root, TRUE);
	
	g_free (root);
	g_free (virtual);
}

static void
message_set_emblem_cb (PlumaMessageBus *bus,
		       PlumaMessage    *message,
		       WindowData      *data)
{
	gchar *id = NULL;
	gchar *emblem = NULL;
	GtkTreePath *path;
	PlumaFileBrowserStore *store;
	
	pluma_message_get (message, "id", &id, "emblem", &emblem, NULL);
	
	if (!id || !emblem)
	{
		g_free (id);
		g_free (emblem);
		
		return;
	}
	
	path = track_row_lookup (data, id);
	
	if (path != NULL)
	{
		GError *error = NULL;
		GdkPixbuf *pixbuf;
		
		pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), 
						   emblem, 
						   10, 
						   0, 
						   &error);
		
		if (pixbuf)
		{
			GValue value = { 0, };
			GtkTreeIter iter;
			
			store = pluma_file_browser_widget_get_browser_store (data->widget);
			
			if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path))
			{
				g_value_init (&value, GDK_TYPE_PIXBUF);
				g_value_set_object (&value, pixbuf);
			
				pluma_file_browser_store_set_value (store, 
								    &iter,
								    PLUMA_FILE_BROWSER_STORE_COLUMN_EMBLEM,
								    &value);
			
				g_value_unset (&value);
			}
			
			g_object_unref (pixbuf);
		}
		
		if (error)
			g_error_free (error);
	}
	
	g_free (id);
	g_free (emblem);
}

static gchar *
item_id (const gchar *path,
	 const gchar *uri)
{
	return g_strconcat (path, "::", uri, NULL);
}

static gchar *
track_row (WindowData            *data,
	   PlumaFileBrowserStore *store,
	   GtkTreePath           *path,
	   const gchar		 *uri)
{
	GtkTreeRowReference *ref;
	gchar *id;
	gchar *pathstr;
	
	pathstr = gtk_tree_path_to_string (path);
	id = item_id (pathstr, uri);
	
	ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (store), path);
	g_hash_table_insert (data->row_tracking, g_strdup (id), ref);
	
	g_free (pathstr);
	
	return id;
}

static void
set_item_message (WindowData   *data, 
		  GtkTreeIter  *iter,
		  GtkTreePath  *path,
		  PlumaMessage *message)
{
	PlumaFileBrowserStore *store;
	gchar *uri = NULL;
	guint flags = 0;
	gchar *track_id;
	
	store = pluma_file_browser_widget_get_browser_store (data->widget);
	
	gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
			    PLUMA_FILE_BROWSER_STORE_COLUMN_URI, &uri,
			    PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags,
			    -1);
	
	if (!uri)
		return;

	if (path && gtk_tree_path_get_depth (path) != 0)
		track_id = track_row (data, store, path, uri);
	else
		track_id = NULL;

	pluma_message_set (message,
			   "id", track_id,
			   "uri", uri,
			   NULL);
	
	if (pluma_message_has_key (message, "is_directory"))
	{
		pluma_message_set (message, 
				   "is_directory", FILE_IS_DIR (flags),
				   NULL);
	}			   

	g_free (uri);
	g_free (track_id);
}

static gboolean
custom_message_filter_func (PlumaFileBrowserWidget *widget,
			    PlumaFileBrowserStore  *store,
			    GtkTreeIter            *iter,
			    FilterData             *data)
{
	WindowData *wdata = get_window_data (data->window);
	gchar *uri = NULL;
	guint flags = 0;
	gboolean filter = FALSE;
	GtkTreePath *path;
	
	gtk_tree_model_get (GTK_TREE_MODEL (store), iter, 
			    PLUMA_FILE_BROWSER_STORE_COLUMN_URI, &uri,
			    PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags,
			    -1);
	
	if (!uri || FILE_IS_DUMMY (flags))
	{
		g_free (uri);
		return FALSE;
	}
	
	path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter);
	set_item_message (wdata, iter, path, data->message);
	gtk_tree_path_free (path);
	
	pluma_message_set (data->message, "filter", filter, NULL);

	pluma_message_bus_send_message_sync (wdata->bus, data->message);
	pluma_message_get (data->message, "filter", &filter, NULL);
	
	return !filter;
}

static void
message_add_filter_cb (PlumaMessageBus *bus,
		       PlumaMessage    *message,
		       PlumaWindow     *window)
{
	gchar *object_path = NULL;
	gchar *method = NULL;
	gulong id;
	PlumaMessageType *message_type;
	PlumaMessage *cbmessage;
	FilterData *filter_data;
	WindowData *data = get_window_data (window);
	
	pluma_message_get (message, 
			   "object_path", &object_path,
			   "method", &method,
			   NULL);
	
	// Check if there exists such a 'callback' message
	if (!object_path || !method)
	{
		g_free (object_path);
		g_free (method);
		
		return;
	}
	
	message_type = pluma_message_bus_lookup (bus, object_path, method);
	
	if (!message_type)
	{
		g_free (object_path);
		g_free (method);
		
		return;
	}
	
	// Check if the message type has the correct arguments
	if (pluma_message_type_lookup (message_type, "id") != G_TYPE_STRING ||
	    pluma_message_type_lookup (message_type, "uri") != G_TYPE_STRING ||
	    pluma_message_type_lookup (message_type, "is_directory") != G_TYPE_BOOLEAN ||
	    pluma_message_type_lookup (message_type, "filter") != G_TYPE_BOOLEAN)
	{
		return;
	}
	
	cbmessage = pluma_message_type_instantiate (message_type,
						    "id", NULL,
						    "uri", NULL,
						    "is_directory", FALSE,
						    "filter", FALSE,
						    NULL);

	// Register the custom filter on the widget
	filter_data = filter_data_new (window, cbmessage);
	id = pluma_file_browser_widget_add_filter (data->widget, 
						   (PlumaFileBrowserWidgetFilterFunc)custom_message_filter_func,
						   filter_data,
						   (GDestroyNotify)filter_data_free);

	filter_data->id = id;
}

static void
message_remove_filter_cb (PlumaMessageBus *bus,
		          PlumaMessage    *message,
		          WindowData      *data)
{
	gulong id = 0;
	
	pluma_message_get (message, "id", &id, NULL);
	
	if (!id)
		return;
	
	pluma_file_browser_widget_remove_filter (data->widget, id);
}

static void
message_up_cb (PlumaMessageBus *bus,
	       PlumaMessage    *message,
	       WindowData      *data)
{
	PlumaFileBrowserStore *store = pluma_file_browser_widget_get_browser_store (data->widget);
	
	pluma_file_browser_store_set_virtual_root_up (store);
}

static void
message_history_back_cb (PlumaMessageBus *bus,
		         PlumaMessage    *message,
		         WindowData      *data)
{
	pluma_file_browser_widget_history_back (data->widget);
}

static void
message_history_forward_cb (PlumaMessageBus *bus,
		            PlumaMessage    *message,
		            WindowData      *data)
{
	pluma_file_browser_widget_history_forward (data->widget);
}

static void
message_refresh_cb (PlumaMessageBus *bus,
		    PlumaMessage    *message,
		    WindowData      *data)
{
	pluma_file_browser_widget_refresh (data->widget);
}

static void
message_set_show_hidden_cb (PlumaMessageBus *bus,
		            PlumaMessage    *message,
		            WindowData      *data)
{
	gboolean active = FALSE;
	PlumaFileBrowserStore *store;
	PlumaFileBrowserStoreFilterMode mode;
	
	pluma_message_get (message, "active", &active, NULL);
	
	store = pluma_file_browser_widget_get_browser_store (data->widget);
	mode = pluma_file_browser_store_get_filter_mode (store);
	
	if (active)
		mode &= ~PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN;
	else
		mode |= PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_HIDDEN;

	pluma_file_browser_store_set_filter_mode (store, mode);
}

static void
message_set_show_binary_cb (PlumaMessageBus *bus,
		            PlumaMessage    *message,
		            WindowData      *data)
{
	gboolean active = FALSE;
	PlumaFileBrowserStore *store;
	PlumaFileBrowserStoreFilterMode mode;
	
	pluma_message_get (message, "active", &active, NULL);
	
	store = pluma_file_browser_widget_get_browser_store (data->widget);
	mode = pluma_file_browser_store_get_filter_mode (store);
	
	if (active)
		mode &= ~PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY;
	else
		mode |= PLUMA_FILE_BROWSER_STORE_FILTER_MODE_HIDE_BINARY;

	pluma_file_browser_store_set_filter_mode (store, mode);
}

static void
message_show_bookmarks_cb (PlumaMessageBus *bus,
		           PlumaMessage    *message,
		           WindowData      *data)
{
	pluma_file_browser_widget_show_bookmarks (data->widget);
}

static void
message_show_files_cb (PlumaMessageBus *bus,
		       PlumaMessage    *message,
		       WindowData      *data)
{
	pluma_file_browser_widget_show_files (data->widget);
}

static void
message_add_context_item_cb (PlumaMessageBus *bus,
			     PlumaMessage    *message,
			     WindowData      *data)
{
	GtkAction *action = NULL;
	gchar *path = NULL;
	gchar *name;
	GtkUIManager *manager;
	guint merge_id;
	
	pluma_message_get (message, 
			   "action", &action, 
			   "path", &path, 
			   NULL);
	
	if (!action || !path)
	{
		if (action)
			g_object_unref (action);

		g_free (path);
		return;
	}
	
	gtk_action_group_add_action (data->merged_actions, action);
	manager = pluma_file_browser_widget_get_ui_manager (data->widget);
	name = g_strconcat (gtk_action_get_name (action), "MenuItem", NULL);
	merge_id = gtk_ui_manager_new_merge_id (manager);
	
	gtk_ui_manager_add_ui (manager, 
			       merge_id,
			       path,
			       name,
			       gtk_action_get_name (action),
			       GTK_UI_MANAGER_AUTO,
			       FALSE);
	
	if (gtk_ui_manager_get_widget (manager, path))
	{
		data->merge_ids = g_list_prepend (data->merge_ids, GINT_TO_POINTER (merge_id));
		pluma_message_set (message, "id", merge_id, NULL);
	}
	else
	{
		pluma_message_set (message, "id", 0, NULL);
	}
	
	g_object_unref (action);
	g_free (path);
	g_free (name);
}

static void
message_remove_context_item_cb (PlumaMessageBus *bus,
				PlumaMessage    *message,
				WindowData      *data)
{
	guint merge_id = 0;
	GtkUIManager *manager;
	
	pluma_message_get (message, "id", &merge_id, NULL);
	
	if (merge_id == 0)
		return;
	
	manager = pluma_file_browser_widget_get_ui_manager (data->widget);
		
	data->merge_ids = g_list_remove (data->merge_ids, GINT_TO_POINTER (merge_id));
	gtk_ui_manager_remove_ui (manager, merge_id);
}

static void
message_get_view_cb (PlumaMessageBus *bus,
		     PlumaMessage    *message,
		     WindowData      *data)
{
	PlumaFileBrowserView *view;
	view = pluma_file_browser_widget_get_browser_view (data->widget);

	pluma_message_set (message, "view", view, NULL);
}

static void
register_methods (PlumaWindow            *window,
		  PlumaFileBrowserWidget *widget)
{
	PlumaMessageBus *bus = pluma_window_get_message_bus (window);
	WindowData *data = get_window_data (window);

	/* Register method calls */
	pluma_message_bus_register (bus, 
				    MESSAGE_OBJECT_PATH, "get_root", 
				    1,
				    "uri", G_TYPE_STRING,
				    NULL);
 
	pluma_message_bus_register (bus, 
				    MESSAGE_OBJECT_PATH, "set_root", 
				    1, 
				    "uri", G_TYPE_STRING,
				    "virtual", G_TYPE_STRING,
				    NULL);
				    
	pluma_message_bus_register (bus,
				    MESSAGE_OBJECT_PATH, "set_emblem",
				    0,
				    "id", G_TYPE_STRING,
				    "emblem", G_TYPE_STRING,
				    NULL);
	
	pluma_message_bus_register (bus,
				    MESSAGE_OBJECT_PATH, "add_filter",
				    1,
				    "object_path", G_TYPE_STRING,
				    "method", G_TYPE_STRING,
				    "id", G_TYPE_ULONG,
				    NULL);
	
	pluma_message_bus_register (bus,
				    MESSAGE_OBJECT_PATH, "remove_filter",
				    0,
				    "id", G_TYPE_ULONG,
				    NULL);
	
	pluma_message_bus_register (bus,
				    MESSAGE_OBJECT_PATH, "add_context_item",
				    1,
				    "action", GTK_TYPE_ACTION,
				    "path", G_TYPE_STRING,
				    "id", G_TYPE_UINT,
				    NULL);

	pluma_message_bus_register (bus,
				    MESSAGE_OBJECT_PATH, "remove_context_item",
				    0,
				    "id", G_TYPE_UINT,
				    NULL);
	
	pluma_message_bus_register (bus, MESSAGE_OBJECT_PATH, "up", 0, NULL);
	
	pluma_message_bus_register (bus, MESSAGE_OBJECT_PATH, "history_back", 0, NULL);
	pluma_message_bus_register (bus, MESSAGE_OBJECT_PATH, "history_forward", 0, NULL);
	
	pluma_message_bus_register (bus, MESSAGE_OBJECT_PATH, "refresh", 0, NULL);

	pluma_message_bus_register (bus, 
				    MESSAGE_OBJECT_PATH, "set_show_hidden", 
				    0, 
				    "active", G_TYPE_BOOLEAN,
				    NULL);
	pluma_message_bus_register (bus, 
				    MESSAGE_OBJECT_PATH, "set_show_binary",
				    0, 
				    "active", G_TYPE_BOOLEAN,
				    NULL);

	pluma_message_bus_register (bus, MESSAGE_OBJECT_PATH, "show_bookmarks", 0, NULL);
	pluma_message_bus_register (bus, MESSAGE_OBJECT_PATH, "show_files", 0, NULL);

	pluma_message_bus_register (bus,
				    MESSAGE_OBJECT_PATH, "get_view",
				    1,
				    "view", PLUMA_TYPE_FILE_BROWSER_VIEW,
				    NULL);

	BUS_CONNECT (bus, get_root, data);
	BUS_CONNECT (bus, set_root, data);
	BUS_CONNECT (bus, set_emblem, data);
	BUS_CONNECT (bus, add_filter, window);
	BUS_CONNECT (bus, remove_filter, data);

	BUS_CONNECT (bus, add_context_item, data);
	BUS_CONNECT (bus, remove_context_item, data);

	BUS_CONNECT (bus, up, data);
	BUS_CONNECT (bus, history_back, data);
	BUS_CONNECT (bus, history_forward, data);

	BUS_CONNECT (bus, refresh, data);
	
	BUS_CONNECT (bus, set_show_hidden, data);
	BUS_CONNECT (bus, set_show_binary, data);
	
	BUS_CONNECT (bus, show_bookmarks, data);
	BUS_CONNECT (bus, show_files, data);

	BUS_CONNECT (bus, get_view, data);
}

static void
store_row_inserted (PlumaFileBrowserStore *store,
		    GtkTreePath		  *path,
		    GtkTreeIter           *iter,
		    MessageCacheData      *data)
{
	gchar *uri = NULL;
	guint flags = 0;

	gtk_tree_model_get (GTK_TREE_MODEL (store), iter, 
			    PLUMA_FILE_BROWSER_STORE_COLUMN_URI, &uri,
			    PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags,
			    -1);
	
	if (!FILE_IS_DUMMY (flags) && !FILE_IS_FILTERED (flags))
	{
		WindowData *wdata = get_window_data (data->window);
		
		set_item_message (wdata, iter, path, data->message);
		pluma_message_bus_send_message_sync (wdata->bus, data->message);
	}
	
	g_free (uri);
}

static void
store_row_deleted (PlumaFileBrowserStore *store,
		   GtkTreePath		 *path,
		   MessageCacheData      *data)
{
	GtkTreeIter iter;
	gchar *uri = NULL;
	guint flags = 0;
	
	if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path))
		return;
	
	gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, 
			    PLUMA_FILE_BROWSER_STORE_COLUMN_URI, &uri,
			    PLUMA_FILE_BROWSER_STORE_COLUMN_FLAGS, &flags,
			    -1);
	
	if (!FILE_IS_DUMMY (flags) && !FILE_IS_FILTERED (flags))
	{
		WindowData *wdata = get_window_data (data->window);
		
		set_item_message (wdata, &iter, path, data->message);
		pluma_message_bus_send_message_sync (wdata->bus, data->message);
	}
	
	g_free (uri);
}

static void
store_virtual_root_changed (PlumaFileBrowserStore *store,
			    GParamSpec            *spec,
			    MessageCacheData      *data)
{
	WindowData *wdata = get_window_data (data->window);
	gchar *uri;
	
	uri = pluma_file_browser_store_get_virtual_root (store);
	
	if (!uri)
		return;
	
	pluma_message_set (data->message,
			   "uri", uri,
			   NULL);
			   
	pluma_message_bus_send_message_sync (wdata->bus, data->message);
	
	g_free (uri);
}

static void
store_begin_loading (PlumaFileBrowserStore *store,
		     GtkTreeIter           *iter,
		     MessageCacheData      *data)
{
	GtkTreePath *path;
	WindowData *wdata = get_window_data (data->window);
	
	path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter);
	
	set_item_message (wdata, iter, path, data->message);
	
	pluma_message_bus_send_message_sync (wdata->bus, data->message);
	gtk_tree_path_free (path);
}

static void
store_end_loading (PlumaFileBrowserStore *store,
		   GtkTreeIter           *iter,
		   MessageCacheData      *data)
{
	GtkTreePath *path;
	WindowData *wdata = get_window_data (data->window);
	
	path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter);
	
	set_item_message (wdata, iter, path, data->message);
	
	pluma_message_bus_send_message_sync (wdata->bus, data->message);
	gtk_tree_path_free (path);
}
		    
static void
register_signals (PlumaWindow            *window,
		  PlumaFileBrowserWidget *widget)
{
	PlumaMessageBus *bus = pluma_window_get_message_bus (window);
	PlumaFileBrowserStore *store;
	PlumaMessageType *inserted_type;
	PlumaMessageType *deleted_type;
	PlumaMessageType *begin_loading_type;
	PlumaMessageType *end_loading_type;
	PlumaMessageType *root_changed_type;
	
	PlumaMessage *message;
	WindowData *data;

	/* Register signals */
	root_changed_type = pluma_message_bus_register (bus,
				    MESSAGE_OBJECT_PATH, "root_changed",
				    0,
				    "id", G_TYPE_STRING,
				    "uri", G_TYPE_STRING,
				    NULL);
	
	begin_loading_type = pluma_message_bus_register (bus,
				    MESSAGE_OBJECT_PATH, "begin_loading",
				    0,
				    "id", G_TYPE_STRING,
				    "uri", G_TYPE_STRING,
				    NULL);

	end_loading_type = pluma_message_bus_register (bus,
				    MESSAGE_OBJECT_PATH, "end_loading",
				    0,
				    "id", G_TYPE_STRING,
				    "uri", G_TYPE_STRING,
				    NULL);

	inserted_type = pluma_message_bus_register (bus,
						    MESSAGE_OBJECT_PATH, "inserted",
						    0,
						    "id", G_TYPE_STRING,
						    "uri", G_TYPE_STRING,
						    "is_directory", G_TYPE_BOOLEAN,
						    NULL);

	deleted_type = pluma_message_bus_register (bus,
						   MESSAGE_OBJECT_PATH, "deleted",
						   0,
						   "id", G_TYPE_STRING,
						   "uri", G_TYPE_STRING,
						   "is_directory", G_TYPE_BOOLEAN,
						   NULL);

	store = pluma_file_browser_widget_get_browser_store (widget);
	
	message = pluma_message_type_instantiate (inserted_type, 
						  "id", NULL,
						  "uri", NULL, 
						  "is_directory", FALSE, 
						  NULL);

	data = get_window_data (window);

	data->row_inserted_id = 
		g_signal_connect_data (store, 
				       "row-inserted", 
				       G_CALLBACK (store_row_inserted), 
				       message_cache_data_new (window, message),
				       (GClosureNotify)message_cache_data_free,
				       0);

	message = pluma_message_type_instantiate (deleted_type, 
						  "id", NULL, 
						  "uri", NULL,
						  "is_directory", FALSE, 
						  NULL);
	data->row_deleted_id = 
		g_signal_connect_data (store, 
				       "row-deleted", 
				       G_CALLBACK (store_row_deleted), 
				       message_cache_data_new (window, message),
				       (GClosureNotify)message_cache_data_free,
				       0);
	
	message = pluma_message_type_instantiate (root_changed_type,
						  "id", NULL,
						  "uri", NULL,
						  NULL);
	data->root_changed_id = 
		g_signal_connect_data (store,
				       "notify::virtual-root",
				       G_CALLBACK (store_virtual_root_changed),
				       message_cache_data_new (window, message),
				       (GClosureNotify)message_cache_data_free,
				       0);

	message = pluma_message_type_instantiate (begin_loading_type,
						  "id", NULL,
						  "uri", NULL,
						  NULL);	
	data->begin_loading_id = 
		g_signal_connect_data (store,
				      "begin_loading",
				       G_CALLBACK (store_begin_loading),
				       message_cache_data_new (window, message),
				       (GClosureNotify)message_cache_data_free,
				       0);

	message = pluma_message_type_instantiate (end_loading_type,
						  "id", NULL,
						  "uri", NULL,
						  NULL);
	data->end_loading_id = 
		g_signal_connect_data (store,
				       "end_loading",
				       G_CALLBACK (store_end_loading),
				       message_cache_data_new (window, message),
				       (GClosureNotify)message_cache_data_free,
				       0);
}

static void
message_unregistered (PlumaMessageBus  *bus,
		      PlumaMessageType *message_type,
		      PlumaWindow      *window)
{
	gchar *identifier = pluma_message_type_identifier (pluma_message_type_get_object_path (message_type),
							   pluma_message_type_get_method (message_type));
	FilterData *data;
	WindowData *wdata = get_window_data (window);
	
	data = g_hash_table_lookup (wdata->filters, identifier);
	
	if (data)
		pluma_file_browser_widget_remove_filter (wdata->widget, data->id);
	
	g_free (identifier);
}

void 
pluma_file_browser_messages_register (PlumaWindow            *window, 
				      PlumaFileBrowserWidget *widget)
{
	window_data_new (window, widget);
	
	register_methods (window, widget);
	register_signals (window, widget);
	
	g_signal_connect (pluma_window_get_message_bus (window),
			  "unregistered",
			  G_CALLBACK (message_unregistered),
			  window);	
}

static void
cleanup_signals (PlumaWindow *window)
{
	WindowData *data = get_window_data (window);
	PlumaFileBrowserStore *store;
	
	store = pluma_file_browser_widget_get_browser_store (data->widget);
	
	g_signal_handler_disconnect (store, data->row_inserted_id);
	g_signal_handler_disconnect (store, data->row_deleted_id);
	g_signal_handler_disconnect (store, data->root_changed_id);
	g_signal_handler_disconnect (store, data->begin_loading_id);
	g_signal_handler_disconnect (store, data->end_loading_id);
	
	g_signal_handlers_disconnect_by_func (data->bus, message_unregistered, window);
}

void
pluma_file_browser_messages_unregister (PlumaWindow *window)
{
	PlumaMessageBus *bus = pluma_window_get_message_bus (window);
		
	cleanup_signals (window);
	pluma_message_bus_unregister_all (bus, MESSAGE_OBJECT_PATH);

	window_data_free (window);
}