/* -*- 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.
 *
 *  $Id: kz-bookmark.c 3704 2009-02-15 11:43:24Z ikezoe $
 */

#include "kz-bookmark.h"

#include <string.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include "glib-utils.h"
#include "kz-marshalers.h"
#include "utils.h"
#include "kz-bookmark-file.h"
#include "kz-bookmark-folder.h"
#include "kz-bookmark-separator.h"
#include "kz-bookmarks-enum-types.h"

enum {
	PROP_0,
	PROP_TITLE,
	PROP_ID,
	PROP_LINK,
	PROP_DESCRIPTION,
	PROP_LAST_MODIFIED,
	PROP_LAST_VISITED,
	PROP_ADDED_TIME,
	PROP_INTERVAL
};


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 GQuark id_quark                = 0;
static GQuark title_quark             = 0;
static GQuark link_quark              = 0;
static GQuark description_quark       = 0;
static GQuark last_mod_quark          = 0;
static GQuark last_visited_quark      = 0;
static GQuark added_time_quark        = 0;
static GQuark parent_quark            = 0;

G_DEFINE_TYPE(KzBookmark, kz_bookmark, G_TYPE_OBJECT)

static void
kz_bookmark_class_init (KzBookmarkClass *klass)
{
	GObjectClass *object_class;

	object_class = G_OBJECT_CLASS(klass);

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

	g_object_class_install_property(
		object_class,
		 PROP_ID,
		 g_param_spec_string(
			 "id",
			 _("ID"),
			 _("The ID of the bookmark"),
			 NULL,
			 G_PARAM_READWRITE));

	g_object_class_install_property(
		object_class,
		 PROP_TITLE,
		 g_param_spec_string(
			 "title",
			 _("Title"),
			 _("The title of the bookmark"),
			 NULL,
			 G_PARAM_READWRITE));

	g_object_class_install_property(
		object_class,
		 PROP_LINK,
		 g_param_spec_string(
			 "link",
			 _("Link"),
			 _("The URI of the link"),
			 NULL,
			 G_PARAM_READWRITE));

	g_object_class_install_property(
		object_class,
		 PROP_DESCRIPTION,
		 g_param_spec_string(
			 "description",
			 _("Description"),
			 _("The description of the bookmark"),
			 NULL,
			 G_PARAM_READWRITE));

	g_object_class_install_property(
		object_class,
		 PROP_LAST_MODIFIED,
		 g_param_spec_uint(
			 "last-modified",
			 _("Last Modified"),
			 _("Last modification time of the link"),
			 0,
			 G_MAXUINT,
			 0,
			 G_PARAM_READWRITE));

	g_object_class_install_property(
		object_class,
		 PROP_LAST_VISITED,
		 g_param_spec_uint(
			 "last-visited",
			 _("Last Visited Time"),
			 _("The time of the user's last visit to the link"),
			 0,
			 G_MAXUINT,
			 0,
			 G_PARAM_READWRITE));

	g_object_class_install_property(
		object_class,
		 PROP_ADDED_TIME,
		 g_param_spec_uint(
			 "added-time",
			 _("Added Time"),
			 _("The time of the added the bookmark"),
			 0,
			 G_MAXUINT,
			 0,
			 G_PARAM_READWRITE));


	/* FIXME! add other properties */
	/*
	 * candidates:
	 * 
	 *   * ID
	 *   * Last-Accessed time
	 *   * frequency
	 *   * ......
	 */

	id_quark           = g_quark_from_string("KzBookmark::ID");
	title_quark        = g_quark_from_string("KzBookmark::Title");
	link_quark         = g_quark_from_string("KzBookmark::Link");
	description_quark  = g_quark_from_string("KzBookmark::Description");
	last_mod_quark     = g_quark_from_string("KzBookmark::LastModified");
	last_visited_quark = g_quark_from_string("KzBookmark::LastVisited");
	added_time_quark   = g_quark_from_string("KzBookmark::AddedTime");
	parent_quark       = g_quark_from_string("KzBookmark::Parent");
}

static void
kz_bookmark_init (KzBookmark *bookmark)
{
}


static void
dispose (GObject *object)
{
	if (G_OBJECT_CLASS (kz_bookmark_parent_class)->dispose)
		G_OBJECT_CLASS (kz_bookmark_parent_class)->dispose(object);
}


static void
set_property (GObject *object,
              guint prop_id,
              const GValue *value,
              GParamSpec *pspec)
{
	KzBookmark *bookmark = KZ_BOOKMARK(object);

	switch (prop_id) {
	case PROP_ID:
		g_return_if_fail(!kz_bookmark_is_separator(bookmark));
		kz_bookmark_set_id(bookmark, g_value_get_string(value));
		break;
	case PROP_TITLE:
		kz_bookmark_set_title(bookmark, g_value_get_string(value));
		break;
	case PROP_LINK:
		g_return_if_fail(!kz_bookmark_is_separator(bookmark));
		kz_bookmark_set_link(bookmark, g_value_get_string(value));
		break;
	case PROP_DESCRIPTION:
		g_return_if_fail(!kz_bookmark_is_separator(bookmark));
		kz_bookmark_set_description(bookmark, g_value_get_string(value));
		break;
	case PROP_LAST_MODIFIED:
		g_return_if_fail(!kz_bookmark_is_separator(bookmark));
                kz_bookmark_set_last_modified(bookmark, g_value_get_uint(value));
		break;
	case PROP_LAST_VISITED:
		g_return_if_fail(!kz_bookmark_is_separator(bookmark));
		kz_bookmark_set_last_visited(bookmark ,g_value_get_uint(value));
		break;
	case PROP_ADDED_TIME:
		g_return_if_fail(!kz_bookmark_is_separator(bookmark));
		kz_bookmark_set_added_time(bookmark ,g_value_get_uint(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)
{
	gchar *str;
	guint time;

	switch (prop_id) {
	case PROP_ID:
		str = g_object_get_qdata(object, id_quark);
		g_value_set_string(value, str);
		break;
	case PROP_TITLE:
		str = g_object_get_qdata(object, title_quark);
		g_value_set_string(value, str);
		break;
	case PROP_LINK:
		str = g_object_get_qdata(object, link_quark);
		g_value_set_string(value, str);
		break;
	case PROP_DESCRIPTION:
		str = g_object_get_qdata(object, description_quark);
		g_value_set_string(value, str);
		break;
	case PROP_LAST_MODIFIED:
		time = GPOINTER_TO_UINT(g_object_get_qdata(object,
							   last_mod_quark));
		g_value_set_uint(value, time);
		break;
	case PROP_LAST_VISITED:
		time = GPOINTER_TO_UINT(g_object_get_qdata(object,
							   last_visited_quark));
		g_value_set_uint(value, time);
		break;
	case PROP_ADDED_TIME:
		time = GPOINTER_TO_UINT(g_object_get_qdata(object,
							   added_time_quark));
		g_value_set_uint(value, time);
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
		break;
	}
}


KzBookmark *
kz_bookmark_new (void)
{
	KzBookmark *bookmark = g_object_new(KZ_TYPE_BOOKMARK,
					    NULL);
	return bookmark;
}

KzBookmark *
kz_bookmark_new_with_attrs (const gchar *title,
			    const gchar *uri,
			    const gchar *description)
{
	KzBookmark *bookmark;

	bookmark = g_object_new(KZ_TYPE_BOOKMARK,
			        "title",       title,
				"link",        uri,
				"description", description,
				NULL);
	return bookmark;
}


const gchar *
kz_bookmark_get_id (KzBookmark *bookmark)
{
	g_return_val_if_fail(KZ_IS_BOOKMARK(bookmark), NULL);
	return g_object_get_qdata(G_OBJECT(bookmark), id_quark);
}


const gchar *
kz_bookmark_get_title (KzBookmark *bookmark)
{
	g_return_val_if_fail(KZ_IS_BOOKMARK(bookmark), NULL);
	return g_object_get_qdata(G_OBJECT(bookmark), title_quark);
}


const gchar *
kz_bookmark_get_link (KzBookmark *bookmark)
{
	g_return_val_if_fail(KZ_IS_BOOKMARK(bookmark), NULL);
	return g_object_get_qdata(G_OBJECT(bookmark), link_quark);
}


const gchar *
kz_bookmark_get_description (KzBookmark *bookmark)
{
	g_return_val_if_fail(KZ_IS_BOOKMARK(bookmark), NULL);
	return g_object_get_qdata(G_OBJECT(bookmark), description_quark);
}


guint
kz_bookmark_get_last_modified (KzBookmark *bookmark)
{
	g_return_val_if_fail(KZ_IS_BOOKMARK(bookmark), 0);
	return GPOINTER_TO_UINT(g_object_get_qdata(G_OBJECT(bookmark),
						   last_mod_quark));
}

guint
kz_bookmark_get_last_visited (KzBookmark *bookmark)
{
	g_return_val_if_fail(KZ_IS_BOOKMARK(bookmark), 0);
	return GPOINTER_TO_UINT(g_object_get_qdata(G_OBJECT(bookmark),
						   last_visited_quark));
}

guint
kz_bookmark_get_added_time (KzBookmark *bookmark)
{
	g_return_val_if_fail(KZ_IS_BOOKMARK(bookmark), 0);
	return GPOINTER_TO_UINT(g_object_get_qdata(G_OBJECT(bookmark),
						   added_time_quark));
}


gboolean
kz_bookmark_is_editable (KzBookmark *bookmark)
{
	KzBookmark *parent_file;

	g_return_val_if_fail(KZ_IS_BOOKMARK(bookmark), FALSE);

	parent_file = kz_bookmark_get_parent_file(bookmark);

	if (!parent_file) return FALSE;

	if (!kz_bookmark_file_is_editable(KZ_BOOKMARK_FILE(parent_file)))
		return FALSE;

	return TRUE;
}

#define CHANGE_STR(obj, quark, value) \
{ \
	g_object_set_qdata_full(G_OBJECT((obj)), (quark), g_strdup((value)), \
				(GDestroyNotify) g_free); \
}

void
kz_bookmark_set_id (KzBookmark *bookmark,
		    const gchar *id)
{
	g_return_if_fail(KZ_IS_BOOKMARK(bookmark));
	CHANGE_STR(bookmark, id_quark, id);
	g_object_notify(G_OBJECT(bookmark), "id");
}


void
kz_bookmark_set_title (KzBookmark *bookmark,
		       const gchar *title)
{
	g_return_if_fail(KZ_IS_BOOKMARK(bookmark));
	CHANGE_STR(bookmark, title_quark, title);
	g_object_notify(G_OBJECT(bookmark), "title");
}


void
kz_bookmark_set_link (KzBookmark *bookmark,
		      const gchar *uri)
{
	g_return_if_fail(KZ_IS_BOOKMARK(bookmark));
	CHANGE_STR(bookmark, link_quark, uri);
	g_object_notify(G_OBJECT(bookmark), "link");
}


void
kz_bookmark_set_description (KzBookmark *bookmark,
			     const gchar *description)
{
	g_return_if_fail(KZ_IS_BOOKMARK(bookmark));
	CHANGE_STR(bookmark, description_quark, description);
	g_object_notify(G_OBJECT(bookmark), "description");
}


void
kz_bookmark_set_last_modified (KzBookmark *bookmark,
			       guint time)
{
	g_return_if_fail(KZ_IS_BOOKMARK(bookmark));
	g_object_set_qdata(G_OBJECT(bookmark), last_mod_quark,
			   GUINT_TO_POINTER(time));
	g_object_notify(G_OBJECT(bookmark), "last-modified");
}

void
kz_bookmark_set_last_visited (KzBookmark *bookmark,
			      guint time)
{
	g_return_if_fail(KZ_IS_BOOKMARK(bookmark));
	g_object_set_qdata(G_OBJECT(bookmark), last_visited_quark,
			   GUINT_TO_POINTER(time));
	g_object_notify(G_OBJECT(bookmark), "last-visited");
}

void
kz_bookmark_set_added_time (KzBookmark *bookmark,
		            guint time)
{
	g_return_if_fail(KZ_IS_BOOKMARK(bookmark));
	g_object_set_qdata(G_OBJECT(bookmark), added_time_quark,
			   GUINT_TO_POINTER(time));
	g_object_notify(G_OBJECT(bookmark), "added-time");
}

KzBookmarkFolder *
kz_bookmark_get_parent (KzBookmark *bookmark)
{
	g_return_val_if_fail(KZ_IS_BOOKMARK(bookmark), NULL);

	return g_object_get_qdata(G_OBJECT(bookmark), parent_quark);
}

void
kz_bookmark_set_parent (KzBookmark *bookmark, KzBookmarkFolder *parent)
{
	g_return_if_fail(KZ_IS_BOOKMARK_FOLDER(parent));

	g_object_set_qdata(G_OBJECT(bookmark), parent_quark, parent);
}

KzBookmark *
kz_bookmark_get_parent_file (KzBookmark *bookmark)
{
	KzBookmark *child = bookmark;
        KzBookmarkFolder *parent;

	g_return_val_if_fail(KZ_IS_BOOKMARK(bookmark), NULL);

        while (TRUE)
	{
                parent = kz_bookmark_get_parent(child);
                if (!parent)
                        return NULL;
		if (KZ_IS_BOOKMARK_FILE(parent))
			return KZ_BOOKMARK(parent);
                child = KZ_BOOKMARK(parent);
	}

	return NULL;
}

KzBookmark *
kz_bookmark_next (KzBookmark *bookmark)
{
	KzBookmarkFolder *parent;
	GList *children, *node;

	g_return_val_if_fail(KZ_IS_BOOKMARK(bookmark), NULL);

	parent = kz_bookmark_get_parent(bookmark);
	if (!parent) return NULL;

	children = kz_bookmark_folder_get_children(parent);
	node = g_list_find(children, bookmark);
	if (node && (node = g_list_next(node)))
		return node->data;

	return NULL;
}


KzBookmark *
kz_bookmark_prev (KzBookmark  *bookmark)
{
	KzBookmarkFolder *parent;
	GList *children, *node;

	g_return_val_if_fail(KZ_IS_BOOKMARK(bookmark), NULL);

	parent = kz_bookmark_get_parent(bookmark);
	if (!parent) return NULL;

	children = kz_bookmark_folder_get_children(parent);
	node = g_list_find(children, bookmark);
	if (node && (node = g_list_previous(node)))
		return node->data;

	return NULL;
}

