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

/*
 *  Copyright (C) 2003 Hiroyuki Ikezoe
 *  Copyright (C) 2003 Takuro Ashie
 *
 *  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-proxy-folder.h"

#include <glib/gi18n.h>

typedef struct _KzProxyFolderPriv KzProxyFolderPriv;
struct _KzProxyFolderPriv
{
	KzBookmarkFolder *folder;
};

#define KZ_PROXY_FOLDER_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), KZ_TYPE_PROXY_FOLDER, KzProxyFolderPriv))

enum {
	PROP_0,
	PROP_KZ_BOOKMARK_FOLDER
};

static GObject *constructor  (GType type,
                              guint n_props,
                              GObjectConstructParam *props);
static void     dispose      (GObject            *object);

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     cb_folder_insert_child	     (KzBookmarkFolder *folder,
					      KzBookmark       *child,
					      KzBookmark       *sibling,
					      KzProxyFolder *proxy);
static void     cb_folder_remove_child       (KzBookmarkFolder *folder,
					      KzBookmark       *child,
					      KzProxyFolder    *proxy);

G_DEFINE_TYPE(KzProxyFolder, kz_proxy_folder, KZ_TYPE_BOOKMARK_FOLDER)

static void
kz_proxy_folder_class_init (KzProxyFolderClass *klass)
{
	GObjectClass *object_class;

	object_class = G_OBJECT_CLASS(klass);

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

	g_object_class_install_property
		(object_class,
		 PROP_KZ_BOOKMARK_FOLDER,
		 g_param_spec_object ("kz-bookmark-folder",
				      _("KzBookmarkFolder"),
				      _("The BookmarkFolder object"),
				      KZ_TYPE_BOOKMARK_FOLDER,
				      G_PARAM_READWRITE |
				      G_PARAM_CONSTRUCT_ONLY));
	g_type_class_add_private (klass, sizeof(KzProxyFolderPriv));
}


static void
kz_proxy_folder_init (KzProxyFolder *proxy)
{
	KzProxyFolderPriv *priv = KZ_PROXY_FOLDER_GET_PRIVATE(proxy);

	priv->folder = NULL;
}


static KzBookmark *
create_current_page_bookmark (KzBookmarkFolder *tab)
{
	KzBookmark *current_page;
	KzBookmark *new;

	current_page = kz_bookmark_folder_get_current_bookmark(tab);

	new = kz_bookmark_new_with_attrs(current_page ? kz_bookmark_get_title(current_page) : "",
					 current_page ? kz_bookmark_get_link(current_page) : "",
					 NULL);
	return new;
}

static void
append_current_page_bookmark (KzBookmark *bookmark, KzProxyFolder *proxy)
{
	KzBookmark *cur_page;
	cur_page = create_current_page_bookmark(KZ_BOOKMARK_FOLDER(bookmark));

	kz_bookmark_folder_append(KZ_BOOKMARK_FOLDER(proxy), cur_page);
	g_object_unref(cur_page);
}

static void
create_proxy_folder (KzProxyFolder *proxy, KzBookmarkFolder *tabs)
{
	kz_bookmark_folder_foreach_child(tabs,
					 (GFunc)append_current_page_bookmark,
					 proxy);
}


static GObject*
constructor (GType type,
             guint n_props,
             GObjectConstructParam *props)
{
	GObject *object;
	GObjectClass *klass = G_OBJECT_CLASS(kz_proxy_folder_parent_class);
	KzProxyFolderPriv *priv;

	object = klass->constructor(type, n_props, props);
	priv = KZ_PROXY_FOLDER_GET_PRIVATE(object);

	/* set signals */
	g_signal_connect(priv->folder, "insert-child",
			 G_CALLBACK(cb_folder_insert_child),
			 object);
	g_signal_connect(priv->folder, "remove-child",
			 G_CALLBACK(cb_folder_remove_child),
			 object);

	return object;
}


static void
dispose (GObject *object)
{
	KzProxyFolderPriv *priv = KZ_PROXY_FOLDER_GET_PRIVATE(object);

	if (priv->folder)
	{
		g_signal_handlers_disconnect_by_func
			(priv->folder,
			 G_CALLBACK(cb_folder_insert_child),
			 object);
		g_signal_handlers_disconnect_by_func
			(priv->folder,
			 G_CALLBACK(cb_folder_remove_child),
			 object);
		g_object_unref(priv->folder);
	}
	priv->folder = NULL;

	if (G_OBJECT_CLASS (kz_proxy_folder_parent_class)->dispose)
		G_OBJECT_CLASS (kz_proxy_folder_parent_class)->dispose(object);
}


static void
set_property (GObject *object,
              guint prop_id,
              const GValue *value,
              GParamSpec *pspec)
{
	KzProxyFolderPriv *priv = KZ_PROXY_FOLDER_GET_PRIVATE(object);
  
	switch (prop_id)
	{
	case PROP_KZ_BOOKMARK_FOLDER:
		priv->folder = g_object_ref(g_value_get_object(value));
		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)
{
	KzProxyFolderPriv *priv = KZ_PROXY_FOLDER_GET_PRIVATE(object);

	switch (prop_id)
	{
	case PROP_KZ_BOOKMARK_FOLDER:
		g_value_set_object(value, priv->folder);
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
		break;
	}
}


KzBookmark *
kz_proxy_folder_new (KzBookmarkFolder *folder)
{
	KzProxyFolder *proxy;

	proxy = g_object_new(KZ_TYPE_PROXY_FOLDER,
			     "title", _("ProxyFolder"),
			     "kz-bookmark-folder", folder,
			     NULL);

	create_proxy_folder(proxy, folder);

	return KZ_BOOKMARK(proxy);
}


static void
cb_folder_insert_child (KzBookmarkFolder *folder,
			KzBookmark *child, KzBookmark *sibling,
			KzProxyFolder *proxy)
{
	KzBookmark *new;
	KzProxyFolderPriv *priv = KZ_PROXY_FOLDER_GET_PRIVATE(proxy);

	new = create_current_page_bookmark(KZ_BOOKMARK_FOLDER(child));

	if (sibling)
	{
		gint index;

		index = kz_bookmark_folder_get_child_index(priv->folder, sibling);
		if (index >= 0)
		{
			KzBookmark *sib;
			sib = kz_bookmark_folder_get_nth_child(KZ_BOOKMARK_FOLDER(proxy),
							       index);
			kz_bookmark_folder_insert_before(KZ_BOOKMARK_FOLDER(proxy),
						  	 new, sib);
		}
	}
	else
	{
		kz_bookmark_folder_prepend(KZ_BOOKMARK_FOLDER(proxy), new);
	}
	g_object_unref(new);
}


static void
cb_folder_remove_child (KzBookmarkFolder *folder,
			KzBookmark *child, 
			KzProxyFolder *proxy) 
{
	gint index;
	KzProxyFolderPriv *priv = KZ_PROXY_FOLDER_GET_PRIVATE(proxy);

	index = kz_bookmark_folder_get_child_index(priv->folder, child);

	if (index >= 0)
	{
		KzBookmark *remove;

		remove = kz_bookmark_folder_get_nth_child(KZ_BOOKMARK_FOLDER(proxy), index);
		kz_bookmark_folder_remove(KZ_BOOKMARK_FOLDER(proxy), remove);
	}
}


KzBookmark *
kz_proxy_folder_get_original_bookmark (KzProxyFolder *proxy,
				       KzBookmark *bookmark)
{
	gint index;
	KzProxyFolderPriv *priv = KZ_PROXY_FOLDER_GET_PRIVATE(proxy);

	index = kz_bookmark_folder_get_child_index(KZ_BOOKMARK_FOLDER(proxy), bookmark);

	return (index >= 0) ? kz_bookmark_folder_get_nth_child(priv->folder, index) : NULL;
}

KzBookmark *
kz_proxy_folder_get_original_bookmark_from_index (KzProxyFolder *proxy,
				                  gint index)
{
	KzProxyFolderPriv *priv = KZ_PROXY_FOLDER_GET_PRIVATE(proxy);

	return kz_bookmark_folder_get_nth_child(priv->folder, index);
}

