/*
 *  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.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "window-recent-history.h"
#include "gul-gobject-misc.h"
#include "galeon-marshal.h"
#include "galeon-debug.h"
#include <string.h>

/**
 * Private data
 */

typedef struct 
{
	gchar *url;
	gchar *title;
} WrhEntry;

struct _GaleonWindowRecentHistoryPrivate 
{
	gint max_items;
	gint num_items;
	WrhEntry *items;
};

/**
 * Private functions, only availble from this file
 */
static void	galeon_window_recent_history_class_init		(GaleonWindowRecentHistoryClass *klass);
static void	galeon_window_recent_history_init		(GaleonWindowRecentHistory *dip);
static void	galeon_window_recent_history_finalize_impl	(GObject *o);
static void	galeon_window_recent_history_emit_changed 	(GaleonWindowRecentHistory *wrh);
static void	galeon_window_recent_history_move_item_to_top	(GaleonWindowRecentHistory *wrh, 
								 gint current_pos);

static void	wrh_entry_clear					(WrhEntry *e);
static void 	wrh_entry_set_url				(WrhEntry *w, const gchar *url);
static void	wrh_entry_set_title				(WrhEntry *e, const gchar *title);

static gpointer g_object_class;

enum GaleonWindowRecentHistorySignalsEnum {
	GALEON_WINDOW_RECENT_HISTORY_CHANGED,
	GALEON_WINDOW_RECENT_HISTORY_LAST_SIGNAL
};
static gint GaleonWindowRecentHistorySignals[GALEON_WINDOW_RECENT_HISTORY_LAST_SIGNAL];


/**
 * GaleonWindowRecentHistory object
 */
MAKE_GET_TYPE (galeon_window_recent_history, "GaleonWindowRecentHistory", GaleonWindowRecentHistory, 
	       galeon_window_recent_history_class_init, galeon_window_recent_history_init, 
	       G_TYPE_OBJECT);


static void
galeon_window_recent_history_class_init (GaleonWindowRecentHistoryClass *klass)
{
	G_OBJECT_CLASS (klass)->finalize = galeon_window_recent_history_finalize_impl;
	g_object_class = g_type_class_peek_parent (klass);

	GaleonWindowRecentHistorySignals[GALEON_WINDOW_RECENT_HISTORY_CHANGED] = g_signal_new (
		"changed", G_OBJECT_CLASS_TYPE (klass),  
		G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP,
                G_STRUCT_OFFSET (GaleonWindowRecentHistoryClass, changed), 
		NULL, NULL, 
		galeon_marshal_VOID__VOID,
		G_TYPE_NONE, 0);
	
}

static void 
galeon_window_recent_history_init (GaleonWindowRecentHistory *dip)
{
	GaleonWindowRecentHistoryPrivate *p = g_new0 (GaleonWindowRecentHistoryPrivate, 1);
	dip->priv = p;
	p->num_items = 0;
	p->max_items = 10;
	p->items = g_new0 (WrhEntry, p->max_items);
}

static void
galeon_window_recent_history_finalize_impl (GObject *o)
{
	GaleonWindowRecentHistory *dip = GALEON_WINDOW_RECENT_HISTORY (o);
	GaleonWindowRecentHistoryPrivate *p = dip->priv;
	int i;
	
	for (i = 0; i < p->max_items; ++i)
	{
		wrh_entry_clear (&p->items[i]);
	}
	g_free (p->items);
	g_free (p);
	
	G_OBJECT_CLASS (g_object_class)->finalize (o);
}

GaleonWindowRecentHistory *
galeon_window_recent_history_new (void)
{
	GaleonWindowRecentHistory *ret = g_object_new (GALEON_TYPE_WINDOW_RECENT_HISTORY, NULL);
	return ret;
}

static void
galeon_window_recent_history_emit_changed (GaleonWindowRecentHistory *wrh)
{
	g_signal_emit (wrh, GaleonWindowRecentHistorySignals[GALEON_WINDOW_RECENT_HISTORY_CHANGED], 0);
}

static void
galeon_window_recent_history_move_item_to_top (GaleonWindowRecentHistory *wrh, 
					       gint current_pos)
{
	GaleonWindowRecentHistoryPrivate *p = wrh->priv;
	gint i;
	WrhEntry e = p->items[current_pos];
	for (i = current_pos; i > 0; --i)
	{
		p->items[i] = p->items[i - 1];
	}
	p->items[0] = e;
}					       

void
galeon_window_recent_history_visited (GaleonWindowRecentHistory *wrh,
				      const gchar *url,
				      const gchar *title)
{
	GaleonWindowRecentHistoryPrivate *p;
	gint i;
	
	g_return_if_fail (GALEON_IS_WINDOW_RECENT_HISTORY (wrh));
	g_return_if_fail (url);

	p = wrh->priv;

	if (!title)
	{
		title = url;
	}

	LOG ("visited %s (%s)", url, title);

	for (i = 0; i < p->num_items; ++i)
	{
		if (!strcmp (p->items[i].url, url))
		{
			if (i == 0 && !strcmp (title, p->items[i].title))
			{
				/* it's the same item than the last time, nothing to do */
				return;
			}
			else
			{
				if (strcmp (title, p->items[i].title))
				{
					wrh_entry_set_title (&p->items[i], title);
				}
				galeon_window_recent_history_move_item_to_top (wrh, i);
				galeon_window_recent_history_emit_changed (wrh);
				return;
			}
		}
	}

	/* new item */
	if (p->num_items == p->max_items)
	{
		/* remove the oldest item */
		--p->num_items;
	}
	wrh_entry_set_url (&p->items[p->num_items], url);
	wrh_entry_set_title (&p->items[p->num_items], title);
	p->num_items++;
	
	galeon_window_recent_history_move_item_to_top (wrh, p->num_items - 1);
	galeon_window_recent_history_emit_changed (wrh);
}

void
galeon_window_recent_history_get_num_items (GaleonWindowRecentHistory *wrh, int *n)
{
	*n = wrh->priv->num_items;
}

void
galeon_window_recent_history_get_item (GaleonWindowRecentHistory *wrh, int n,
				       gchar **url, gchar **title)
{
	GaleonWindowRecentHistoryPrivate *p;
	
	g_return_if_fail (GALEON_IS_WINDOW_RECENT_HISTORY (wrh));
	g_return_if_fail (n >= 0);

	p = wrh->priv;

	if (n >= p->num_items)
	{
		if (url) *url = NULL;
		if (title) *title = NULL;
	}
	else
	{
		if (url) *url = g_strdup (p->items[n].url);
		if (title) *title = p->items[n].title 
				   ? g_strdup (p->items[n].title)
				   : g_strdup (p->items[n].url);
	}
}

void
galeon_window_recent_history_clear (GaleonWindowRecentHistory *wrh)
{
	GaleonWindowRecentHistoryPrivate *p = wrh->priv;
	gint i;
	for (i = 0; i < p->max_items; ++i)
	{
		wrh_entry_clear (&p->items[i]);
	}
	p->num_items = 0;

	galeon_window_recent_history_emit_changed (wrh);
}

void
galeon_window_recent_history_set_max_num_items (GaleonWindowRecentHistory *wrh, int m)
{
	GaleonWindowRecentHistoryPrivate *p;
	int i;
	WrhEntry *new_items;

	g_return_if_fail (GALEON_IS_WINDOW_RECENT_HISTORY (wrh));
	g_return_if_fail (m > 0);
	
	p = wrh->priv;
	new_items = g_new0 (WrhEntry, m);

	for (i = 0; i < p->max_items; ++i)
	{
		if (i < m)
		{
			new_items[i] = p->items[i];
		}
		else
		{
			wrh_entry_clear (&p->items[i]);
		}
	}

	g_free (p->items);
	p->items = new_items;
	p->max_items = m;
	p->num_items = MIN (p->num_items, p->max_items);
}

static void
wrh_entry_clear (WrhEntry *e)
{
	g_free (e->url);
	e->url = NULL;
	g_free (e->title);
	e->title = NULL;
}

static void
wrh_entry_set_url (WrhEntry *e, const gchar *url)
{
	g_return_if_fail (url);

	g_free (e->url);
	e->url = g_strdup (url);
}

static void
wrh_entry_set_title (WrhEntry *e, const gchar *title)
{
	g_return_if_fail (title);
	
	g_free (e->title);
	e->title = g_strdup (title);
}

