/*
 *  Copyright (C) 2002-2004 Marco Pesenti Gritti <mpeseng@tin.it>
 *
 *  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.
 *
 *  $Id$
 */

#include "config.h"

#include "ephy-topics-selector.h"
#include "ephy-debug.h"

#include <glib/gi18n.h>

static void ephy_topics_selector_class_init (EphyTopicsSelectorClass *klass);
static void ephy_topics_selector_init (EphyTopicsSelector *editor);

#define EPHY_TOPICS_SELECTOR_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_TOPICS_SELECTOR, EphyTopicsSelectorPrivate))

struct EphyTopicsSelectorPrivate
{
	EphyBookmarks *bookmarks;
	EphyNode *bookmark;
	EphyNodeFilter *filter;
	GList *topics;
};

enum
{
	PROP_0,
	PROP_BOOKMARKS,
	PROP_BOOKMARK
};

static GObjectClass *parent_class = NULL;

GType
ephy_topics_selector_get_type (void)
{
	static GType type = 0;

	if (G_UNLIKELY (type == 0))
	{
		static const GTypeInfo our_info =
		{
			sizeof (EphyTopicsSelectorClass),
			NULL,
			NULL,
			(GClassInitFunc) ephy_topics_selector_class_init,
			NULL,
			NULL,
			sizeof (EphyTopicsSelector),
			0,
			(GInstanceInitFunc) ephy_topics_selector_init
		};

		type = g_type_register_static (EPHY_TYPE_NODE_VIEW,
					       "EphyTopicsSelector",
					       &our_info, 0);
	}

	return type;
}

static void
ephy_topics_selector_set_bookmark (EphyTopicsSelector *selector,
				   EphyNode *bookmark)
{
	LOG ("Set bookmark")

	selector->priv->bookmark = bookmark;

	g_object_notify (G_OBJECT (selector), "bookmark");
}

static void
ephy_topics_selector_set_bookmarks (EphyTopicsSelector *selector,
				    EphyBookmarks *bookmarks)
{
	selector->priv->bookmarks = bookmarks;
}

static void
ephy_topics_selector_set_property (GObject *object,
		                   guint prop_id,
		                   const GValue *value,
		                   GParamSpec *pspec)
{
	EphyTopicsSelector *selector = EPHY_TOPICS_SELECTOR (object);

	switch (prop_id)
	{
	case PROP_BOOKMARKS:
		ephy_topics_selector_set_bookmarks
			(selector, g_value_get_object (value));
		break;
	case PROP_BOOKMARK:
		ephy_topics_selector_set_bookmark
			(selector, g_value_get_pointer (value));
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
		break;
	}
}

static void
ephy_topics_selector_get_property (GObject *object,
		                   guint prop_id,
		                   GValue *value,
		                   GParamSpec *pspec)
{
	EphyTopicsSelector *selector = EPHY_TOPICS_SELECTOR (object);

	switch (prop_id)
	{
	case PROP_BOOKMARK:
		g_value_set_pointer (value, selector);
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
		break;
	}
}

void
ephy_topics_selector_apply (EphyTopicsSelector *selector,
			    EphyNode *bookmark)
{
	GList *l;

	for (l = selector->priv->topics; l != NULL; l = l->next)
	{
		EphyNode *node = l->data;

		ephy_bookmarks_set_keyword (selector->priv->bookmarks,
					    node, bookmark);
	}
}

static void
provide_toggle (EphyNode *node,
		GValue *value,
		gpointer data)
{
	EphyTopicsSelector *selector = EPHY_TOPICS_SELECTOR (data);
	gboolean result = FALSE;

	g_value_init (value, G_TYPE_BOOLEAN);

	if (selector->priv->bookmark)
	{
		result = ephy_node_has_child (node, selector->priv->bookmark);
	}
	else
	{
		result = (g_list_find (selector->priv->topics, node) != NULL);
	}

	g_value_set_boolean (value, result);
}

static GObject *
ephy_topics_selector_constructor (GType type,
				  guint n_construct_properties,
                                  GObjectConstructParam *construct_params)

{
	GObject *object;
	EphyTopicsSelector *selector;
	EphyTopicsSelectorPrivate *priv;

	object = parent_class->constructor (type, n_construct_properties,
                                            construct_params);
	selector = EPHY_TOPICS_SELECTOR (object);
	priv = EPHY_TOPICS_SELECTOR_GET_PRIVATE (object);

	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (selector), FALSE);

	ephy_node_view_add_toggle (EPHY_NODE_VIEW (selector),
				   provide_toggle, selector);
	ephy_node_view_add_column (EPHY_NODE_VIEW (selector), _("Topics"),
				   G_TYPE_STRING,
				   EPHY_NODE_KEYWORD_PROP_NAME,
				   EPHY_NODE_VIEW_SHOW_PRIORITY |
				   EPHY_NODE_VIEW_EDITABLE |
				   EPHY_NODE_VIEW_SEARCHABLE, NULL);
	ephy_node_view_set_sort (EPHY_NODE_VIEW (selector), G_TYPE_STRING,
				 EPHY_NODE_KEYWORD_PROP_NAME, GTK_SORT_ASCENDING);

	return object;
}

static void
topic_destroy_cb (EphyNode *node,
		  EphyTopicsSelector *selector)
{
	selector->priv->topics = g_list_remove
				(selector->priv->topics, node);
}

static void
toggle_topic (EphyTopicsSelector *selector, EphyNode *node, gboolean checked)
{
	if (selector->priv->bookmark)
	{
		if (checked)
		{
			ephy_bookmarks_set_keyword (selector->priv->bookmarks,
						    node,
						    selector->priv->bookmark);
		}
		else
		{
			ephy_bookmarks_unset_keyword (selector->priv->bookmarks,
						      node,
						      selector->priv->bookmark);
		}
	}
	else
	{
		if (checked)
		{
			selector->priv->topics = g_list_prepend
					(selector->priv->topics, node);
			ephy_node_signal_connect_object (node, EPHY_NODE_DESTROY,
				 			 (EphyNodeCallback) topic_destroy_cb,
							 G_OBJECT (selector));
		}
		else
		{
			selector->priv->topics = g_list_remove
					(selector->priv->topics, node);
		}
	}
}

static void
node_toggled_cb (EphyTopicsSelector *selector, EphyNode *node,
		 gboolean checked, gpointer data)
{
	toggle_topic (selector, node, checked);
}

static void
ephy_topics_selector_init (EphyTopicsSelector *selector)
{
	selector->priv = EPHY_TOPICS_SELECTOR_GET_PRIVATE (selector);

	selector->priv->filter = ephy_node_filter_new ();
	ephy_node_filter_add_expression (selector->priv->filter,
				         ephy_node_filter_expression_new (EPHY_NODE_FILTER_EXPRESSION_INT_PROP_EQUALS,
								          EPHY_NODE_KEYWORD_PROP_PRIORITY,
									  EPHY_NODE_VIEW_NORMAL_PRIORITY),
				         0);
	g_object_set (selector, "filter", selector->priv->filter, NULL);

	g_signal_connect (selector, "node_toggled",
			  G_CALLBACK (node_toggled_cb), NULL);
}

static void
ephy_topics_selector_finalize (GObject *object)
{
	EphyTopicsSelector *selector = EPHY_TOPICS_SELECTOR (object);

	g_list_free (selector->priv->topics);

	g_object_unref (selector->priv->filter);

	parent_class->finalize (object);
}

GtkWidget *
ephy_topics_selector_new (EphyBookmarks *bookmarks,
			  EphyNode *bookmark)
{
	EphyTopicsSelector *editor;
	EphyNode *root;

	g_assert (bookmarks != NULL);

	root = ephy_bookmarks_get_keywords (bookmarks);
	editor = EPHY_TOPICS_SELECTOR (g_object_new
			(EPHY_TYPE_TOPICS_SELECTOR,
			 "bookmarks", bookmarks,
			 "bookmark", bookmark,
			 "root", root,
			 NULL));

	return GTK_WIDGET (editor);
}

void
ephy_topics_selector_new_topic (EphyTopicsSelector *selector)
{
	EphyNode *node;

	node = ephy_bookmarks_add_keyword
			(selector->priv->bookmarks, _("Type a topic"));
	toggle_topic (selector, node, TRUE);
	ephy_node_view_select_node (EPHY_NODE_VIEW (selector), node);
	ephy_node_view_edit (EPHY_NODE_VIEW (selector), TRUE);
}

static void
ephy_topics_selector_class_init (EphyTopicsSelectorClass *klass)
{
	GObjectClass *object_class = G_OBJECT_CLASS (klass);

	parent_class = g_type_class_peek_parent (klass);

	object_class->set_property = ephy_topics_selector_set_property;
	object_class->get_property = ephy_topics_selector_get_property;
	object_class->constructor = ephy_topics_selector_constructor;
	object_class->finalize = ephy_topics_selector_finalize;

	g_object_class_install_property (object_class,
					 PROP_BOOKMARKS,
					 g_param_spec_object ("bookmarks",
							      "Bookmarks set",
							      "Bookmarks set",
							      EPHY_TYPE_BOOKMARKS,
							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));

	g_object_class_install_property (object_class,
					 PROP_BOOKMARK,
					 g_param_spec_pointer ("bookmark",
							       "Bookmark",
							       "Bookmark",
							       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));

	g_type_class_add_private (object_class, sizeof(EphyTopicsSelectorPrivate));
}