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

/*
 * Netscape bookmark importing by Nate Case <nd@kracked.com>
 * Netscape preference importing patch by Andreas Heck <aheck@pro-linux.de>
 * Netscape bookmark exporting by Ricardo Fernández Pascual <ric@users.sourceforge.net>
 */

#include "galeon.h"
#include "bookmarks.h"
#include "misc.h"
#include "prefs.h"
#include "mozilla.h"

#include <stdlib.h>
#include <string.h>
#include <libgnomeui/gnome-dialog-util.h>
#include <libgnome/gnome-config.h>
#include <libgnome/gnome-i18n.h>

/* local data types */

typedef struct
{
	gchar *homepage;
	gint win_height, win_width;
	gint startup_page;
	gint toolbar_style;
	gboolean enable_java, enable_javascript;
	gchar *proxy_auto_url, *http_proxy, *ftp_proxy, *no_proxies;
	gint proxy_type, http_proxy_port, ftp_proxy_port;
} ns_prefs;


/* local function prototypes */
static NSItemType ns_get_bookmark_item (FILE *f, GString *name, GString *url,
					GString *nick, GTime *added,
					GTime *visited);
static GTime ns_get_bookmark_date (const char *line, const char *search);
static char *ns_parse_bookmark_item (GString *string);
static ns_prefs *get_ns_prefs(gchar *);

static void netscape_export_bookmarks_item (FILE *file, BookmarkItem *b, 
					    gboolean use_locale);


/**
 * updates list, tree widget, and updates menu 
 * as the intelligence of this has improved, it's also gotten big and complex.
 * FIXME: needs modularization - Nate
 * FIXME: needs a total rewrite, using libxml - Ricardo
 */
gint 
netscape_import_bookmarks (GString *filename, gboolean use_locale)
{
	BookmarkItem *parent, *newbm = NULL;
	FILE *bf;  /* bookmark file */
	GString *name = g_string_new (NULL);
	gchar *parsedname;
	GString *url = g_string_new (NULL);
	GString *nick = g_string_new (NULL);
	GTime added, visited;
	GSList *urls, *l;
	int dup = 0;
	GSList * folders;
	gchar *str1, *str2;
	gchar * (*to_utf8) (const gchar *) = 
		use_locale ? mozilla_locale_to_utf8 : g_strdup;
	
	if (!(bf = fopen (filename->str, "r"))) {
		g_warning ("Failed to open file: %s\n", filename->str);
		return -1;
	}	
	
	if (bookmarks_root)
	{
		urls = bookmarks_list_all_urls (bookmarks_root);
		folders = bookmarks_list_all_folders (bookmarks_root);
	}
	else
	{
		urls = NULL;
		folders = NULL;
	}
	
	parent = bookmarks_root;
	
	while (!feof (bf)) {
		added = visited = 0;
		switch (ns_get_bookmark_item(bf, name, url, nick,
					     &added, &visited )) {
		case NS_FOLDER: 

			newbm = NULL;

			for (l = folders; l != NULL; l = l->next)
			{    /* use existing folder if it's already there */
				if (l->data)
				{
					gchar *str = to_utf8 (((BookmarkItem *)(l->data))->name);
					gchar *stripped = strip_uline_accel (str);
					g_free (str);
					if (!g_strcasecmp(stripped, name->str))
					{
						g_free (stripped);
						newbm = (BookmarkItem *) (l->data);
						break;
					}
					g_free (stripped);
				}
			}
					
			if (!newbm)
			{
				gchar *str = to_utf8 (name->str);
				newbm = bookmarks_new_bookmark 
					(BM_FOLDER, TRUE, str, 
					 NULL, NULL, NULL, NULL);
				g_free (str);
				newbm->parent = parent;
				newbm->create_toolbar = strcmp
					(name->str, 
					 _("Personal Toolbar Folder")) == 0 
					? TRUE : FALSE;
				parent->list = g_list_insert (parent->list, newbm, -1);
				newbm->parent = parent;
				newbm->time_added = added;
				bookmarks_editor_place_tree_items (newbm);
			}
			
			parent = newbm;
			break;
		case NS_SITE:
			newbm = NULL;
			dup = FALSE;
			
			for(l = urls; l != NULL; l = l->next)
			{   /* ignore if duplicate bookmark */
				if (l->data)
					if (!g_strcasecmp(l->data, url->str))
					{
						dup = TRUE;
						break;
					}
			}
			if (dup) break;
			
			parsedname = ns_parse_bookmark_item (name);
			str1 = to_utf8 (parsedname);
			if (nick->str) 
				str2 = to_utf8 (nick->str);
			else
				str2 = NULL;
			newbm = bookmarks_new_bookmark 
				(BM_SITE, TRUE, str1, url->str, 
				 str2, NULL, NULL);
			g_free (str2);
			g_free (str1);
			g_free (parsedname);
			newbm->parent = parent;
			parent->list = g_list_insert(parent->list, newbm, -1);
			newbm->time_added = added;
			newbm->time_visited = visited;
			bookmarks_editor_place_tree_items (newbm);
			break;
		case NS_NOTES:
			if (newbm)
			{
				char *tmpstr = newbm->notes;
				str1 = to_utf8 (tmpstr);
				str2 = to_utf8 (name->str);
				newbm->notes = g_strconcat (str1, str2, NULL);
				g_free (str2);
				g_free (str1);
				g_free (tmpstr);
			}
			break;
		case NS_SEPARATOR:
			/* how to check if a separator is duplicated? */
			newbm = bookmarks_new_bookmark 
				(BM_SEPARATOR, TRUE, NULL, NULL, NULL, NULL, NULL);
			newbm->parent = parent;
			parent->list = g_list_insert(parent->list, newbm, -1);
			bookmarks_editor_place_tree_items (newbm);
			newbm = NULL;
			break;
		case NS_FOLDER_END:
			newbm = NULL;
			if (parent != bookmarks_root)
				parent = parent->parent;
			break;
		default:
			newbm = NULL;
			break;
		}		
	}
	fclose (bf);
	g_string_free (name, TRUE);
	g_string_free (url, TRUE);
	g_string_free (nick, TRUE);
	g_slist_free(urls);
	g_slist_free(folders);
		
	bookmarks_tb_dirty = TRUE;
	bookmarks_dirty = TRUE;

	return 0;	
}

static GTime
ns_get_bookmark_date (const char *line, const char *search)
{
	const char *found = g_strcasestr(line, search);
	if (!found)
		return 0;
	return atoi (found + strlen (search) + 1);
}

/** 
 * Parses a line of a mozilla/netscape bookmark file. File must be open.
 */
/* this has been tested fairly well */
static NSItemType 
ns_get_bookmark_item (FILE *f, GString *name, GString *url, GString *nick,
		      GTime *added, GTime *visited)
{
	char *line = NULL;
	char *found;

	line = read_line_from_file (f);

	if ((found = (char *) g_strcasestr (line, "<A HREF="))) {  /* declare site? */
		g_string_assign (url, found+9);  /* url=URL+ ADD_DATE ... */
		g_string_truncate (url, strstr(url->str, "\"")-url->str);
		found = (char *) strstr (found+9+url->len, "\">");
		if (!found) return NS_UNKNOWN;
		g_string_assign (name, found+2);
		g_string_truncate (name, g_strcasestr(name->str, "</A>")-name->str);
		if ((found = (char *) g_strcasestr (line, "SHORTCUTURL="))) {
			g_string_assign (nick, found+13);
			g_string_truncate (nick, strstr(nick->str, "\"")-nick->str);
		} else
			g_string_assign (nick, "");
		*added = ns_get_bookmark_date (line, "ADD_DATE=");
		*visited = ns_get_bookmark_date (line, "LAST_VISIT=");
		return NS_SITE;
	} else if ((found = (char *) g_strcasestr (line, "<DT><H3"))) { /* declare folder? */
		found = (char *) strstr(found+7, ">");
		if (!found) return NS_UNKNOWN;
		g_string_assign (name, found+1);
		g_string_truncate (name, g_strcasestr(name->str, "</H3>")-name->str);
		*added = ns_get_bookmark_date (line, "ADD_DATE=");
		return NS_FOLDER;		
	} else if ((found = (char *) g_strcasestr (line, "</DL>"))) {     /* end folder? */
		return NS_FOLDER_END;
	} else if ((found = (char *) g_strcasestr (line, "<HR>"))) {    /* separator */
		return NS_SEPARATOR;
	} else if ((found = (char *) g_strcasestr (line, "<DD>"))) {    /* comments */
		g_string_assign (name, found+4);
		return NS_NOTES;
	} else if (strchr(line, '<')==NULL && strchr(line, '>')==NULL) {    /* continued comments (probably) */
		g_string_assign (name, line);
		return NS_NOTES;
	}
	
	return NS_UNKNOWN;
}

/**
 * This function replaces some weird elements
 * like &amp; &le;, etc..
 * More info : http://www.w3.org/TR/html4/charset.html#h-5.3.2
 * NOTE : We don't support &#D or &#xH.
 * Patch courtesy of Almer S. Tigelaar <almer1@dds.nl>
 */
static char *
ns_parse_bookmark_item (GString *string)
{
	char *iterator, *temp;
	int cnt = 0;
	GString *result = g_string_new (NULL);

	g_return_val_if_fail (string != NULL, NULL);
	g_return_val_if_fail (string->str != NULL, NULL);

	iterator = string->str;
	
	for (cnt = 0, iterator = string->str;
	     cnt <= strlen (string->str);
	     cnt++, iterator++) {
		if (*iterator == '&') {
			int jump = 0;
			int i;

			if (g_strncasecmp (iterator, "&amp;", 5) == 0) {
			
				g_string_append_c (result, '&');
				jump = 5;
			} else if (g_strncasecmp (iterator, "&lt;", 4) == 0) {
			
				g_string_append_c (result, '<');
				jump = 4;
			} else if (g_strncasecmp (iterator, "&gt;", 4) == 0) {

				g_string_append_c (result, '>');
				jump = 4;
			} else if (g_strncasecmp (iterator, "&quot;", 6) == 0) {
			
				g_string_append_c (result, '\"');
				jump = 6;
			} else {
				/* It must be some numeric thing now */

				iterator++;

				if (iterator && *iterator == '#') {
					int val;
					char *num, *tmp;
					
					iterator++;
					
					val = atoi (iterator);

					tmp = g_strdup_printf ("%d", val);
					jump = strlen (tmp);
					g_free (tmp);
					
					num = g_strdup_printf ("%c", (char) val);
					g_string_append (result, num);
					g_free (num);
				}
			}
			for (i = jump - 1; i > 0; i--) {
				iterator++;
				if (iterator == NULL)
					break;
			}
		} else 
			g_string_append_c (result, *iterator);
	}
	temp = result->str;
	g_string_free (result, FALSE);
	return temp;
}

/**
 * Exports bookmarks to netscape or mozilla
 * Will overwrite the file!
 */
gint 
netscape_export_bookmarks (gchar *filename, BookmarkItem *root, 
			   gboolean use_locale)
{
	FILE *file;
	GList *l;

	g_return_val_if_fail (root->type == BM_FOLDER, -1);
	g_return_val_if_fail (filename != NULL, -1);

	if (!(file = fopen (filename, "w"))) {
		gchar *error = g_strdup_printf (_("Could not open file: %s"), filename);
		gnome_error_dialog (error);
		g_free (error);
		return -1;
	}

	/* write the headers */
	fputs ("<!DOCTYPE NETSCAPE-Bookmark-file-1>\n", file);
	fputs ("<!-- This file was automatically generated by Galeon\n", file);
	fputs ("It will be read and overwritten.\n", file);
	fputs ("Do Not Edit! -->\n", file);
	if (!use_locale)
		fputs ("<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=UTF-8\">\n", file);
	fputs ("<TITLE>Bookmarks</TITLE>\n", file);
	fputs ("<H1>Bookmarks</H1>\n", file);
	fputs ("\n", file);
	fputs ("<DL><p>\n", file);

	/* write the bookmarks */
	for (l = root->list; l != NULL; l = l->next) 
		netscape_export_bookmarks_item (file, l->data, use_locale);
	
	/* finish */
	fputs ("</DL><p>\n", file);

	fclose (file);	
	return 0;
}

static void 
netscape_export_bookmarks_item (FILE *file, BookmarkItem *b, gboolean use_locale)
{
	GList *l;
	gchar *str;
	gchar *strippedname;
	gchar * (*from_utf8) (const gchar *) = 
		use_locale ? mozilla_utf8_to_locale : g_strdup;

	switch (b->type) {
	case BM_SITE:
		fputs ("\t<DT><A HREF=\"", file);
		fputs (b->url, file);
		fputs ("\"", file);
		if (b->time_added > 0)
			fprintf (file, " ADD_DATE=\"%d\"", b->time_added);
		if (b->time_modified > 0) 
			fprintf (file, " LAST_MODIFIED=\"%d\"", b->time_modified);
		if (b->time_visited > 0)
			fprintf (file, " LAST_VISIT=\"%d\"", b->time_visited);
		/* support a mozilla-only feature, but won't harm netscape */
		if (strlen (b->nick) > 0) {
			fputs (" SHORTCUTURL=\"", file);
			str = from_utf8 (b->nick);
			fputs (str, file);
			g_free (str);
			fputs ("\"", file);
		}
		fputs (">", file);
		strippedname = strip_uline_accel (b->name);
		str = from_utf8 (strippedname);
		fputs (str, file);
		g_free (str);
		g_free(strippedname);
		fputs ("</A>\n", file);
		if (strlen (b->notes) > 0) {
			fputs ("<DD>", file);
			str = from_utf8 (b->notes);
			fputs (str, file);
			g_free (str);
			fputs ("\n", file);
		}
		break;
	case BM_FOLDER:
		fputs ("<DT><H3 ADD_DATE=\"0\">", file); 
		strippedname = strip_uline_accel (b->name);
		str = from_utf8 (strippedname);
		fputs (str, file);
		g_free (str);
		g_free(strippedname);
		fputs ("</H3>\n", file);
		if (strlen (b->notes) > 0) {
			fputs ("<DD>", file);
			str = from_utf8 (b->notes);
			fputs (str, file);
			g_free (str);
			fputs ("\n", file);
		}
		fputs ("<DL><p>\n", file);
		/* FIXME: Alias catogories are not exported */
		if (!b->alias_of)
			for (l = b->list; l != NULL; l = l->next) 
				netscape_export_bookmarks_item (file, l->data, use_locale);
		else
			g_warning ("Detected a bookmark item type that I can't export!");
		fputs ("</DL><p>\n", file);
		break;
	case BM_SEPARATOR:
		fputs ("<HR>\n", file);
		break;
	default:
		g_warning ("Detected a bookmark item type that I can't export!");
		break;
	}
}

static ns_prefs *
get_ns_prefs(gchar *nsprefsfile)
{
	static ns_prefs prefs;
	FILE *fp;
	gchar buffer[512];
	gchar *pos;
	GString *pkey = g_string_new("");
	GString *value = g_string_new("");
	int startpos = 0;

	/* preferences struct init start */

	prefs.startup_page = 1;
	prefs.toolbar_style = 2;
	prefs.enable_java = TRUE;
	prefs.enable_javascript = TRUE;

	/* preferences struct init end */

	if ((fp = fopen(nsprefsfile, "r")) == NULL)
	{
		return NULL;
	}

	while (!feof(fp) && !ferror(fp))
	{
		fgets(buffer, 512, fp);

		if (strstr(buffer, "user_pref"))  /* line is a user_pref definition */
		{
			if ((startpos = strcspn(buffer, "\"")))
			{
				memcpy(buffer, &buffer[startpos], strlen(&buffer[startpos]));

				g_string_assign(pkey, "");

				if ((pos = (char *)strstr(buffer, "\"")))
				{
					g_string_assign(pkey, pos+1);
					pos = (char *)strstr(pkey->str, "\"");
					g_string_truncate(pkey, pos-pkey->str);
				}

				if ((pos = (char *)strstr(buffer, " ")))
				{
					g_string_assign(value, pos+1);  /* get the value */
					
					if ((pos = (char *)strstr(value->str, ")")))
						g_string_truncate(value, pos-value->str);

					while ((pos = (char *)strstr(value->str, "\""))) /* strip " */
					{
						g_string_erase(value, pos-value->str, 1);
					}
				}

				/* g_print("Key: %s\tValue: %s\n", pkey->str, value->str); */

				if (strcmp(pkey->str, "browser.startup.homepage") == 0)
					prefs.homepage = g_strdup(value->str);
				else if (strcmp(pkey->str, "browser.win_height") == 0)
					prefs.win_height = atoi(value->str);
				else if (strcmp(pkey->str, "browser.win_width") == 0)
					prefs.win_width = atoi(value->str);
				else if (strcmp(pkey->str, "security.enable_java") == 0)
				{
					if (strcmp(value->str, "false") == 0)
						prefs.enable_java = FALSE;
				}
				else if (strcmp(pkey->str, "javascript.enabled") == 0)
				{
					if (strcmp(value->str, "false") == 0)
						prefs.enable_javascript = FALSE;
				}
				else if (strcmp(pkey->str, "browser.startup.page") == 0)
				{
					prefs.startup_page = atoi(value->str);

					/*
					 * 0: Browser starts with blank page
					 * 1/No value: Last page visited
					 * 2: Starts with homepage
					 */
				}
				else if (strcmp(pkey->str, "network.proxy.http") == 0)
					prefs.http_proxy = g_strdup(value->str);
				else if (strcmp(pkey->str, "network.proxy.ftp") == 0)
					prefs.ftp_proxy = g_strdup(value->str);
				else if (strcmp(pkey->str, "network.proxy.no_proxies_on") == 0)
				{
					prefs.no_proxies = g_strdup(value->str);
				}
				else if (strcmp(pkey->str, "network.proxy.type") == 0)
				{
					prefs.proxy_type = atoi(value->str);

					/*
					 * 0: no proxy
					 * 1: manual proxy
					 * 2: auto proxy setup
					 */
				}
				else if (strcmp(pkey->str, "network.proxy.autoconfig_url") == 0)
					prefs.proxy_auto_url = g_strdup(value->str);
				else if (strcmp(pkey->str, "network.proxy.http_port") == 0)
					prefs.http_proxy_port = atoi(value->str);
				else if (strcmp(pkey->str, "network.proxy.ftp_port") == 0)
					prefs.ftp_proxy_port = atoi(value->str);
			        else if (strcmp(pkey->str, "browser.chrome.toolbar_style") == 0)
					prefs.toolbar_style = atoi(value->str);
					
					/*
					 * 0: Pictures only toolbar
					 * 1: Text only toolbar
					 * 2: Pictures and text toolbar
					 */
			}
		}
	}

	fclose(fp);
	return &prefs;
}

/* returns TRUE if successful */
gboolean
netscape_import_prefs(void)
{
	ns_prefs *prefs;
	gchar *prefpath;
	gint buffer = 0;

	prefpath = g_strconcat(g_get_home_dir(), "/.netscape/preferences.js",
			NULL);

	if (!(prefs = get_ns_prefs(prefpath)))
		return FALSE;

	/* now we set some of galeon prefs to whats in "ns_prefs *prefs" */

	eel_gconf_set_string(CONF_GENERAL_HOMEPAGE, prefs->homepage);
	switch (prefs->startup_page)
	{
		case 0: buffer = 2; break;
		case 1: buffer = 0; break;
		case 2: buffer = 1; break;
	}

	eel_gconf_set_boolean(CONF_NETWORK_PROXY_MODE, 
			      prefs->proxy_type);
	eel_gconf_set_string(CONF_NETWORK_PROXY_AUTO_URL,
			     prefs->proxy_auto_url);
	eel_gconf_set_string(CONF_NETWORK_HTTP_PROXY, 
			     prefs->http_proxy);
	eel_gconf_set_string(CONF_NETWORK_FTP_PROXY, 
			     prefs->ftp_proxy);
        eel_gconf_set_integer(CONF_NETWORK_HTTP_PROXY_PORT, 
			      prefs->http_proxy_port);
	eel_gconf_set_integer(CONF_NETWORK_FTP_PROXY_PORT, 
			      prefs->ftp_proxy_port);
	eel_gconf_set_string(CONF_NETWORK_NO_PROXIES_FOR, 
			     prefs->no_proxies);

	eel_gconf_set_integer(CONF_GENERAL_STARTPAGE_TYPE, 
			     buffer);
	eel_gconf_set_integer(CONF_TOOLBAR_STYLE, 
			     prefs->toolbar_style);
	eel_gconf_set_integer(CONF_STATE_WINWIDTH, 
			     prefs->win_width);
	eel_gconf_set_integer(CONF_STATE_WINHEIGHT, 
			     prefs->win_height);
	eel_gconf_set_boolean(CONF_FILTERING_JAVA_ENABLED, 
			     prefs->enable_java);
	eel_gconf_set_boolean(CONF_FILTERING_JAVASCRIPT_ENABLED, 
			     prefs->enable_javascript);	

/* 	set_toolbar_style_global ();
	mozilla_prefs_set ();	*/
/*	
 *	I decided not to do this here because it's only called when Galeon is run for the
 *	first time and it was getting errors in init_cache() from mozilla_prefs_set().
 *	The quick solution is to remove it because the prefs are gonna be read anyways
 *	by preferences_load() called afterwards.
 *	
 *	FIXME: Make more friendly so it will be callable in other places
 */
	
	return TRUE;
}
