/*
 *  Copyright (C) 2002  Ricardo Fernández Pascual
 *
 *  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.
 */

#ifndef __bookmarks_h
#define __bookmarks_h


#include <glib-object.h>
#include <gtk/gtkwidget.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <libxml/tree.h>


G_BEGIN_DECLS

/* object forward declarations */

typedef struct _GbBookmark GbBookmark;
typedef struct _GbBookmarkClass GbBookmarkClass;
typedef struct _GbSite GbSite;
typedef struct _GbSiteClass GbSiteClass;
typedef struct _GbSmartSite GbSmartSite;
typedef struct _GbSmartSiteClass GbSmartSiteClass;
typedef struct _GbFolder GbFolder;
typedef struct _GbFolderClass GbFolderClass;
typedef struct _GbSeparator GbSeparator;
typedef struct _GbSeparatorClass GbSeparatorClass;
typedef struct _GbAutoFolder GbAutoFolder;
typedef struct _GbAutoFolderClass GbAutoFolderClass;
typedef struct _GbAliasPlaceholder GbAliasPlaceholder;
typedef struct _GbAliasPlaceholderClass GbAliasPlaceholderClass;
typedef struct _GbBookmarkSet GbBookmarkSet;
typedef struct _GbBookmarkSetClass GbBookmarkSetClass;
typedef struct _GbIO GbIO;
typedef struct _GbIOClass GbIOClass;
typedef struct _GbTbWidget GbTbWidget;
typedef struct _GbIconProvider GbIconProvider;

/**
 * General functions that affect the bookmark system.
 */
void			gb_system_set_icon_provider	(GbIconProvider *ip);
GbIconProvider *	gb_system_get_icon_provider	(void);

/**
 * Bookmark object
 */

#define GB_TYPE_BOOKMARK		(gb_bookmark_get_type())
#define GB_BOOKMARK(object)		(G_TYPE_CHECK_INSTANCE_CAST((object), GB_TYPE_BOOKMARK,\
					 GbBookmark))
#define GB_BOOKMARK_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST((klass), GB_TYPE_BOOKMARK,\
					 GbBookmarkClass))
#define GB_IS_BOOKMARK(object)		(G_TYPE_CHECK_INSTANCE_TYPE((object), GB_TYPE_BOOKMARK))
#define GB_IS_BOOKMARK_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE((klass), GB_TYPE_BOOKMARK))
#define GB_BOOKMARK_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS((obj), GB_TYPE_BOOKMARK,\
					 GbBookmarkClass))

struct _GbBookmarkClass 
{
	GObjectClass parent_class;

	/* virtual methods */
	void		(*gb_bookmark_set_set)		(GbBookmark *b, GbBookmarkSet *set);
	GbBookmark *	(*gb_bookmark_copy)		(GbBookmark *b);
	GbBookmark *	(*gb_bookmark_alias_create)	(GbBookmark *b, GbAliasPlaceholder *ap);
	GbTbWidget *	(*gb_bookmark_create_toolbar_widget) (GbBookmark *b);

	/* signals */
	void		(*gb_bookmark_modified)		(GbBookmark *b);
	void		(*gb_bookmark_name_modified)	(GbBookmark *b, const gchar *new_name);
};

/* Remember: fields are public read-only */
struct _GbBookmark
{
	GObject parent_object;

	/* the BookmarkSet that owns this bookmark */
	GbBookmarkSet *set;

	/* parent folder (NULL for root bookmark) */
	GbFolder *parent; 

	/* the next and prev bookmark (brothers) */
	GbBookmark *next;
	GbBookmark *prev;

	/* if not NULL, then this is an alias. The pointed bookmark can be an
	 * alias too */
        GbBookmark *alias_of;

	/* Points to the first alias of this bookmark, if any. If the 
	 * bookmark is an alias, then it points to the next alias */
	GbBookmark *alias;

	/* unique identifier (for the same GbBookmarkSet) */
	gchar *id;

	/* the user visible name of the bookmark */
	/* (an empty string if it doesn't make sense for this type of bookmark) */
	gchar *name;

	/* nickname used as a shorthand for this bookmark */
	gchar *nick;
	
	/* the pixmap file used to represent it */
	gchar *pixmap_file;

	/* the in-memory binary data of the pixmap */
	/* GdkPixbuf *pixbuf_data; */

	/* xbel node of the bookmark, may be NULL */
	xmlNodePtr xbel_node;

	/* any user provided comments about the bookmark */
	gchar *notes; 

	/* if TRUE, we add this bookmark to the document context menu */
	gboolean add_to_context_menu;
	
	/* time info (if they are 0, then they should be ignored) */
	GTime time_added;
	GTime time_modified;
};

GType		gb_bookmark_get_type			(void);
void		gb_bookmark_set_id			(GbBookmark *b, const gchar *val);
void		gb_bookmark_set_xbel_node		(GbBookmark *b, xmlNodePtr node);
void		gb_bookmark_set_name			(GbBookmark *b, const gchar *val);
void		gb_bookmark_set_nick			(GbBookmark *b, const gchar *val);
void 		gb_bookmark_set_notes	 		(GbBookmark *b, const gchar *val);
void 		gb_bookmark_set_pixmap		 	(GbBookmark *b, const gchar *val);
void 		gb_bookmark_set_add_to_context_menu	(GbBookmark *b, gboolean val);
void 		gb_bookmark_set_time_added	 	(GbBookmark *b, GTime val);
void 		gb_bookmark_set_time_added_now	 	(GbBookmark *b);
void 		gb_bookmark_set_time_modified 		(GbBookmark *b, GTime val);
void 		gb_bookmark_set_time_modified_now	(GbBookmark *b);
void 		gb_bookmark_unparent	 		(GbBookmark *b);
void		gb_bookmark_unparent_safe		(GbBookmark *b);
GbBookmark *	gb_bookmark_copy			(GbBookmark *b);
GbBookmark *	gb_bookmark_real_bookmark		(GbBookmark *b);
void		gb_bookmark_alias_make_real		(GbBookmark *alias);
GbBookmark *	gb_bookmark_alias_create		(GbBookmark *b, GbAliasPlaceholder *ap);
GbTbWidget *	gb_bookmark_create_toolbar_widget	(GbBookmark *b);
GdkPixbuf *	gb_bookmark_get_icon			(GbBookmark *b);
GdkPixbuf *	gb_bookmark_get_image			(GbBookmark *b);
#define gb_bookmark_is_alias(b) (((GbBookmark *) b)->alias_of != NULL)
#define gb_bookmark_has_alias(b) (((GbBookmark *) b)->alias != NULL)
void		gb_bookmark_emit_changed		(GbBookmark *b);
GbBookmark *	gb_bookmark_add_alias_under		(GbBookmark *b, GbFolder *newparent);
GbBookmark *	gb_bookmark_ensure_alias_under		(GbBookmark *b, GbFolder *newparent);
GSList *	gb_bookmark_get_all_alias_parents	(GbBookmark *b);

/**
 * Site object
 */ 

#define GB_TYPE_SITE			(gb_site_get_type())
#define GB_SITE(object)			(G_TYPE_CHECK_INSTANCE_CAST((object), GB_TYPE_SITE, GbSite))
#define GB_SITE_CLASS(klass) 		(G_TYPE_CHECK_CLASS_CAST((klass), GB_TYPE_SITE, GbSiteClass))
#define GB_IS_SITE(object)		(G_TYPE_CHECK_INSTANCE_TYPE((object), GB_TYPE_SITE))
#define GB_IS_SITE_CLASS(klass) 	(G_TYPE_CHECK_CLASS_TYPE((klass), GB_TYPE_SITE))
#define GB_SITE_GET_CLASS(obj) 		(G_TYPE_INSTANCE_GET_CLASS((obj), GB_TYPE_SITE,\
					 GbSiteClass))

struct _GbSiteClass 
{
	GbBookmarkClass parent_class;

	/* signals */
	void		(*gb_site_url_modified)		(GbSite *b, const gchar *new_url);
};

struct _GbSite 
{
	GbBookmark parent_object;

	/* the site it points at */
	gchar *url;

	/* accel data */
	guint accel_key;
	guint accel_mods;

	/* time info */
	GTime time_visited;
};

GType		gb_site_get_type		(void);
GbSite *	gb_site_new			(GbBookmarkSet *set, const char *name, 
						 const char *url);
void 		gb_site_set_url			(GbSite *b, const char *val);
void		gb_site_set_time_visited 	(GbSite *b, GTime val);
void		gb_site_set_time_visited_now	(GbSite *b);
void		gb_site_set_accel		(GbSite *b, guint accel_key, guint accel_mods);

/**
 * SmartSite object
 */

#define GB_TYPE_SMART_SITE		(gb_smart_site_get_type())
#define GB_SMART_SITE(object)		(G_TYPE_CHECK_INSTANCE_CAST((object), GB_TYPE_SMART_SITE,\
					 GbSmartSite))
#define GB_SMART_SITE_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST((klass), GB_TYPE_SMART_SITE,\
					 GbSmartSiteClass))
#define GB_IS_SMART_SITE(object) 	(G_TYPE_CHECK_INSTANCE_TYPE((object), GB_TYPE_SMART_SITE))
#define GB_IS_SMART_SITE_CLASS(klass)	 (G_TYPE_CHECK_CLASS_TYPE((klass), GB_TYPE_SMART_SITE))
#define GB_SMART_SITE_GET_CLASS(obj) 	(G_TYPE_INSTANCE_GET_CLASS((obj), GB_TYPE_SMART_SITE,\
					 GbSmartSiteClass))

struct _GbSmartSiteClass
{
	GbSiteClass parent_class;

	/* signals */
	void		(*gb_smart_site_visibility_changed)	(GbSmartSite *b);
	void		(*gb_smart_site_entry_width_changed)	(GbSmartSite *b, gint index, gint width);
	void		(*gb_smart_site_history_changed)	(GbSmartSite *b);
};

struct _GbSmartSite
{
	GbSite parent_object;
	/* smart url for smart bookmark */
	gboolean folded;

	/* private */
	gchar *smarturl;
	gint *entries_sizes;
	GSList *history;
};

GType 		gb_smart_site_get_type		(void);
GbSmartSite *	gb_smart_site_new		(GbBookmarkSet *set, const char *name, 
						 const char *url, const char *smarturl);
GbSmartSite *	gb_smart_site_new_from_site	(GbSite *site, const char *smarturl);
void 		gb_smart_site_set_smarturl	(GbSmartSite *b, const gchar *val);
gchar *		gb_smart_site_get_smarturl	(GbSmartSite *b);
gint 		gb_smart_site_get_num_fields	(GbSmartSite *b);
gint		gb_smart_site_get_entry_size	(GbSmartSite *b, int index);
void		gb_smart_site_set_entry_size	(GbSmartSite *b, gint index, gint width);
void 		gb_smart_site_set_folded	(GbSmartSite *b, gboolean folded);
gchar *		gb_smart_site_subst_args	(GbSmartSite *b, gchar **args);
gchar *		gb_smart_site_get_encoding	(GbSmartSite *b);
void		gb_smart_site_set_encoding	(GbSmartSite *b, const gchar *encoding);
GSList *	gb_smart_site_get_history	(GbSmartSite *b, int entry_index);
void		gb_smart_site_set_history	(GbSmartSite *b, int entry_index, const GSList *history);
void		gb_smart_site_prepend_history	(GbSmartSite *b, int entry_index, const gchar *item);

/**
 * Folder object
 */

#define GB_TYPE_FOLDER			(gb_folder_get_type())
#define GB_FOLDER(object)		(G_TYPE_CHECK_INSTANCE_CAST((object), GB_TYPE_FOLDER,\
					 GbFolder))
#define GB_FOLDER_CLASS(klass) 		(G_TYPE_CHECK_CLASS_CAST((klass), GB_TYPE_FOLDER,\
					 GbFolderClass))
#define GB_IS_FOLDER(object) 		(G_TYPE_CHECK_INSTANCE_TYPE((object), GB_TYPE_FOLDER))
#define GB_IS_FOLDER_CLASS(klass) 	(G_TYPE_CHECK_CLASS_TYPE((klass), GB_TYPE_FOLDER))
#define GB_FOLDER_GET_CLASS(obj) 	(G_TYPE_INSTANCE_GET_CLASS((obj), GB_TYPE_FOLDER,\
					 GbFolderClass))

struct _GbFolderClass 
{
	GbBookmarkClass parent_class;

	/* signals */
	void		(*gb_folder_child_modified)	(GbFolder *f, GbBookmark *c);
	void		(*gb_folder_child_added)	(GbFolder *f, GbBookmark *c, gint position);
	void		(*gb_folder_child_removed)	(GbFolder *f, GbBookmark *c, gint position);
	void		(*gb_folder_descendant_modified) (GbFolder *f, GbBookmark *b);
	void		(*gb_folder_descendant_added)	(GbFolder *f, GbFolder *p, GbBookmark *c, 
							 gint position);
	void		(*gb_folder_descendant_removed)	(GbFolder *f, GbFolder *p, GbBookmark *c, 
							 gint position);
	
};

struct _GbFolder
{
	GbBookmark parent_object;

	/* the first child */
	GbBookmark *child;

	/* if TRUE create a toolbar from it */
	gboolean create_toolbar; 

	/* if TRUE then it was shown open in the editor last time */
	gboolean expanded; 

	/* toolbar style (FIXME: does this need to be here?) */ 
	/* GtkToolbarStyle toolbar_style; */
};

GType 		gb_folder_get_type			(void);
GbFolder *	gb_folder_new				(GbBookmarkSet *set, const gchar *name);
void 		gb_folder_set_create_toolbar		(GbFolder *b, gboolean val);
void		gb_folder_set_expanded			(GbFolder *b, gboolean val);
/* void		gb_folder_set_toolbar_style	 	(BookmarkItem *b, GtkToolbarStyle val); */
void		gb_folder_add_child			(GbFolder *p, GbBookmark *c, gint position);
void		gb_folder_move_child	 			(GbFolder *p, GbBookmark *c, gint position);
gint		gb_folder_get_child_index		(GbFolder *p, GbBookmark *b);
gboolean	gb_folder_is_ancestor			(GbFolder *p, GbBookmark *b);
gboolean 	gb_folder_is_default_folder		(GbFolder *f);
GSList * 	gb_folder_list_children			(GbFolder *f);
void		gb_folder_sort				(GbFolder *f, gboolean folders_first, 
							 gboolean recursive);
gboolean 	gb_folder_has_child_or_alias		(GbFolder *f, GbBookmark *c);
void	 	gb_folder_remove_child_or_aliases	(GbFolder *f, GbBookmark *c);

/**
 * Separator object
 */

#define GB_TYPE_SEPARATOR		(gb_separator_get_type())
#define GB_SEPARATOR(object) 		(G_TYPE_CHECK_INSTANCE_CAST((object), GB_TYPE_SEPARATOR,\
					 GbSeparator))
#define GB_SEPARATOR_CLASS(klass) 	(G_TYPE_CHECK_CLASS_CAST((klass), GB_TYPE_SEPARATOR,\
					 GbSeparatorClass))
#define GB_IS_SEPARATOR(object) 	(G_TYPE_CHECK_INSTANCE_TYPE((object), GB_TYPE_SEPARATOR))
#define GB_IS_SEPARATOR_CLASS(klass) 	(G_TYPE_CHECK_CLASS_TYPE((klass), GB_TYPE_SEPARATOR))
#define GB_SEPARATOR_GET_CLASS(obj) 	(G_TYPE_INSTANCE_GET_CLASS((obj), GB_TYPE_SEPARATOR,\
					 GbSeparatorClass))

struct _GbSeparatorClass 
{
	GbBookmarkClass parent_class;
};

struct _GbSeparator
{
	GbBookmark parent_object;
};

GType		gb_separator_get_type	(void);
GbSeparator *	gb_separator_new 	(GbBookmarkSet *set);

/**
 * AutoFolder object
 */

#define GB_TYPE_AUTO_FOLDER 		(gb_auto_folder_get_type())
#define GB_AUTO_FOLDER(object) 		(G_TYPE_CHECK_INSTANCE_CAST((object), GB_TYPE_AUTO_FOLDER,\
					 GbAutoFolder))
#define GB_AUTO_FOLDER_CLASS(klass) 	(G_TYPE_CHECK_CLASS_CAST((klass), GB_TYPE_AUTO_FOLDER,\
					 GbAutoFolderClass))
#define GB_IS_AUTO_FOLDER(object) 	(G_TYPE_CHECK_INSTANCE_TYPE((object), \
					 GB_TYPE_AUTO_FOLDER))
#define GB_IS_AUTO_FOLDER_CLASS(klass) 	(G_TYPE_CHECK_CLASS_TYPE((klass), GB_TYPE_AUTO_FOLDER))
#define GB_AUTO_FOLDER_GET_CLASS(obj) 	(G_TYPE_INSTANCE_GET_CLASS((obj), GB_TYPE_AUTO_FOLDER,\
					 GbAutoFolderClass))

struct _GbAutoFolderClass 
{
	GbFolderClass parent_class;
};

struct _GbAutoFolder
{
	GbFolder parent_object;
};

GType		gb_auto_folder_get_type	(void);
GbAutoFolder *	gb_auto_folder_new	(GbBookmarkSet *set, const gchar *name);
void		gb_auto_folder_refresh	(void);

/**
 * AliasPlaceholder object
 */

#define GB_TYPE_ALIAS_PLACEHOLDER	(gb_alias_placeholder_get_type ())
#define GB_ALIAS_PLACEHOLDER(object)	(G_TYPE_CHECK_INSTANCE_CAST((object), GB_TYPE_ALIAS_PLACEHOLDER,\
					 GbAliasPlaceholder))
#define GB_ALIAS_PLACEHOLDER_CLASS(klass) \
					(G_TYPE_CHECK_CLASS_CAST((klass), GB_TYPE_ALIAS_PLACEHOLDER,\
					 GbAliasPlaceholderClass))
#define GB_IS_ALIAS_PLACEHOLDER(object)	(G_TYPE_CHECK_INSTANCE_TYPE((object), GB_TYPE_ALIAS_PLACEHOLDER))
#define GB_IS_ALIAS_PLACEHOLDER_CLASS(klass) \
					(G_TYPE_CHECK_CLASS_TYPE((klass), GB_TYPE_ALIAS_PLACEHOLDER))
#define GB_ALIAS_PLACEHOLDER_GET_CLASS(obj) \
					(G_TYPE_INSTANCE_GET_CLASS((obj), GB_TYPE_ALIAS_PLACEHOLDER,\
					 GbAliasPlaceholderClass))

struct _GbAliasPlaceholderClass 
{
	GbBookmarkClass parent_class;
};

struct _GbAliasPlaceholder
{
	GbBookmark parent_object;
	
	char *alias_of_id;
	
	/* data that may be different betwen a bookmark and it's alias and it's 
	   not in GbBookmark */
	
	gboolean create_toolbar; 

	
};

GType		gb_alias_placeholder_get_type	(void);
GbAliasPlaceholder *gb_alias_placeholder_new	(GbBookmarkSet *set, const char *alias_of_id);
void		gb_alias_placeholder_set_create_toolbar (GbAliasPlaceholder *ap, gboolean val);
gboolean	gb_alias_placeholder_resolve	(GbAliasPlaceholder *ap);

/**
 * BookmarkSet object
 */

#define GB_TYPE_BOOKMARK_SET		(gb_bookmark_set_get_type())
#define GB_BOOKMARK_SET(object)		(G_TYPE_CHECK_INSTANCE_CAST((object), GB_TYPE_BOOKMARK_SET,\
					 GbBookmarkSet))
#define GB_BOOKMARK_SET_CLASS(klass) 	(G_TYPE_CHECK_CLASS_CAST((klass), GB_TYPE_BOOKMARK_SET,\
					 GbBookmarkSetClass))
#define GB_IS_BOOKMARK_SET(object)	(G_TYPE_CHECK_INSTANCE_TYPE((object), GB_TYPE_BOOKMARK_SET))
#define GB_IS_BOOKMARK_SET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GB_TYPE_BOOKMARK_SET))
#define GB_BOOKMARK_SET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GB_TYPE_BOOKMARK_SET,\
					 GbBookmarkSetClass))

struct _GbBookmarkSetClass 
{
	GObjectClass parent_class;

	/* Signals */
	void		(*gb_bookmark_set_toolbar)		(GbBookmarkSet *set, GbFolder *f);
	void		(*gb_bookmark_set_context_menu)		(GbBookmarkSet *set);
};

typedef enum
{
	GB_FILE_FORMAT_VERSION_UNKNOWN = 0,
	GB_FILE_FORMAT_VERSION_GALEON_1,
	GB_FILE_FORMAT_VERSION_GALEON_2
} GbFileFormatVersion;

struct _GbBookmarkSet
{
	GObject parent_object;
	GbFolder *root;
	GbFolder *default_folder;

	GHashTable *id_to_bookmark;
	GHashTable *url_to_bookmark;

	GSList *unresolved_aliases;

	xmlDocPtr xbel_doc;

/*
	GSList *undo_queue;
	GSList *redo_queue;
*/
	GSList *toolbars;

	/* all bookmarks in preorder, or NULL */
	GSList *all_bookmarks;
	GSList *all_bookmarks_noalias;
	GSList *context_bookmarks;

	GbIO *io;
	gchar *filename;
	GbFileFormatVersion file_format_version;
	gboolean needs_saving;
	guint autosave_timeout_id;

	guint max_smart_site_history_items;
};

GType		gb_bookmark_set_get_type		(void);
GbBookmarkSet *	gb_bookmark_set_new			(void);
void		gb_bookmark_set_set_io			(GbBookmarkSet *set, GbIO *io);
void		gb_bookmark_set_set_xbel_doc		(GbBookmarkSet *set, xmlDocPtr doc);
void		gb_bookmark_set_discard_xml_nodes	(GbBookmarkSet *set);
void		gb_bookmark_set_set_filename		(GbBookmarkSet *set, const gchar *filename);
gboolean	gb_bookmark_set_check_save		(GbBookmarkSet *set);
void		gb_bookmark_set_set_root		(GbBookmarkSet *set, GbFolder *root);
void		gb_bookmark_set_set_default_folder	(GbBookmarkSet *set, GbFolder *default_folder);
void		gb_bookmark_set_resolve_aliases		(GbBookmarkSet *set);
GSList *	gb_bookmark_set_get_toolbars	 	(GbBookmarkSet *set);
const GSList *	gb_bookmark_set_get_context_bookmarks 	(GbBookmarkSet *set);
void		gb_bookmark_set_set_needs_saving	(GbBookmarkSet *set, gboolean needs_saving);
void		gb_bookmark_set_set_auto_save		(GbBookmarkSet *set, guint interval);
void		gb_bookmark_set_add_default		(GbBookmarkSet *set, GbBookmark *b);
void		gb_bookmark_set_fix_galeon1_mess	(GbBookmarkSet *set);
GbBookmark *	gb_bookmark_set_get_bookmark_by_url	(GbBookmarkSet *set, 
							 const gchar *url);
GbBookmark *	gb_bookmark_set_get_bookmark_by_nick	(GbBookmarkSet *set, 
							 const gchar *nick);
gchar *		gb_bookmark_set_get_url_by_nick_and_args (GbBookmarkSet *set, 
							  const gchar *nick_and_args);
const GSList *	gb_bookmark_set_get_all			(GbBookmarkSet *set);
const GSList *	gb_bookmark_set_get_all_noalias		(GbBookmarkSet *set);


G_END_DECLS

#endif
