/*
 *  Copyright (C) 2004 Mathias Andre <mathias@openbrookes.org>
 *
 *  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 of the License, 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 <glib.h>
#include <gconf/gconf-client.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include "ui/nb_ui_interface.h"
#include "ui/nb_ui_note_view.h"
#include "ui/nb_ui_treeview.h"
#include "nb_note.h"
#include "nb_note_list.h"
#include "nb_util.h"
#include "nb_global.h"

#define _(text) gettext(text)

/* private functions */
static void nb_global_add_note_to_tree (Global * self);
static void nb_global_update_current_note_in_tree (Global * self);
static gboolean nb_global_cb_delete_note_from_file (GtkTreeModel * model, GtkTreePath * path, GtkTreeIter * iter, GList ** rowref_list);
static gchar * nb_global_get_config (Global * self);

/* create and free object */
Global *
nb_global_new (void)
{
	Global * self = g_malloc (sizeof (Global));
	gchar * notefile = NULL;

	self->current_note = nb_note_new ();
	self->inserted_note = NEW;
	self->modified_note = CLEAN;
	self->show_icon_list = TRUE;

	/* set up the ListStore for the treeview */
	self->store = gtk_list_store_new (N_COLUMNS,
					  G_TYPE_STRING,
					  G_TYPE_STRING,
					  G_TYPE_STRING,
					  G_TYPE_STRING,
					  G_TYPE_STRING,
					  G_TYPE_POINTER);

	nb_ui_treeview_set_sort_func (self->store);

	notefile = (gchar *) nb_global_get_config (self);
	self->nl = nb_note_list_new (notefile);

	return self;
}

void
nb_global_free (Global * self)
{
	nb_note_free (self->current_note);
	nb_note_list_free (self->nl);
	g_free (self->default_browser);
	g_free (self);
}

/* notes management */
void
nb_global_new_note (Global * self)
{
	if  ( self->modified_note == EDITED )
	{
		if ( (self->inserted_note == INSERTED) || !nb_ui_note_view_is_empty () )
		{
			if ( !nb_ui_dialog_question ((gchar *) _("Do you want to save note?"), (gchar *) _("Save note?")) )
				return ;

			if ( nb_global_save_note (self) )
				nb_ui_statusbar_push ((gchar *) _("Successfully saved note to file."));
			else
				return ;
		}
		else
			return ;
	}
	else
		nb_ui_statusbar_push ((gchar *) _("Empty note created."));

	/* empty the current note text to gain memory */
	nb_note_clear_text (self->current_note);

	/* create a new blank note */
	self->current_note = nb_note_new ();
	self->inserted_note = NEW;
	self->modified_note = CLEAN;

	nb_ui_note_view_reset ();
	nb_ui_attachment_view_update (self->current_note->attachments);
}

void
nb_global_delete_note (Global * self)
{
	GtkTreeSelection * selection = nb_ui_treeview_get_selection ();
	int count = gtk_tree_selection_count_selected_rows (selection);

	if ( count < 1 )
	{
		nb_ui_dialog_error ((gchar *) _("No note selected"));
		return ;
	}

	if ( count == 1 )
	{
		if ( !nb_ui_dialog_question ((gchar *) _("Do you want to delete current note?"), (gchar *) _("Delete note?")) )
			return ;
	}
	else
	{
		if ( !nb_ui_dialog_question ((gchar *) _("Do you want to delete all selected notes?"), (gchar *) _("Delete note?")) )
			return ;
	}

	GList * rr_list = NULL;    /* list of GtkTreeRowReferences to remove */
	GList * node;

	/* delete note(s) from file  and get list of notes' pointers */
	gtk_tree_selection_selected_foreach (selection, (GtkTreeSelectionForeachFunc) nb_global_cb_delete_note_from_file, &rr_list);

	/* delete note from treeview */
	for ( node = rr_list;  node != NULL;  node = node->next )
	{
		GtkTreePath * path;

		path = gtk_tree_row_reference_get_path ((GtkTreeRowReference *)node->data);

		if ( path )
		{
			GtkTreeIter  iter;

			if ( gtk_tree_model_get_iter ( GTK_TREE_MODEL(self->store), &iter, path) )
				gtk_list_store_remove( self->store, &iter);
		}
	}

	nb_ui_note_view_reset ();

	nb_note_free (self->current_note);
	self->current_note = nb_note_new ();
	self->inserted_note = NEW;
	self->modified_note = CLEAN;

	if ( count == 1 )
		nb_ui_statusbar_push ((gchar *) _("Note successfully deleted"));
	else
		nb_ui_statusbar_push(g_strdup_printf ((gchar *) _("%d notes successfully deleted"), count));
}

void
nb_global_update_note (Global * self)
{
	if ( nb_ui_note_view_is_empty () )
		return ;

	if ( nb_global_save_note (self) )
		nb_ui_statusbar_push ((gchar *) _("Successfully saved note to file."));
}

gboolean
nb_global_save_note (Global * self)
{
	/* update the current_note fields with the note_view */
	nb_note_set_title (self->current_note, nb_ui_note_view_get_title ());
	nb_note_set_text (self->current_note, nb_ui_note_view_get_text ());

	/* if the subject is empty prompt the user */
	if ( strlen (self->current_note->title) == 0 )
	{
		nb_ui_dialog_error ((gchar *) _("The note has no subject, please find one."));
		return FALSE;
	}

	if ( self->inserted_note == NEW )
	{
		if ( !nb_global_update_xml_file (self, self->current_note, ADD_NOTE) )
		{
			nb_ui_dialog_error ((gchar *) _("Failed to save note in file."));
			return FALSE;
		}
	}
	else
	{
		if ( !nb_global_update_xml_file (self, self->current_note, UPDATE_NOTE) )
		{
			nb_ui_dialog_error ((gchar *) _("Failed to save note in file."));
			return FALSE;
		}
	}

	/* if the note is new then add it to the list */
	if ( self->inserted_note == NEW )
	{
		self->inserted_note = INSERTED;
		nb_note_list_add (self->nl, self->current_note);
		nb_global_add_note_to_tree (self);
	}
	else
	{
		/* update the last_update field */
		nb_note_set_lastupdate (self->current_note, NULL);
		nb_global_update_current_note_in_tree (self);
	}

	self->modified_note = CLEAN;

	return TRUE;

}

void
nb_global_check_attachments (Global * self)
{
	nb_note_check_attachments (self->current_note);
}

/* import/export of NoteList */
void
nb_global_import_note_list (Global * self, gchar * filename)
{
	int i;
	Note * n;
	NoteList * nl = nb_note_list_new (filename);

	if ( !nb_note_list_load_xml_file (nl) )
		return;

	for ( i = 0 ; i < nb_note_list_get_nb (nl) ; i++ )
	{
		/* get the note */
		n = g_ptr_array_index (nl->notes, i);

		/* get note text from file */
		nb_note_set_text (n, nb_note_list_get_note_text_from_index (nl, i));

		/* update the file */
		if ( !nb_note_list_update_xml_file (self->nl, n, ADD_NOTE) )
		{
			nb_ui_dialog_error ((gchar *) _("Failed to save note in file"));
			return ;
		}

		/* add the note to the list */
		nb_note_list_add (self->nl, n);
	}

	/* update the tree view */
	nb_ui_treeview_update (NULL);
	nb_ui_statusbar_push ( g_strdup_printf ((gchar *) _("Successfully imported %d notes."), nl->notes->len));

	/* FIXME: we probably need to free nl here */
}

void
nb_global_export_note_list (Global * self, ExportType * type, gchar * filename)
{
	int i, nb = 0;
	Note * n; 
	NoteList * nl = nb_note_list_new (filename);

	for ( i = 0 ; i < nb_note_list_get_nb (self->nl) ; i++ )
	{
		/* get the note */
		n = g_ptr_array_index (self->nl->notes, i);

		if ( nb_note_matches_type (n, type))
		{
			nb_note_list_add (nl, n);
			/* get note text from file */
			nb_note_set_text (n, nb_note_list_get_note_text_from_index (self->nl, i));

			/* update the file */
			if ( !nb_note_list_update_xml_file (nl, n, ADD_NOTE) )
			{
				nb_ui_dialog_error ((gchar *) _("Failed to save note in file"));

				nb_note_list_free (nl);
				return ;
			}
			nb++;
		}
	}

	nb_ui_statusbar_push ( g_strdup_printf ((gchar *) _("Successfully exported %d notes."), nb));
	nb_note_list_free (nl);
}

/* quit */
gboolean
nb_global_quit (Global * self)
{
	if  ( self->modified_note == EDITED )
	{
		if ( (self->inserted_note == INSERTED) || !nb_ui_note_view_is_empty () )
		{
			if ( !nb_ui_dialog_question ((gchar *) _("Do you want to save note?"), (gchar *) _("Save note?")) )
				return TRUE;

			if ( !nb_global_save_note (self) )
				return FALSE;
		}
	}

	return TRUE;
}

/* read/write from/to xml doc */
gboolean
nb_global_update_xml_file (Global * self, Note * n, gint action)
{
	return nb_note_list_update_xml_file (self->nl, n, action);
}

/* callbacks */
static gboolean
nb_global_cb_delete_note_from_file (GtkTreeModel * model, GtkTreePath * path, GtkTreeIter * iter, GList ** rowref_list)
{
	Note * n;
	extern Global * g;

	g_assert ( rowref_list != NULL );

	gtk_tree_model_get (model, iter, NOTE_POINTER_COLUMN, &n, -1);

	/* delete the note from the xml file */
	if ( !nb_global_update_xml_file (g, n, REMOVE_NOTE) )
		nb_ui_dialog_error ((gchar *) _("Failed to delete note from file"));
	else
	{
		GtkTreeRowReference  * rowref;

		rowref = gtk_tree_row_reference_new (model, path);

		*rowref_list = g_list_append (* rowref_list, rowref);

		/* remove the note from the notelist */
		nb_note_list_remove (g->nl, n);
	}

	return FALSE;
}

/* static functions */
static void
nb_global_add_note_to_tree (Global * self)
{
	gchar * type = (gchar *) _(note_type_string [self->current_note->type]);
	gchar * status = (gchar *) _(note_type_string [self->current_note->status]);
	gchar * date = (gchar *) nb_util_get_date_string (self->current_note->date);
	gchar * update = (gchar *) nb_util_get_date_string (self->current_note->update);

	nb_ui_treeview_add_note (self->current_note->title, 
				 type, status, 
				 date, update,
				 self->current_note,
				 TRUE);

	g_free (date);
	g_free (update);
}

static void
nb_global_update_current_note_in_tree (Global * self)
{
	gchar * type = (gchar *) _(note_type_string [self->current_note->type]);
	gchar * status = (gchar *) _(note_type_string [self->current_note->status]);
	gchar * update = (gchar *) nb_util_get_date_string (self->current_note->update);

	nb_ui_treeview_update_note (self->current_note->title, type, status, update, self->current_note);

	g_free (update);
}

static gchar * 
nb_global_get_config (Global * self)
{
	GConfClient * client;
	gchar * notefile = NULL;
	gchar * browser = NULL;
	gchar * configpath = NULL;

	client = gconf_client_get_default ();

	notefile = gconf_client_get_string (client, "/apps/notebook/config/notes_file", NULL);
	browser = gconf_client_get_string (client, "/desktop/gnome/url-handlers/http/command", NULL);

	if ( browser == NULL )
		browser = gconf_client_get_string (client, "/apps/notebook/config/browser", NULL);

	if ( notefile == NULL)
	{
		/* try to create the config directory if it doesn't already exist */
		configpath = g_strdup_printf ("%s/%s", g_get_home_dir (), DEFAULT_CONFIG_DIR);

		if ( mkdir ( configpath, 0777) == -1 )
		{
			if ( errno != EEXIST )
			{
				perror ("Can't create default directory: ");
				exit (EXIT_FAILURE);
			}
		}

		notefile = g_strdup_printf ("%s/%s/%s", g_get_home_dir (), DEFAULT_CONFIG_DIR, DEFAULT_NOTES_FILE);
		gconf_client_set_string (client, "/apps/notebook/config/notes_file", notefile, NULL);
	}

	if ( browser == NULL)
	{
		browser = g_strdup_printf ("mozilla-firefox");
		gconf_client_set_string (client, "/apps/notebook/config/browser", browser, NULL);
	}

	self->default_browser = browser;

	/* TODO: set callback to update default browser on gconf key change */

	return notefile;
}

void
nb_global_launch_web_browser (Global * self, gchar * url)
{
	gchar ** split;
	gchar * command;

	if ( fork() == 0 )
	{
		if (  g_strrstr (self->default_browser, "%s") != NULL )
		{
			split = g_strsplit (self->default_browser, "%s", 2);
			command = g_strdup_printf ("%s%s%s", split[0], url, split[1]);
			g_strfreev(split);

			split = g_strsplit (command, " ", 0);
			g_strstrip(split[0]);

			execvp (split[0], split);
			perror ("exec: ");
			exit (1);
		}
		else
		{
			execlp (self->default_browser, self->default_browser, url, NULL);
			perror ("exec: ");
			exit (1);
		}
	}

}

void
nb_global_add_attachments (Global * self, GSList * selection)
{
	GSList * l = selection;
	Attachment * a;

	do
	{
		if ( l->data == NULL )
			break;

		a = nb_attachment_new (l->data, (gchar * ) gnome_vfs_get_mime_type (l->data));

		if ( nb_note_add_attachment (self->current_note, a) )
			self->modified_note = EDITED;

		l = l->next;
	}
	while ( l != NULL );

	nb_ui_attachment_view_update (self->current_note->attachments);
}
