/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*  This file is part of the GtkHTML library.
 *
 *  Copyright 1999, 2000 Helix Code, Inc.
 *  Authors:             Radek Doulik (rodo@helixcode.com)
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library 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
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public License
 *  along with this library; see the file COPYING.LIB.  If not, write to
 *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *  Boston, MA 02110-1301, USA.
*/

#include <config.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include "gtkhtml.h"
#include "gtkhtml-private.h"
#include "gtkhtml-search.h"
#include "htmlengine-search.h"
#include "htmlsearch.h"
#include "htmlselection.h"

struct _GtkHTMLISearch {
	GtkHTML  *html;
	gboolean forward;
	gboolean changed;
	guint focus_out;
	gchar *last_text;
};
typedef struct _GtkHTMLISearch GtkHTMLISearch;

static void
changed (GtkEntry *entry,
         GtkHTMLISearch *data)
{
	/* printf ("isearch changed to '%s'\n", gtk_entry_get_text (entry)); */
	if (*gtk_entry_get_text (GTK_ENTRY (data->html->priv->search_input_line))) {
		html_engine_search_incremental (data->html->engine,
						gtk_entry_get_text (GTK_ENTRY (data->html->priv->search_input_line)),
						data->forward);
	} else
		html_engine_unselect_all (data->html->engine);
	data->changed = TRUE;
}

static void
continue_search (GtkHTMLISearch *data,
                 gboolean forward)
{
	HTMLEngine *e = data->html->engine;

	if (!data->changed && data->last_text && *data->last_text) {
		gtk_entry_set_text (GTK_ENTRY (data->html->priv->search_input_line), data->last_text);
		html_engine_search_incremental (data->html->engine, data->last_text, forward);
		data->changed = TRUE;
	} else if (*gtk_entry_get_text (GTK_ENTRY (data->html->priv->search_input_line))) {
		if (e->search_info)
			html_search_set_forward (e->search_info, forward);
		html_engine_search_next (e);
	}
	data->forward = forward;
}

static gboolean
hide (GtkHTMLISearch *data)
{
	g_signal_handler_disconnect (data->html->priv->search_input_line, data->focus_out);
	gtk_grab_remove (GTK_WIDGET (data->html->priv->search_input_line));
	gtk_widget_grab_focus (GTK_WIDGET (data->html));
	gtk_widget_hide (GTK_WIDGET (data->html->priv->search_input_line));

	return FALSE;
}

static void
data_destroy (GtkHTMLISearch *data)
{
	g_free (data->last_text);
	g_free (data);
}

static gint
key_press (GtkWidget *widget,
           GdkEventKey *event,
           GtkHTMLISearch *data)
{
	gint rv = TRUE;

	if (event->state & GDK_CONTROL_MASK && event->keyval == GDK_KEY_s) {
		continue_search (data, TRUE);
	} else if (event->state & GDK_CONTROL_MASK && event->keyval == GDK_KEY_r) {
		continue_search (data, FALSE);
	} else if (event->keyval == GDK_KEY_Escape) {
		hide (data);
	} else
		rv = FALSE;

	return rv;
}

static gint
focus_out_event (GtkWidget *widget,
                 GdkEventFocus *event,
                 GtkHTMLISearch *data)
{
	hide (data);

	return FALSE;
}

static void
destroy (GtkWidget *w,
         GtkHTMLISearch *data)
{
	data_destroy (data);
}

void
gtk_html_isearch (GtkHTML *html,
                  gboolean forward)
{
	GtkHTMLISearch *data;

	if (!html->editor_api->create_input_line)
		return;

	if (!html->priv->search_input_line) {
		html->priv->search_input_line  = (*html->editor_api->create_input_line) (html, html->editor_data);
		if (!html->priv->search_input_line)
			return;
		g_object_ref (html->priv->search_input_line);

		data = g_new (GtkHTMLISearch, 1);
		g_object_set_data (G_OBJECT (html->priv->search_input_line), "search_data", data);

		data->html      = html;

		g_signal_connect (html->priv->search_input_line, "key_press_event", G_CALLBACK (key_press), data);
		g_signal_connect (html->priv->search_input_line, "changed", G_CALLBACK (changed), data);
		g_signal_connect (html->priv->search_input_line, "destroy", G_CALLBACK (destroy), data);
	} else {
		gtk_widget_show (GTK_WIDGET (html->priv->search_input_line));
		data = (GtkHTMLISearch *) g_object_get_data (G_OBJECT (html->priv->search_input_line), "search_data");
	}

	data->forward   = forward;
	data->changed   = FALSE;
	data->last_text = NULL;

	if (html->engine->search_info) {
		data->last_text = g_strdup (html->engine->search_info->text);
		html_search_set_text (html->engine->search_info, "");
	}

	gtk_widget_grab_focus (GTK_WIDGET (html->priv->search_input_line));
	data->focus_out = g_signal_connect (html->priv->search_input_line, "focus_out_event",
					    G_CALLBACK (focus_out_event), data);
}

gboolean
gtk_html_engine_search (GtkHTML *html,
                        const gchar *text,
                        gboolean case_sensitive,
                        gboolean forward,
                        gboolean regular)
{
	return html_engine_search (html->engine, text, case_sensitive, forward, regular);
}

void
gtk_html_engine_search_set_forward (GtkHTML *html,
                                    gboolean forward)
{
	html_engine_search_set_forward (html->engine, forward);
}

gboolean
gtk_html_engine_search_next (GtkHTML *html)
{
	return html_engine_search_next (html->engine);
}

gboolean
gtk_html_engine_search_incremental (GtkHTML *html,
                                    const gchar *text,
                                    gboolean forward)
{
	return html_engine_search_incremental (html->engine, text, forward);
}
