/*
 *  Copyright (C) 2000 Marco Pesenti Gritti
 *
 *  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 "galeon.h"
#include "history.h"
#include "bookmarks.h"
#include "misc.h"
#include "prefs.h"
#include "mozilla.h"

#include <math.h>
#include <libgnome/gnome-config.h>
#include <libgnome/gnome-i18n.h>
#include <time.h>


/*
 *  AutoBookmarks
 *
 *  (c) Matthew Aubury 2000
 *
 *  This code implements "AutoBookmarks", bookmarks which are generated
 *  automatically by scanning and scoring the user's history file.
 *  In theory, these represent the most commonly used sites and are
 *  handy for particularly lazy users who otherwise don't get round
 *  to making bookmarks (really, I've seen a lot of them!).
 *
 *  The current code is the result of some considerable tweaking and
 *  refinement but at present is based ONLY on my history file, which
 *  cannot possibly be representative of general usage. I'm interested
 *  in ANY feedback people have about how well the scoring algorithm 
 *  actually works.
 *
 *  The Scoring Algorithm
 *
 *  This works as follows. All visits to a server (e.g. www.foo.com) are
 *  lumped together and counted as one. The root page of the site is taken
 *  as the most popular amongst these. This means that if you visit
 *  lots of news pages linked from a site (say, slashdot.org) the rating
 *  of http://slashdot.org/index.pl should be extremely high.
 *  The score is then scaled according to how long you've been visiting
 *  the site (simply visiting a bunch of pages in one session doesn't
 *  give a high score), and how long it is since you last visited the
 *  site (so if I stop going somewhere it gradually drops down the list --
 *  but if I go again it shoots back up).
 * 
 *  FIXME: at the moment autobookmarks are generated once only at the
 *  beginning of the session. In future they should be regenerated at
 *  "some point" during execution... but when?
 *
 *  -- MattA  <matt@ookypooky.com>  19/12/2000
 */

/* local function prototypes */
static gint compare_hosts (const HistoryHost *a, const HistoryHost *b);
static gdouble score_of_host (const HistoryHost *server);

/** The AutoBookmarks folder */
BookmarkItem *autobookmarks_root = NULL;

/**
 * autobookmarks_generate: generate AutoBookmarks folder from 
 * history elements
 */
void 
autobookmarks_generate (void)
{
	GList *list, *item;
	gint count, maximum;
	gint shorten;

	/* check if it's not enabled */
	if (eel_gconf_get_boolean (CONF_BOOKMARKS_AB_ENABLED) == FALSE)
	{
		/* delete the folder if it exists */
		if (autobookmarks_root != NULL)
		{
			bookmarks_toolbars_check_update (autobookmarks_root);
			bookmarks_editor_remove_tree_items(autobookmarks_root);
			bookmarks_remove_recursively (autobookmarks_root);
			autobookmarks_root = NULL;
			bookmarks_updated ();
		}
		return;
	}
		
	/* we're configured to generate them -- is the folder there? */
	if (autobookmarks_root != NULL)
	{
		/* yes, delete the contents */
		item = autobookmarks_root->list;
		while (item != NULL)
		{
			bookmarks_remove_recursively (item->data);
			item = item->next;
		}
		autobookmarks_root->list = NULL;
	}
	else
	{
		/* no, create the folder */
		gchar* utfstr = mozilla_locale_to_utf8(_("AutoBookmarks"));
		autobookmarks_root = bookmarks_new_bookmark 
			(BM_AUTOBOOKMARKS, TRUE, utfstr,
			 NULL, NULL, NULL, NULL);
		g_free(utfstr);

		/* add it to the main folder */
		g_return_if_fail(bookmarks_root != NULL);
		bookmarks_root->list = g_list_append (bookmarks_root->list, 
						      autobookmarks_root);
		autobookmarks_root->parent = bookmarks_root;
		autobookmarks_root->create_toolbar = FALSE;
		autobookmarks_root->expanded = FALSE;
		autobookmarks_root->list = NULL;
	}

	/* get values from configuration */
	maximum = eel_gconf_get_integer (CONF_BOOKMARKS_AB_COUNT);
	shorten = eel_gconf_get_integer (CONF_BOOKMARKS_AB_SHORTEN);

	/* get the list of hosts */
	list = history_get_host_list ();
	
	/* sort by score */
	list = g_list_sort (list, (GCompareFunc)compare_hosts);

	/* iterate over the first useful elements */
	count = 0;
	for (item = list; item != NULL; item = g_list_next(item), count++)
	{
		HistoryHost *host = (HistoryHost *)item->data;
		HistoryItem *hi = (HistoryItem *)host->dominant_item;
		gchar *title_utf8, *name;
		BookmarkItem *b;

		/* add it if within bounds */
		if (count < maximum && hi != NULL)
		{
			/* create the bookmark */
			/* note that shorten_name takes care of
			 * duplicating the title string for us, even 
			 * when it's not changed */
			title_utf8 = (hi->title_utf8 != NULL ? 
				      hi->title_utf8 : hi->title_locale);
			name = shorten_name (title_utf8, shorten);
			b = bookmarks_new_bookmark (BM_SITE, TRUE, name, 
						    hi->url, NULL, NULL, NULL);
			g_free (name);
			
			/* add it to the autobookmarks folder */
			b->parent = autobookmarks_root;
			autobookmarks_root->list = 
				g_list_append (autobookmarks_root->list, b);
		}
	}

	/* free the list */
	g_list_free(list);

	if (autobookmarks_root)
		bookmarks_toolbars_check_update (autobookmarks_root);
	bookmarks_updated ();
}

/**
 * score_of_host: compute the "score" of a host.
 * This value represents how likely the item is to make a good AutoBookmark. 
 */
static inline gdouble 
score_of_host (const HistoryHost *host)
{
	static gdouble age, age_scale;
 	static gdouble interval_scale;
	static gdouble score;

	/* check */
	if (host->dominant_item == NULL)
	{
		return 0.0;
	}

	/* get some basic values */
	age = (gdouble)(time(NULL) - host->dominant_item->last);

	/* age scaling, falls of exponentially with time */
	age_scale = exp((double)(-age / 1e12));

	/* scale linearly according to how long we've been visiting */
	interval_scale = (gdouble)(host->dominant_item->last - 
				   host->dominant_item->first);

	/* score by scaled number of vists */
	score = (gdouble)host->visits * age_scale * interval_scale;

	/* return the score */
	return score;	
}

/**
 * compare_hosts: compare the scores of two hosts
 */
static gint 
compare_hosts (const HistoryHost *a, const HistoryHost *b)
{
	static gdouble score_a, score_b;

	/* compute scores */
	score_a = score_of_host(a);
	score_b = score_of_host(b);

	/* return compared values */
	return (score_b > score_a ? 1 : -1);
}

