/*
 * test-html-editor.c
 *
 * Copyright (C) 2012 Dan Vrátil <dvratil@redhat.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) version 3.
 *
 * 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with the program; if not, see <http://www.gnu.org/licenses/>
 *
 */

#include "evolution-config.h"

#include <gtk/gtk.h>
#include <e-util/e-util.h>

#include <glib/gi18n-lib.h>

/* Enable it, once printing is implemented (it doesn't work to do it
   on a WebKit side, because the EContentEditor can be a different
   structure. That might be why EMsgComposer uses a "print" signal,
   which prints a constructed message, like within the message preview. */
/* #define ENABLE_PRINT */

static const gchar *file_ui =
"<ui>\n"
"  <menubar name='main-menu'>\n"
"    <menu action='file-menu'>\n"
"     <menuitem action='new-editor'/>\n"
"     <separator/>\n"
"     <menuitem action='save'/>\n"
"     <menuitem action='save-as'/>\n"
#ifdef ENABLE_PRINT
"     <separator/>\n"
"     <menuitem action='print-preview'/>\n"
"     <menuitem action='print'/>\n"
#endif /* ENABLE_PRINT */
"     <separator/>\n"
"     <menuitem action='disable-editor'/>\n"
"     <separator/>\n"
"     <menuitem action='quit'/>\n"
"    </menu>\n"
"  </menubar>\n"
"</ui>";

static const gchar *view_ui =
"<ui>\n"
"  <menubar name='main-menu'>\n"
"    <menu action='view-menu'>\n"
"     <menuitem action='view-html-output'/>\n"
"     <menuitem action='view-html-source'/>\n"
"     <menuitem action='view-plain-source'/>\n"
"     <separator/>\n"
"     <menuitem action='view-webkit-inspector'/>\n"
"    </menu>\n"
"  </menubar>\n"
"</ui>";

static void create_new_editor (void);

static void
handle_error (GError **error)
{
	if (*error != NULL) {
		g_warning ("%s", (*error)->message);
		g_clear_error (error);
	}
}

#ifdef ENABLE_PRINT
static void
print (EHTMLEditor *editor,
       GtkPrintOperationAction action)
{
	WebKitWebFrame *frame;
	GtkPrintOperation *operation;
	GtkPrintOperationResult result;
	GError *error = NULL;

	operation = gtk_print_operation_new ();

	frame = webkit_web_view_get_main_frame (
		WEBKIT_WEB_VIEW (e_html_editor_get_view (editor)));
	webkit_web_frame_print_full (frame, operation, action, NULL);

	g_object_unref (operation);
	handle_error (&error);
}
#endif

static gint
save_dialog (EHTMLEditor *editor)
{
	GtkWidget *dialog;
	const gchar *filename;
	gint response;

	dialog = gtk_file_chooser_dialog_new (
		_("Save As"),
		GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (editor))),
		GTK_FILE_CHOOSER_ACTION_SAVE,
		_("_Cancel"), GTK_RESPONSE_CANCEL,
		_("_Save"), GTK_RESPONSE_ACCEPT,
		NULL);

	gtk_file_chooser_set_do_overwrite_confirmation (
		GTK_FILE_CHOOSER (dialog), TRUE);

	filename = e_html_editor_get_filename (editor);

	if (filename != NULL)
		gtk_file_chooser_set_filename (
			GTK_FILE_CHOOSER (dialog), filename);
	else
		gtk_file_chooser_set_current_name (
			GTK_FILE_CHOOSER (dialog), _("Untitled document"));

	response = gtk_dialog_run (GTK_DIALOG (dialog));

	if (response == GTK_RESPONSE_ACCEPT) {
		gchar *new_filename;

		new_filename = gtk_file_chooser_get_filename (
			GTK_FILE_CHOOSER (dialog));
		e_html_editor_set_filename (editor, new_filename);
		g_free (new_filename);
	}

	gtk_widget_destroy (dialog);

	return response;
}

static void
view_source_dialog (EHTMLEditor *editor,
                    const gchar *title,
                    gboolean plain_text,
                    gboolean show_source)
{
	GtkWidget *dialog;
	GtkWidget *content;
	GtkWidget *content_area;
	GtkWidget *scrolled_window;
	EContentEditor *cnt_editor;
	gchar * html;

	cnt_editor = e_html_editor_get_content_editor (editor);

	dialog = gtk_dialog_new_with_buttons (
		title,
		GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (editor))),
		GTK_DIALOG_DESTROY_WITH_PARENT,
		_("_Close"), GTK_RESPONSE_CLOSE,
		NULL);

	content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));

	scrolled_window = gtk_scrolled_window_new (NULL, NULL);
	gtk_scrolled_window_set_policy (
		GTK_SCROLLED_WINDOW (scrolled_window),
		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
	gtk_scrolled_window_set_shadow_type (
		GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_IN);
	gtk_box_pack_start (
		GTK_BOX (content_area),
		scrolled_window, TRUE, TRUE, 0);

	gtk_container_set_border_width (GTK_CONTAINER (dialog), 6);
	gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 6);
	gtk_window_set_default_size (GTK_WINDOW (dialog), 400, 300);

	if (plain_text) {
		html = e_content_editor_get_content (cnt_editor,
			E_CONTENT_EDITOR_GET_PROCESSED | E_CONTENT_EDITOR_GET_TEXT_PLAIN,
			NULL, NULL);
	} else {
		GSList *inline_images = NULL;

		html = e_content_editor_get_content (cnt_editor,
			E_CONTENT_EDITOR_GET_PROCESSED | E_CONTENT_EDITOR_GET_TEXT_HTML | E_CONTENT_EDITOR_GET_INLINE_IMAGES,
			"test-domain", &inline_images);

		g_slist_free_full (inline_images, g_object_unref);
	}

	if (show_source || plain_text) {
		GtkTextBuffer *buffer;

		content = gtk_text_view_new ();
		buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (content));
		gtk_text_buffer_set_text (buffer, html, -1);
		gtk_text_view_set_editable (GTK_TEXT_VIEW (content), FALSE);
	} else {
		content = webkit_web_view_new ();
		webkit_web_view_load_html (WEBKIT_WEB_VIEW (content), html, "evo-file://");
	}
	g_free (html);

	gtk_container_add (GTK_CONTAINER (scrolled_window), content);
	gtk_widget_show_all (scrolled_window);

	gtk_dialog_run (GTK_DIALOG (dialog));
	gtk_widget_destroy (dialog);
}

static void
action_new_editor_cb (GtkAction *action,
		      EHTMLEditor *editor)
{
	create_new_editor ();
}

#ifdef ENABLE_PRINT
static void
action_print_cb (GtkAction *action,
                 EHTMLEditor *editor)
{
	print (editor, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG);
}

static void
action_print_preview_cb (GtkAction *action,
                         EHTMLEditor *editor)
{
	print (editor, GTK_PRINT_OPERATION_ACTION_PREVIEW);
}
#endif /* ENABLE_PRINT */

static void
action_quit_cb (GtkAction *action,
                EHTMLEditor *editor)
{
	gtk_main_quit ();
}

static void
action_save_cb (GtkAction *action,
                EHTMLEditor *editor)
{
	const gchar *filename;
	gboolean as_html;
	GError *error = NULL;

	if (e_html_editor_get_filename (editor) == NULL)
		if (save_dialog (editor) == GTK_RESPONSE_CANCEL)
			return;

	filename = e_html_editor_get_filename (editor);
	as_html = (e_content_editor_get_html_mode (e_html_editor_get_content_editor (editor)));

	e_html_editor_save (editor, filename, as_html, &error);
	handle_error (&error);
}

static void
action_save_as_cb (GtkAction *action,
                   EHTMLEditor *editor)
{
	const gchar *filename;
	gboolean as_html;
	GError *error = NULL;

	if (save_dialog (editor) == GTK_RESPONSE_CANCEL)
		return;

	filename = e_html_editor_get_filename (editor);
	as_html = (e_content_editor_get_html_mode (e_html_editor_get_content_editor (editor)));

	e_html_editor_save (editor, filename, as_html, &error);
	handle_error (&error);
}

static void
action_toggle_editor (GtkAction *action,
                      EHTMLEditor *editor)
{
	EContentEditor *cnt_editor;

	cnt_editor = e_html_editor_get_content_editor (editor);
	e_content_editor_set_editable (cnt_editor, !e_content_editor_is_editable (cnt_editor));
}

static void
action_view_html_output (GtkAction *action,
                         EHTMLEditor *editor)
{
	view_source_dialog (editor, _("HTML Output"), FALSE, FALSE);
}

static void
action_view_html_source (GtkAction *action,
                         EHTMLEditor *editor)
{
	view_source_dialog (editor, _("HTML Source"), FALSE, TRUE);
}

static void
action_view_plain_source (GtkAction *action,
                          EHTMLEditor *editor)
{
	view_source_dialog (editor, _("Plain Source"), TRUE, FALSE);
}

static void
action_view_inspector (GtkAction *action,
                       EHTMLEditor *editor)
{
	WebKitWebInspector *inspector;
	EContentEditor *cnt_editor;

	cnt_editor = e_html_editor_get_content_editor (editor);
	if (WEBKIT_IS_WEB_VIEW (cnt_editor)) {
		inspector = webkit_web_view_get_inspector (WEBKIT_WEB_VIEW (cnt_editor));
		webkit_web_inspector_show (inspector);
	} else {
		g_print ("Cannot show the inspector, the content editor is not a WebKitWebView descendant\n");
	}
}

static GtkActionEntry file_entries[] = {
	{ "new-editor",
	  "document-new",
	  N_("_New editor"),
	  "<Control>N",
	  NULL,
	  G_CALLBACK (action_new_editor_cb) },

#ifdef ENABLE_PRINT
	{ "print",
	  "document-print",
	  N_("_Print..."),
	  "<Control>p",
	  NULL,
	  G_CALLBACK (action_print_cb) },

	{ "print-preview",
	  "document-print-preview",
	  N_("Print Pre_view"),
	  "<Control><Shift>p",
	  NULL,
	  G_CALLBACK (action_print_preview_cb) },
#endif /* ENABLE_PRINT */

	{ "quit",
	  "application-exit",
	  N_("_Quit"),
	  NULL,
	  NULL,
	  G_CALLBACK (action_quit_cb) },

	{ "save",
	  "document-save",
	  N_("_Save"),
	  NULL,
	  NULL,
	  G_CALLBACK (action_save_cb) },

	{ "save-as",
	  "document-save-as",
	  N_("Save _As..."),
	  NULL,
	  NULL,
	  G_CALLBACK (action_save_as_cb) },

	{ "disable-editor",
	  NULL,
	  N_("Disable/Enable Editor"),
	  NULL,
	  NULL,
	  G_CALLBACK (action_toggle_editor) },

	{ "file-menu",
	  NULL,
	  N_("_File"),
	  NULL,
	  NULL,
	  NULL }
};

static GtkActionEntry view_entries[] = {

	{ "view-html-output",
	  NULL,
	  N_("HTML _Output"),
	  NULL,
	  NULL,
	  G_CALLBACK (action_view_html_output) },

	{ "view-html-source",
	  NULL,
	  N_("_HTML Source"),
	  NULL,
	  NULL,
	  G_CALLBACK (action_view_html_source) },

	{ "view-plain-source",
	  NULL,
	  N_("_Plain Source"),
	  NULL,
	  NULL,
	  G_CALLBACK (action_view_plain_source) },

	{ "view-webkit-inspector",
	  NULL,
	  N_("Inspector"),
	  NULL,
	  "<Control><Shift>I",
	  G_CALLBACK (action_view_inspector) },

	{ "view-menu",
	  NULL,
	  N_("_View"),
	  NULL,
	  NULL,
	  NULL }
};

static guint glob_editors = 0;

static void
editor_destroyed_cb (GtkWidget *editor)
{
	g_return_if_fail (glob_editors > 0);

	glob_editors--;

	if (!glob_editors)
		gtk_main_quit ();
}

static void
create_new_editor_cb (GObject *source_object,
		      GAsyncResult *result,
		      gpointer user_data)
{
	GtkActionGroup *action_group;
	GtkUIManager *manager;
	GtkWidget *container;
	GtkWidget *widget;
	EHTMLEditor *editor;
	EContentEditor *cnt_editor;
	GError *error = NULL;

	widget = e_html_editor_new_finish (result, &error);
	if (error) {
		g_warning ("%s: Failed to create HTML editor: %s", G_STRFUNC, error->message);
		g_clear_error (&error);
		editor_destroyed_cb (NULL);
		return;
	}

	editor = E_HTML_EDITOR (widget);
	cnt_editor = e_html_editor_get_content_editor (editor);

	g_object_set (G_OBJECT (editor),
		"halign", GTK_ALIGN_FILL,
		"hexpand", TRUE,
		"valign", GTK_ALIGN_FILL,
		"vexpand", TRUE,
		NULL);

	g_object_set (G_OBJECT (cnt_editor),
		"halign", GTK_ALIGN_FILL,
		"hexpand", TRUE,
		"valign", GTK_ALIGN_FILL,
		"vexpand", TRUE,
		NULL);

	if (WEBKIT_IS_WEB_VIEW (cnt_editor)) {
		WebKitSettings *web_settings;

		web_settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (cnt_editor));
		webkit_settings_set_allow_file_access_from_file_urls (web_settings, TRUE);
		webkit_settings_set_enable_developer_extras (web_settings, TRUE);
	}

	widget = gtk_window_new (GTK_WINDOW_TOPLEVEL);
	gtk_widget_set_size_request (widget, 600, 400);
	gtk_widget_show (widget);

	g_signal_connect_swapped (
		widget, "destroy",
		G_CALLBACK (editor_destroyed_cb), NULL);

	g_signal_connect (widget, "key-press-event",
		G_CALLBACK (e_util_check_gtk_bindings_in_key_press_event_cb), NULL);

	container = widget;

	widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
	gtk_container_add (GTK_CONTAINER (container), widget);
	gtk_widget_show (widget);

	container = widget;

	widget = e_html_editor_get_managed_widget (editor, "/main-menu");
	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
	gtk_widget_show (widget);

	widget = e_html_editor_get_managed_widget (editor, "/main-toolbar");
	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
	gtk_widget_show (widget);

	widget = GTK_WIDGET (editor);
	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
	gtk_widget_show (widget);

	gtk_widget_grab_focus (GTK_WIDGET (cnt_editor));

	manager = e_html_editor_get_ui_manager (editor);

	gtk_ui_manager_add_ui_from_string (manager, file_ui, -1, &error);
	handle_error (&error);

	gtk_ui_manager_add_ui_from_string (manager, view_ui, -1, &error);
	handle_error (&error);

	action_group = gtk_action_group_new ("file");
	gtk_action_group_set_translation_domain (
		action_group, GETTEXT_PACKAGE);
	gtk_action_group_add_actions (
		action_group, file_entries,
		G_N_ELEMENTS (file_entries), editor);
	gtk_ui_manager_insert_action_group (manager, action_group, 0);

	action_group = gtk_action_group_new ("view");
	gtk_action_group_set_translation_domain (
		action_group, GETTEXT_PACKAGE);
	gtk_action_group_add_actions (
		action_group, view_entries,
		G_N_ELEMENTS (view_entries), editor);
	gtk_ui_manager_insert_action_group (manager, action_group, 0);

	if (!WEBKIT_IS_WEB_VIEW (cnt_editor)) {
		GtkAction *action;

		action = e_html_editor_get_action (editor, "view-webkit-inspector");
		gtk_action_set_visible (action, FALSE);
	}

	gtk_ui_manager_ensure_update (manager);
}

static void
create_new_editor (void)
{
	glob_editors++;

	e_html_editor_new (create_new_editor_cb, NULL);
}

gint
main (gint argc,
      gchar **argv)
{
	GList *modules;

	bindtextdomain (GETTEXT_PACKAGE, EVOLUTION_LOCALEDIR);
	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
	textdomain (GETTEXT_PACKAGE);

	gtk_init (&argc, &argv);

	e_util_init_main_thread (NULL);
	e_passwords_init ();

	modules = e_module_load_all_in_directory (EVOLUTION_MODULEDIR);
	g_list_free_full (modules, (GDestroyNotify) g_type_module_unuse);

	create_new_editor ();

	gtk_main ();

	e_util_cleanup_settings ();
	e_spell_checker_free_global_memory ();

	return 0;
}
