/* ====================================================================
 * FTD4Linux Software License, Version 1.0
 *
 * Copyright (c) 2000-2004 The FTD4Linux Development Team.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        FTD4Linux Development Team (http://www.ftd4linux.2y.net/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "FTD" and "FTD4Linux" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact alguno@ftd4linux.2y.net.
 *
 * 5. Products derived from this software may not be called "FTD4Linux",
 *    nor may "FTD4Linux" appear in their name, without prior written
 *    permission of the FTD4Linux Development Team.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE FTD4LINUX DEVELOPMENT TEAM OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <gtk/gtk.h>
#include <gtkmozembed.h>
#include <gtkmozembed_internal.h>
#include <stdlib.h>
#include <nsStringAPI.h>
#include <nsIDOMWindow.h>
#include <nsIDOMElement.h>
#include <nsIDOMDocument.h>

#include "ftd4linux.h"
#include "ftd_gui_browser.h"

extern "C" {
static void load_finished(GtkWidget *caller, gpointer data);
static gboolean open_uri (GtkWidget *embed, const char *uri, gpointer data);
};

/*
 * The name for this method is NOT arbitrarily chosen.
 * It wishes to express the feelings of the author that this should NOT be used as a good example
 * Still, it works for all strings containing only 7-bit characters
 */
static PRUnichar *
ugly_convert_to_utf16( const char * ascii )
{
    PRUnichar * res = (PRUnichar*) malloc( ( strlen( ascii ) + 1 ) * sizeof( PRUnichar ) );
    int i = 0;

    if( !res ) {
        return NULL;
    }

    PRUnichar * p = res;
    do {
        if( *ascii & 0x80 ) {
            *(p++) = '?';
        }
        else {
            *(p++) = *ascii;
        }
    } while( *(ascii++) );

    return res;
}

static void
set_element_attribute( GtkMozEmbed * browser, const char * elementId, const char * attribute, const char * value )
{
    nsIWebBrowser * webbrowser = NULL;
    nsIDOMWindow * window = NULL;
    nsIDOMDocument * document = NULL;
    nsIDOMElement * element = NULL;
    nsStringContainer elementString;
    nsStringContainer attributeString;
    nsStringContainer valueString;
    nsresult res;

    gtk_moz_embed_get_nsIWebBrowser( browser, &webbrowser );
    if( ! webbrowser ) {
        return;
    }

    webbrowser->GetContentDOMWindow( &window );
    if( !window ) {
        return;
    }

    window->GetDocument( &document );
    if( !document ) {
        return;
    }

    PRUnichar * elementIdUTF16 = ugly_convert_to_utf16( elementId );
    if( !elementIdUTF16 ) {
        return;
    }
    res = NS_StringContainerInit(elementString);
    if( NS_FAILED( res ) ) {
        free( elementIdUTF16 );
        return;
    }

    res = NS_StringSetData( elementString, elementIdUTF16, PR_UINT32_MAX );
    if( NS_SUCCEEDED( res ) ) {
        document->GetElementById( elementString, &element );
    }
    NS_StringContainerFinish( elementString );
    free( elementIdUTF16 );
    if( !element ) {
        return;
    }

    PRUnichar * attributeUTF16 = ugly_convert_to_utf16( attribute );
    if( !attributeUTF16 ) {
        return;
    }
    res = NS_StringContainerInit( attributeString );
    if( NS_FAILED( res ) ) {
        free( attributeUTF16 );
        return;
    }
    res = NS_StringSetData( attributeString, attributeUTF16, PR_UINT32_MAX );
    free( attributeUTF16 );
    if( NS_FAILED( res ) ) {
        NS_StringContainerFinish( attributeString );
        return;
    }

    PRUnichar * valueUTF16 = ugly_convert_to_utf16( value );
    if( !valueUTF16 ) {
        return;
    }
    res = NS_StringContainerInit( valueString );
    if( NS_FAILED( res ) ) {
        NS_StringContainerFinish( attributeString );
        free( valueUTF16 );
        return;
    }
    res = NS_StringSetData( valueString, valueUTF16, PR_UINT32_MAX );
    free( valueUTF16 );
    if( NS_FAILED( res ) ) {
        NS_StringContainerFinish( attributeString );
        NS_StringContainerFinish( valueString );
        return;
    }

    element->SetAttribute( attributeString, valueString );

    NS_StringContainerFinish( attributeString );
    NS_StringContainerFinish( valueString );
}

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

const char *
ftd_gui_browser_get_name(void)
{
    return "Mozilla";
}

FtdGuiBrowserData *
ftd_gui_browser_new(GtkWidget *parent, gboolean is_paned)
{
    FtdGuiBrowserData *browser_data = (FtdGuiBrowserData *) g_malloc0(sizeof(FtdGuiBrowserData));
    static gboolean initialized = FALSE;

    if (!initialized) {
        char *home_dir = ftd_file_parse_cache_filename (NULL, FALSE);
        gtk_moz_embed_set_profile_path (home_dir, "mozilla");
        g_free (home_dir);
        initialized = TRUE;
    }

    browser_data->public_widget = gtk_scrolled_window_new (NULL, NULL);

    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (browser_data->public_widget),
                                    GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);

    browser_data->private_widget = gtk_moz_embed_new();
    gtk_widget_show(browser_data->private_widget);

if (!is_paned) {
    gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(browser_data->public_widget), browser_data->private_widget);
    gtk_widget_show(browser_data->public_widget);
}

    if (is_paned) {
        gtk_paned_pack2 (GTK_PANED (parent), browser_data->private_widget, TRUE, FALSE);
    } else {
        gtk_container_add (GTK_CONTAINER (parent), browser_data->public_widget);
    }

    g_signal_connect_after (browser_data->private_widget, "net_stop", G_CALLBACK(load_finished), browser_data);
    g_signal_connect (browser_data->private_widget, "open_uri", G_CALLBACK(open_uri), browser_data);

    return browser_data;
}

void
ftd_gui_browser_navigate(FtdGuiBrowserData *browser_data, const char *url)
{
    char *filename;
    char *volledigeFilename;
    char *current_url;

    if (strncmp("http://", url, 7) == 0) {
        volledigeFilename = g_strdup(url);
    } else {
        filename = ftd_file_parse_cache_filename(url, FALSE);
        volledigeFilename = g_strdup_printf("file://%s", filename);
        g_free(filename);
    }

    current_url = gtk_moz_embed_get_location(GTK_MOZ_EMBED(browser_data->private_widget));
    if (current_url && !strcmp(volledigeFilename, current_url)) {
        gtk_moz_embed_reload(GTK_MOZ_EMBED (browser_data->private_widget), GTK_MOZ_EMBED_FLAG_RELOADNORMAL);
    } else {
        gtk_moz_embed_load_url (GTK_MOZ_EMBED (browser_data->private_widget), volledigeFilename);
    }

    g_free(current_url);
    g_free(volledigeFilename);
}

void
ftd_gui_browser_destroy(FtdGuiBrowserData *browser_data)
{
    gtk_widget_destroy(browser_data->public_widget);
    g_free(browser_data);
}

void
ftd_gui_browser_set_element_attribute(FtdGuiBrowserData *browser_data, const char *elementId, const char *attribute, const char *value)
{
    set_element_attribute(GTK_MOZ_EMBED(browser_data->private_widget), elementId, attribute, value);
}

static void
load_finished(GtkWidget *caller, gpointer data)
{
    FtdGuiBrowserData *browser_data = (FtdGuiBrowserData *) data;

    if (browser_data->load_finished_cb) {
        browser_data->load_finished_cb(browser_data->public_widget, browser_data->load_finished_data);
    }
}

void
ftd_gui_browser_set_load_finished_cb(FtdGuiBrowserData *browser_data, void (*cb) (GtkWidget *caller, gpointer data), gpointer data)
{
    browser_data->load_finished_cb = cb;
    browser_data->load_finished_data = data;
}

static gboolean
open_uri (GtkWidget *embed, const char *uri, gpointer data)
{
    FtdGuiBrowserData *browser_data = (FtdGuiBrowserData *) data;

    if (browser_data->link_clicked_cb) {
        return browser_data->link_clicked_cb(browser_data->public_widget, uri, browser_data->link_clicked_data);
    }

    return FALSE;
}

void
ftd_gui_browser_set_link_clicked_cb(FtdGuiBrowserData *browser_data, gboolean (*cb) (GtkWidget *caller, const char *url, gpointer data), gpointer data)
{
    browser_data->link_clicked_cb = cb;
    browser_data->link_clicked_data = data;
}

GtkWidget *
ftd_gui_browser_get_widget(FtdGuiBrowserData *browser_data)
{
    return browser_data->public_widget;
}

#ifdef __cplusplus
}
#endif /* __cplusplus */
