/** \file ixhelp.c
 * use the Webkit2-based help system
 */

/*  XTrkCad - Model Railroad CAD
 *  Copyright (C) 2015 Martin Fischer
 *
 *  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.
 */

#include <stdlib.h>
#include <assert.h>

#include "gtkint.h"
#include "i18n.h"

#include <webkit/webkit.h>

void load_into_view(char *file,
                    int requested_view);	// Prototype to please clang.

/* globals and defines related to the HTML help window */

#define  HTMLERRORTEXT "<html><head><meta http-equiv=\"content-type\" content=\"text/html; charset=US-ASCII\">" \
								"<title>Help Error</title><body><h1>Error - help information can not be found.</h1><p>" \
								"The help information you requested cannot be found on this system.<br><pre>%s: %s</pre><p>" \
								"Usually this is an installation problem, Make sure that XTrackCAD and the included " \
								"HTML files are installed properly and can be found via the XTRKCADLIB environment " \
								"variable. Also make sure that the user has sufficient access rights to read these" \
 								"files.</p></body></html>"


#define SLIDERPOSDEFAULT 180		/**< default value for slider position */

#define HTMLHELPSECTION    "gtklib html help" /**< section name for html help window preferences */
#define SLIDERPREFNAME	   "sliderpos"    	 /**< name for the slider position preference */
#define WINDOWPOSPREFNAME  "position"  		 /**< name for the window position preference */
#define WINDOWSIZEPREFNAME "size"   			 /**< name for the window size preference */

#define BACKBUTTON "back"
#define FORWARDBUTTON "forward"
#define HOMEBUTTON "home"
#define CONTENTBUTTON "contents"
#define TOCDOC "tocDoc"
#define CONTENTSDOC "contentsDoc"
#define TOCVIEW "viewLeft"
#define CONTENTSVIEW "viewRight"
#define PANED "hpane"

enum pane_views { MAIN_VIEW, CONTENTS_VIEW };

static char *directory;				/**< base directory for HTML files */

static GtkWidget *wHelpWindow;	/**< handle for the help window */
static GtkWidget *main_view; /** handle for the help main data pane */
static GtkWidget *contents_view; /** handle for the help contents pane */

#define GLADE_HOOKUP_OBJECT(component,widget,name) \
  g_object_set_data_full (G_OBJECT (component), name, \
    gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref)

#define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \
  g_object_set_data (G_OBJECT (component), name, widget)

static GtkWidget*
lookup_widget(GtkWidget *widget, const gchar *widget_name)
{
    GtkWidget *parent, *found_widget;

    for (;;) {
        if (GTK_IS_MENU(widget)) {
            parent = gtk_menu_get_attach_widget(GTK_MENU(widget));
        } else {
            parent = widget->parent;
        }

        if (!parent) {
            parent = (GtkWidget*) g_object_get_data(G_OBJECT(widget), "GladeParentKey");
        }

        if (parent == NULL) {
            break;
        }

        widget = parent;
    }

    found_widget = (GtkWidget*) g_object_get_data(G_OBJECT(widget),
                   widget_name);

    if (!found_widget) {
        g_warning("Widget not found: %s", widget_name);
    }

    return found_widget;
}




/**
 * create a new horizontal pane and place it into container.
 * The separator position is read from the resource configuration and set accordingly.
 * Also a callback is specified that will be executed when the slider has been moved.
 *
 * \PARAM container IN the container into which the pane will be stuffed.
 * \PARAM property IN the name of the property for the slider position
 *
 * \return the HPaned handle
 */

GtkWidget *
CreateHPaned(GtkBox *container, char *property)
{
    GtkWidget *hpaned;
    long posSlider;

    /* the horizontal slider */
    hpaned = gtk_hpaned_new();
    gtk_container_set_border_width(GTK_CONTAINER(hpaned), 6);

    wPrefGetInteger(HTMLHELPSECTION, SLIDERPREFNAME, &posSlider, SLIDERPOSDEFAULT);
    gtk_paned_set_position(GTK_PANED(hpaned), (int)posSlider);

    /* pack the horizontal slider into the main window */
    gtk_box_pack_start(container, hpaned, TRUE, TRUE, 0);
    gtk_widget_show(hpaned);

    return (hpaned);
}

/**
 * Handler for the delete-event issued on the help window.We are saving window
 * information (eg. position) and are hiding the window instead of closing it.
 *
 * \PARAM win IN the window to be destroyed
 * \PARAM event IN unused
 * \PARAM ptr IN unused
 *
 * \RETURN FALSE
 */

static gboolean
DestroyHelpWindow(GtkWidget *win, GdkEvent *event, void *ptr)
{
    int i;
    GtkWidget *widget;
    char tmp[ 20 ];

    gint x, y;

    /* get the slider position and save it */
    widget = lookup_widget(win, PANED);
    i = gtk_paned_get_position(GTK_PANED(widget));
    wPrefSetInteger(HTMLHELPSECTION, SLIDERPREFNAME, i);

    /* get the window position */
    gtk_window_get_position((GtkWindow *)win, &x, &y);
    sprintf(tmp, "%d %d", x, y);
    wPrefSetString(HTMLHELPSECTION, WINDOWPOSPREFNAME, tmp);

    /* get the window size */
    gtk_window_get_size((GtkWindow *)win , &x, &y);
    sprintf(tmp, "%d %d", x, y);
    wPrefSetString(HTMLHELPSECTION, WINDOWSIZEPREFNAME, tmp);

    gtk_widget_hide(win);
    return TRUE;
}

void back_button_clicked(GtkWidget *widget, gpointer data)
{
    webkit_web_view_go_back(WEBKIT_WEB_VIEW(data));
}

void forward_button_clicked(GtkWidget *widget, gpointer data)
{
    webkit_web_view_go_forward(WEBKIT_WEB_VIEW(data));
}

void home_button_clicked(GtkWidget *widget, gpointer data)
{
    load_into_view("index.html", MAIN_VIEW);
}

/* Toggles the contents pane */
void contents_button_clicked(GtkWidget *widget, gpointer data)
{
    if (gtk_paned_get_position(GTK_PANED(data)) < 50) {
        gtk_paned_set_position(GTK_PANED(data), 370);
    } else {
        gtk_paned_set_position(GTK_PANED(data), 0);
    }
}

gboolean contents_click_handler(
    WebKitWebView *web_view,
    WebKitWebFrame *frame,
    WebKitNetworkRequest *request,
    WebKitWebNavigationAction *navigation_action,
    WebKitWebPolicyDecision *policy_decision,
    gpointer data)
{

    webkit_web_view_load_uri(WEBKIT_WEB_VIEW(data),
                             webkit_network_request_get_uri(request));

    return TRUE;
}

/**
 * Initialize the buttons for the help window
 */
void initialize_buttons(GtkWidget *main_vbox, GtkWidget *content_hpane)
{
    GtkWidget *buttons_hbuttonbox;
    GtkWidget *back_button;
    GtkWidget *forward_button;
    GtkWidget *home_button;
    GtkWidget *contents_button;

    // define and attach signals to buttons
    back_button = gtk_button_new_with_label(_("Back"));
    g_signal_connect(back_button, "clicked", G_CALLBACK(back_button_clicked),
                     G_OBJECT(main_view));

    forward_button = gtk_button_new_with_label(_("Forward"));
    g_signal_connect(forward_button, "clicked", G_CALLBACK(forward_button_clicked),
                     G_OBJECT(main_view));

    home_button = gtk_button_new_with_label(_("Home"));
    g_signal_connect(home_button, "clicked", G_CALLBACK(home_button_clicked),
                     G_OBJECT(main_view));

    contents_button = gtk_button_new_with_label(_("Contents"));
    g_signal_connect(contents_button, "clicked",
                     G_CALLBACK(contents_button_clicked), G_OBJECT(content_hpane));

    // button layout
    buttons_hbuttonbox = gtk_hbutton_box_new();
    gtk_container_add(GTK_CONTAINER(buttons_hbuttonbox), back_button);
    gtk_container_add(GTK_CONTAINER(buttons_hbuttonbox), forward_button);
    gtk_container_add(GTK_CONTAINER(buttons_hbuttonbox), home_button);
    gtk_container_add(GTK_CONTAINER(buttons_hbuttonbox), contents_button);
    gtk_box_pack_start(GTK_BOX(main_vbox), buttons_hbuttonbox, FALSE, TRUE, 0);
    gtk_box_set_spacing(GTK_BOX(buttons_hbuttonbox), 6);
    gtk_button_box_set_layout(GTK_BUTTON_BOX(buttons_hbuttonbox),
                              GTK_BUTTONBOX_START);

    /* Store pointers to all widgets, for use by lookup_widget().  */
    GLADE_HOOKUP_OBJECT(main_view, back_button, BACKBUTTON);
    GLADE_HOOKUP_OBJECT(main_view, forward_button, FORWARDBUTTON);
    GLADE_HOOKUP_OBJECT(main_view, home_button, HOMEBUTTON);
    GLADE_HOOKUP_OBJECT(main_view, contents_button, CONTENTBUTTON);
}

/**
 * Create the help windows including all contained widgets and the needed HTML documents.
 *
 * \RETURN handle of the created window.
 */

GtkWidget*
CreateHelpWindow(void)
{
    GtkWidget *main_vbox;
    GtkWidget *main_view_scroller;
    GtkWidget *contents_view_scroller;
    GtkWidget *content_hpane;

    int width;
    int height;
    int x, y;
    int w = 0, h = 0;
    const char *pref;

    wHelpWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);

    width = gdk_screen_get_width(gtk_window_get_screen((GtkWindow *)wHelpWindow));
    height = gdk_screen_get_height(gtk_window_get_screen((GtkWindow *)wHelpWindow));

    pref = wPrefGetString(HTMLHELPSECTION, WINDOWSIZEPREFNAME);

    if (pref) {
        sscanf(pref, "%d %d", &w, &h);

        if (w > width) {
            w = width;
        }

        if (h > height) {
            h = height;
        }
    } else {
        w = (width * 2)/ 5;
        h = height - 100;
    }

    pref = wPrefGetString(HTMLHELPSECTION, WINDOWPOSPREFNAME);

    if (pref) {
        sscanf(pref, "%d %d", &x, &y);

        if (y > height - h) {
            y = height - h;
        }

        if (x > width - w) {
            x = width - w;
        }
    } else {
        x = (width * 3) / 5 - 10;
        y = 70;
    }

    gtk_window_resize((GtkWindow *)wHelpWindow, w, h);
    gtk_window_move((GtkWindow *)wHelpWindow, x, y);

    gtk_window_set_title(GTK_WINDOW(wHelpWindow), "XTrkCad Help");

    g_signal_connect(G_OBJECT(wHelpWindow), "delete-event",
                     G_CALLBACK(DestroyHelpWindow), NULL);

    main_view_scroller = gtk_scrolled_window_new(NULL, NULL);
    contents_view_scroller = gtk_scrolled_window_new(NULL, NULL);
    main_view = webkit_web_view_new();
    contents_view = webkit_web_view_new();
    // must be done here as it gets locked down later
    load_into_view("contents.html", CONTENTS_VIEW);
    gtk_widget_set_size_request(GTK_WIDGET(wHelpWindow), x, y);

    main_vbox = gtk_vbox_new(FALSE, 5);
    gtk_container_add(GTK_CONTAINER(wHelpWindow), main_vbox);

    gtk_container_add(GTK_CONTAINER(main_view_scroller), main_view);

    gtk_container_add(GTK_CONTAINER(contents_view_scroller), contents_view);

    content_hpane = gtk_hpaned_new();
    initialize_buttons(main_vbox, content_hpane);
    gtk_container_add(GTK_CONTAINER(content_hpane), contents_view_scroller);
    gtk_container_add(GTK_CONTAINER(content_hpane), main_view_scroller);
    gtk_box_pack_start(GTK_BOX(main_vbox), content_hpane, TRUE, TRUE, 0);

    gtk_paned_set_position(GTK_PANED(content_hpane), 370);

    g_signal_connect(contents_view, "navigation-policy-decision-requested",
                     G_CALLBACK(contents_click_handler), G_OBJECT(main_view));

    /* Store pointers to all widgets, for use by lookup_widget().  */
    GLADE_HOOKUP_OBJECT_NO_REF(wHelpWindow, wHelpWindow, "wHelpWindow");
    GLADE_HOOKUP_OBJECT(wHelpWindow, content_hpane, PANED);
    GLADE_HOOKUP_OBJECT(wHelpWindow, contents_view, TOCVIEW);
    GLADE_HOOKUP_OBJECT(wHelpWindow, main_view, CONTENTSVIEW);

    return wHelpWindow;
}

void load_into_view(char *file, int requested_view)
{
    GtkWidget *view;

    switch (requested_view) {
    case MAIN_VIEW:
        view = main_view;
        break;

    case CONTENTS_VIEW:
        view = contents_view;
        break;

    default:
        printf("*** error, could not find view");
        break;
    }

    char fileToLoad[250] = "file://";
    strcat(fileToLoad,directory);
    strcat(fileToLoad,file);

    //debug printf("*** loading %s into pane %d.\n", fileToLoad, requested_view);
    webkit_web_view_load_uri(WEBKIT_WEB_VIEW(view), fileToLoad);
}

/**
 * Invoke the help system to display help for <topic>.
 *
 * \param topic IN topic string
 */

void wHelp(const char * topic)
{
    char *htmlFile;

    if (!wHelpWindow) {
        directory = malloc(BUFSIZ);
        assert(directory != NULL);

        sprintf(directory, "%s/html/", wGetAppLibDir());

        wHelpWindow = CreateHelpWindow();
        /* load the default content */
        load_into_view("index.html", MAIN_VIEW);
    }

    /* need space for the 'html' extension plus dot plus \0 */
    htmlFile = malloc(strlen(topic) + 6);
    assert(htmlFile != NULL);

    sprintf(htmlFile, "%s.html", topic);

    load_into_view(htmlFile, MAIN_VIEW);
    gtk_widget_show_all(wHelpWindow);
    gtk_window_present(GTK_WINDOW(wHelpWindow));
}