/*
 *  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 "mozilla.h"
#include "find.h"
#include "glade.h"
#include "dialog.h"
#include "prefs_strings.h"
#include "eel-gconf-extensions.h"

#include <gtk/gtktogglebutton.h>
#include <gtk/gtkentry.h>
#include <libgnomeui/gnome-entry.h>

/**
 * FindDialog: structure representing a "find in document" dialog
 */
typedef struct
{
	GtkWidget *dialog;
	GtkWidget *entry;
	GtkWidget *gnome_entry;
	GtkWidget *case_checkbutton;
	GtkWidget *word_checkbutton;
	GtkWidget *wrap_checkbutton;
	GtkWidget *frames_checkbutton;
	GtkWidget *prev_button;
	GtkWidget *next_button;
	gboolean string_changed;
	GaleonWindow *window;
}
FindDialog;

/**
 * item: stolen from gnome-entry.c so that we can access the text in
 * the history list.  This must be kept in sync with gnome-entry.c.
 */
struct item {
	gboolean save;
	gchar *text;
};

void find_next_button_clicked_cb (GtkButton *button, FindDialog *find_dialog);
void find_prev_button_clicked_cb (GtkButton *button, FindDialog *find_dialog);
void find_close_button_clicked_cb (GtkButton *button, FindDialog *find_dialog); 
void find_destroy_cb (GtkObject *object, FindDialog *find_dialog);
void reset_find_on_check_toggled_cb (GtkToggleButton *togglebutton, FindDialog *find_dialog);
void find_entry_activate_cb (GtkEditable *editable, FindDialog *find_dialog);
void find_entry_changed_cb  (GtkEditable *editable, FindDialog *find_dialog);
static void find_reset (FindDialog *find_dialog);
static gboolean find_go (FindDialog *find_dialog, 
			 gboolean backwards);
static void find_lookup_widgets (FindDialog *find, GladeXML *gxml);
static void find_controls_set_sensitive (FindDialog *find);

/**
 * embed_show_find_dialog: show the find dialog
 */
void find_show_dialog (GaleonWindow *window)
{
	GladeXML *gxml;
	FindDialog *find;

	return_if_not_window (window);
	
	if (window->find_dialog == NULL)
	{
		/* Create the dialog and initialize data*/
		find = g_new0 (FindDialog, 1);
		find->window = window;
		gxml = glade_widget_new ("galeon.glade", "find_dialog", 
					 &(find->dialog), find);
		find_lookup_widgets (find, gxml);		
		window->find_dialog = find->dialog;
		find->string_changed = TRUE;
		gtk_object_unref (GTK_OBJECT (gxml));

		/* HACK Set last search text */
		if (GNOME_ENTRY(find->gnome_entry)->items &&
		    GNOME_ENTRY(find->gnome_entry)->items->data)
		{
			gtk_entry_set_text(GTK_ENTRY(find->entry),
					   ((struct item *)
					    GNOME_ENTRY(find->gnome_entry)->
					    items->data)->text);
			gtk_editable_select_region(GTK_EDITABLE(find->entry),
					0, -1);
		}

		find_controls_set_sensitive (find);

		dialog_set_parent (find->dialog, window->WMain);
	}
	else
	{
		gdk_window_raise(window->find_dialog->window);
		//TODO: focus the dialog somehow.
	}
}

static void
find_lookup_widgets (FindDialog *find, GladeXML *gxml)
{
	find->gnome_entry = glade_xml_get_widget (gxml, 
						  "find_gnome_entry");
	find->entry = glade_xml_get_widget (gxml, "find_entry");
	find->prev_button = glade_xml_get_widget (gxml, "BPrev");
	find->next_button = glade_xml_get_widget (gxml, "BNext");
	find->case_checkbutton = glade_xml_get_widget (gxml, 
						       "case_check");
	find->word_checkbutton = glade_xml_get_widget (gxml, 
						       "word_check");
	find->wrap_checkbutton = glade_xml_get_widget (gxml, 
						       "wrap_check");
	find->frames_checkbutton = glade_xml_get_widget (gxml, 
							 "frames_check");
}

static void
find_controls_set_sensitive (FindDialog *find)
{
	gtk_toggle_button_set_active
		(GTK_TOGGLE_BUTTON (find->case_checkbutton),
		 eel_gconf_get_boolean (CONF_FIND_MATCH_CASE));
	gtk_toggle_button_set_active
		(GTK_TOGGLE_BUTTON (find->word_checkbutton),
		 eel_gconf_get_boolean (CONF_FIND_MATCH_WORD));
	gtk_toggle_button_set_active
		(GTK_TOGGLE_BUTTON (find->frames_checkbutton),
		 eel_gconf_get_boolean (CONF_FIND_SEARCH_IN_FRAMES));
	gtk_toggle_button_set_active
		(GTK_TOGGLE_BUTTON (find->wrap_checkbutton),
		 !eel_gconf_get_boolean (CONF_FIND_AUTOWRAP));
}

void find_destroy_dialog (GaleonWindow *window)
{
	gtk_widget_destroy (window->find_dialog);
	window->find_dialog = NULL;
}

/**
 * find_next_button_clicked_cb: next button clicked
 */
void find_next_button_clicked_cb (GtkButton *button, FindDialog *find_dialog)
{
	gtk_widget_set_sensitive (find_dialog->prev_button, TRUE);
	if (!find_go (find_dialog, FALSE))
	{
		gtk_widget_set_sensitive
			(GTK_WIDGET(find_dialog->next_button), FALSE);
	}
}

/**
 * find_prev_button_clicked_cb: previous button clicked
 */
void
find_prev_button_clicked_cb (GtkButton *button, FindDialog *find_dialog)
{
	gtk_widget_set_sensitive (find_dialog->next_button, TRUE);
	if (!find_go (find_dialog, TRUE))
	{
		gtk_widget_set_sensitive
			(GTK_WIDGET(find_dialog->prev_button),  FALSE);
	}
}

/**
 * find_close_button_clicked_cb: close button clicked
 */
void
find_close_button_clicked_cb (GtkButton *button, FindDialog *find_dialog) 
{
	gtk_widget_destroy(find_dialog->dialog);
}

/**
 * find_destroy_cb: destroy find dialog
 */
void
find_destroy_cb (GtkObject *object, FindDialog *find_dialog)
{
	/* save options */
	eel_gconf_set_boolean (CONF_FIND_MATCH_CASE,
		gtk_toggle_button_get_active
			(GTK_TOGGLE_BUTTON (find_dialog->case_checkbutton)));
	eel_gconf_set_boolean (CONF_FIND_MATCH_WORD,
		gtk_toggle_button_get_active
			(GTK_TOGGLE_BUTTON (find_dialog->word_checkbutton)));
	eel_gconf_set_boolean (CONF_FIND_SEARCH_IN_FRAMES,
		gtk_toggle_button_get_active
			(GTK_TOGGLE_BUTTON (find_dialog->frames_checkbutton)));
	eel_gconf_set_boolean (CONF_FIND_AUTOWRAP,
		!gtk_toggle_button_get_active
			(GTK_TOGGLE_BUTTON (find_dialog->wrap_checkbutton)));

	find_dialog->window->find_dialog = NULL;
	g_free (find_dialog);
}

/**
 * reset_find_on_check_toggled_cb: Reset the find process if one of the checkbox
 * settings has changed.
 */
void 
reset_find_on_check_toggled_cb (GtkToggleButton *togglebutton,
				FindDialog *find_dialog)
{
	find_reset (find_dialog);
}

/**
 * find_entry_activate_cb: entry activated
 */
void 
find_entry_activate_cb (GtkEditable *editable, FindDialog *find_dialog) 
{
	gtk_widget_set_sensitive (find_dialog->prev_button, TRUE);
	if (!find_go (find_dialog, FALSE))
	{
		gtk_widget_set_sensitive
			(GTK_WIDGET(find_dialog->next_button), FALSE);
	}
}

/**
 * find_entry_changed_cb: entry changed
 */
void
find_entry_changed_cb  (GtkEditable *editable, FindDialog *find_dialog)
{
	find_dialog->string_changed = TRUE;
	find_reset (find_dialog);
}

static void
find_reset (FindDialog *find_dialog)
{
	gtk_widget_set_sensitive (find_dialog->next_button, TRUE);
	gtk_widget_set_sensitive (find_dialog->prev_button, TRUE);
}

static gboolean 
find_go (FindDialog *find_dialog, 
	 gboolean backwards)
{
	WrapperSearchProperties *properties;
	gchar *search_string;
	gboolean result;
	GaleonEmbed *embed;

	embed = find_dialog->window->active_embed;
	return_val_if_not_embed (embed, FALSE);

	/* get the search string from the entry field */
	search_string = gtk_editable_get_chars
		(GTK_EDITABLE (find_dialog->entry), 0, -1);

	/* don't do null searches */
	if (search_string[0] == '\0')
	{
		return FALSE;
	}

	/* build search structure */
	properties = g_new0 (WrapperSearchProperties,1);
	properties->search_string = search_string;
	properties->backwards =  backwards;
	properties->match_case = gtk_toggle_button_get_active 
		(GTK_TOGGLE_BUTTON (find_dialog->case_checkbutton));
	properties->wrap = !gtk_toggle_button_get_active 
		(GTK_TOGGLE_BUTTON (find_dialog->wrap_checkbutton));
	properties->entire_word = gtk_toggle_button_get_active 
		(GTK_TOGGLE_BUTTON (find_dialog->word_checkbutton));
	properties->search_frames = gtk_toggle_button_get_active 
		(GTK_TOGGLE_BUTTON (find_dialog->frames_checkbutton));

	/* store the search string in the find history */
	if (find_dialog->string_changed)
	{
		gnome_entry_append_history 
			(GNOME_ENTRY (find_dialog->gnome_entry),
			 TRUE, search_string);
		find_dialog->string_changed = FALSE;
	}

	/* do the find */
	result = mozilla_find (embed, properties);

	/* free structure */
	g_free (properties->search_string);
	g_free (properties);

	/* success or not */
	return result;
}

/**
 * find_next: find the next occurance of a string, used by smart bookmarks
 * phrase searching
 */
gboolean
find_next (GaleonEmbed *embed, const gchar *string)
{
	WrapperSearchProperties *properties;
	gboolean result;

	properties = g_new0 (WrapperSearchProperties, 1);
	properties->search_string = g_strdup (string);
	properties->backwards = FALSE;
	properties->match_case =
		eel_gconf_get_boolean (CONF_FIND_MATCH_CASE);
	properties->entire_word =
		eel_gconf_get_boolean (CONF_FIND_MATCH_WORD);
	properties->search_frames =
		eel_gconf_get_boolean (CONF_FIND_SEARCH_IN_FRAMES);
	properties->wrap =
		eel_gconf_get_boolean (CONF_FIND_AUTOWRAP);

	result = mozilla_find (embed, properties);

	g_free (properties->search_string);
	g_free (properties);

	return result;
}
