/*
 Copyright (C) 2007-2009 Christian Dywan <christian@twotoasts.de>
 Copyright (C) 2008 Dale Whittaker <dayul@users.sf.net>

 This library 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.1 of the License, or (at your option) any later version.

 See the file COPYING for the full license text.
*/

#include "midori-frontend.h"
#include "midori-platform.h"
#include "midori-privatedata.h"
#include "midori-searchaction.h"
#include "midori/midori-session.h"
#include <midori/midori-core.h>

#include <config.h>
#if HAVE_UNISTD_H
    #include <unistd.h>
#endif

#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <glib/gstdio.h>
#include <glib/gi18n-lib.h>
#include "katze/katze.h"
#include <sqlite3.h>

#define HAVE_OFFSCREEN GTK_CHECK_VERSION (2, 20, 0)

#ifndef HAVE_WEBKIT2
static void
snapshot_load_finished_cb (GtkWidget*      web_view,
                           WebKitWebFrame* web_frame,
                           gchar*          filename)
{
    #if HAVE_OFFSCREEN
    GdkPixbuf* pixbuf = gtk_offscreen_window_get_pixbuf (GTK_OFFSCREEN_WINDOW (
        gtk_widget_get_parent (web_view)));
    gdk_pixbuf_save (pixbuf, filename, "png", NULL, "compression", "7", NULL);
    g_object_unref (pixbuf);
    #else
    GError* error;
    GtkPrintOperation* operation = gtk_print_operation_new ();

    gtk_print_operation_set_export_filename (operation, filename);
    error = NULL;
    webkit_web_frame_print_full (web_frame, operation,
        GTK_PRINT_OPERATION_ACTION_EXPORT, &error);

    if (error != NULL)
    {
        g_error ("%s", error->message);
        gtk_main_quit ();
    }

    g_object_unref (operation);
    #endif
    g_print (_("Snapshot saved to: %s\n"), filename);
    gtk_main_quit ();
}
#endif

int
main (int    argc,
      char** argv)
{
    gchar* webapp;
    gchar* config;
    gboolean private;
    gboolean portable;
    gboolean plain;
    gboolean diagnostic_dialog = FALSE;
    gboolean debug = FALSE;
    gboolean run;
    gchar* snapshot;
    gboolean execute;
    gboolean help_execute;
    gboolean version;
    gchar** uris;
    gchar* block_uris;
    gint inactivity_reset;
    GOptionEntry entries[] =
    {
       { "app", 'a', 0, G_OPTION_ARG_STRING, &webapp,
       N_("Run ADDRESS as a web application"), N_("ADDRESS") },
       { "config", 'c', 0, G_OPTION_ARG_FILENAME, &config,
       N_("Use FOLDER as configuration folder"), N_("FOLDER") },
       { "private", 'p', 0, G_OPTION_ARG_NONE, &private,
       N_("Private browsing, no changes are saved"), NULL },
       #ifdef G_OS_WIN32
       { "portable", 'P', 0, G_OPTION_ARG_NONE, &portable,
       N_("Portable mode, all runtime files are stored in one place"), NULL },
       #endif
       { "plain", '\0', 0, G_OPTION_ARG_NONE, &plain,
       N_("Plain GTK+ window with WebKit, akin to GtkLauncher"), NULL },
       { "diagnostic-dialog", 'd', 0, G_OPTION_ARG_NONE, &diagnostic_dialog,
       N_("Show a diagnostic dialog"), NULL },
       { "debug", 'g', 0, G_OPTION_ARG_NONE, &debug,
       N_("Run within gdb and save a backtrace on crash"), NULL },
       { "run", 'r', 0, G_OPTION_ARG_NONE, &run,
       N_("Run the specified filename as javascript"), NULL },
       { "snapshot", 's', 0, G_OPTION_ARG_STRING, &snapshot,
       N_("Take a snapshot of the specified URI"), NULL },
       { "execute", 'e', 0, G_OPTION_ARG_NONE, &execute,
       N_("Execute the specified command"), NULL },
       { "help-execute", 0, 0, G_OPTION_ARG_NONE, &help_execute,
       N_("List available commands to execute with -e/ --execute"), NULL },
       { "version", 'V', 0, G_OPTION_ARG_NONE, &version,
       N_("Display program version"), NULL },
       { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &uris,
       N_("Addresses"), NULL },
       { "block-uris", 'b', 0, G_OPTION_ARG_STRING, &block_uris,
       N_("Block URIs according to regular expression PATTERN"), _("PATTERN") },
       #ifdef HAVE_X11_EXTENSIONS_SCRNSAVER_H
       { "inactivity-reset", 'i', 0, G_OPTION_ARG_INT, &inactivity_reset,
       /* i18n: CLI: Close tabs, clear private data, open starting page */
       N_("Reset Midori after SECONDS seconds of inactivity"), N_("SECONDS") },
       #endif
     { NULL }
    };

    /* Parse cli options */
    webapp = NULL;
    config = NULL;
    private = FALSE;
    portable = FALSE;
    plain = FALSE;
    run = FALSE;
    snapshot = NULL;
    execute = FALSE;
    help_execute = FALSE;
    version = FALSE;
    uris = NULL;
    block_uris = NULL;
    inactivity_reset = 0;
    midori_app_setup (&argc, &argv, entries);

    if (debug)
    {
        gchar* gdb = g_find_program_in_path ("gdb");
        gchar* args = midori_paths_get_command_line_str (FALSE);
        gchar* cmd = g_strdup_printf (
            "--batch -ex 'set print thread-events off' -ex run "
            "-ex 'set logging on %s' -ex 'bt' --return-child-result "
            "--args %s",
            "/tmp/midori-gdb.bt", args);
        if (gdb != NULL)
            sokoke_spawn_program (gdb, TRUE, cmd, FALSE, TRUE);
        else
            g_print (_("Error: \"gdb\" can't be found\n"));
        g_free (gdb);
        g_free (cmd);
        g_free (args);
        return 0;
    }

    g_set_application_name (_("Midori"));
    /* Versioned prgname to override menuproxy blacklist */
    g_set_prgname (PACKAGE_NAME "4");

    if (version)
    {
        GString* versions = g_string_new ("");
        g_string_append_c (versions, '\n');
        midori_view_list_versions (versions, FALSE);
        /* FIXME Plugins may clutter output and hang
        midori_view_list_plugins (NULL, versions, FALSE); */
        g_print ("%s\n", versions->str);
        g_string_free (versions, TRUE);

        g_print (
          "Copyright (c) 2007-2012 Christian Dywan\n\n"
          "%s\n"
          "\t%s\n\n"
          "%s\n"
          "\thttp://www.midori-browser.org\n",
          _("Please report comments, suggestions and bugs to:"),
          PACKAGE_BUGREPORT,
          _("Check for new versions at:")
        );
        return 0;
    }

    if (help_execute)
    {
        MidoriBrowser* browser = midori_browser_new ();
        GtkActionGroup* action_group = midori_browser_get_action_group (browser);
        GList* actions = gtk_action_group_list_actions (action_group);
        GList* temp = actions;
        guint length = 1;
        gchar* space;

        for (; temp; temp = g_list_next (temp))
        {
            GtkAction* action = temp->data;
            length = MAX (length, 1 + strlen (gtk_action_get_name (action)));
        }

        space = g_strnfill (length, ' ');
        for (; actions; actions = g_list_next (actions))
        {
            GtkAction* action = actions->data;
            const gchar* name = gtk_action_get_name (action);
            gchar* padding = g_strndup (space, strlen (space) - strlen (name));
            gchar* label = katze_object_get_string (action, "label");
            gchar* stripped = katze_strip_mnemonics (label);
            gchar* tooltip = katze_object_get_string (action, "tooltip");
            g_print ("%s%s%s%s%s\n", name, padding, stripped,
                     tooltip ? ": " : "", tooltip ? tooltip : "");
            g_free (tooltip);
            g_free (padding);
            g_free (label);
            g_free (stripped);
        }
        g_free (space);
        g_list_free (actions);
        gtk_widget_destroy (GTK_WIDGET (browser));
        return 0;
    }

    if (snapshot)
    {
        GError* error = NULL;
        gchar* filename;
        GtkWidget* web_view;
        gchar* uri;
        #if HAVE_OFFSCREEN
        GtkWidget* offscreen;
        GdkScreen* screen;

        gint fd = g_file_open_tmp ("snapshot-XXXXXX.png", &filename, &error);
        #else
        gint fd = g_file_open_tmp ("snapshot-XXXXXX.pdf", &filename, &error);
        #endif
        close (fd);

        if (error)
        {
            g_error ("%s", error->message);
            return 1;
        }

        if (g_unlink (filename) == -1)
        {
            g_error ("%s", g_strerror (errno));
            return 1;
        }

        web_view = webkit_web_view_new ();
        #if HAVE_OFFSCREEN
        offscreen = gtk_offscreen_window_new ();
        gtk_container_add (GTK_CONTAINER (offscreen), web_view);
        if ((screen = gdk_screen_get_default ()))
            gtk_widget_set_size_request (web_view,
                gdk_screen_get_width (screen), gdk_screen_get_height (screen));
        else
            gtk_widget_set_size_request (web_view, 800, 600);
        gtk_widget_show_all (offscreen);
        #endif
        #ifndef HAVE_WEBKIT2
        g_signal_connect (web_view, "load-finished",
            G_CALLBACK (snapshot_load_finished_cb), filename);
        #endif
        uri = sokoke_prepare_uri (snapshot);
        webkit_web_view_load_uri (WEBKIT_WEB_VIEW (web_view), uri);
        g_free (uri);
        gtk_main ();
        g_free (filename);
        return 0;
    }

    if (plain)
    {
        GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
#ifndef HAVE_WEBKIT2
        GtkWidget* scrolled = gtk_scrolled_window_new (NULL, NULL);
#endif
        GtkWidget* web_view = webkit_web_view_new ();
        gchar* uri = sokoke_prepare_uri (
            (uris != NULL && uris[0]) ? uris[0] : "http://www.example.com");
        katze_window_set_sensible_default_size (GTK_WINDOW (window));

#ifndef HAVE_WEBKIT2
        gtk_container_add (GTK_CONTAINER (window), scrolled);
        gtk_container_add (GTK_CONTAINER (scrolled), web_view);
#else
        gtk_container_add (GTK_CONTAINER (window), web_view);
#endif
        g_signal_connect (window, "delete-event",
            G_CALLBACK (gtk_main_quit), window);
        gtk_widget_show_all (window);
        webkit_web_view_load_uri (WEBKIT_WEB_VIEW (web_view), uri);
        g_free (uri);
        gtk_main ();
        return 0;
    }

    midori_private_data_register_built_ins ();

    if (run)
    {
        gchar* script = NULL;
        GError* error = NULL;

        if (g_file_get_contents (uris ? *uris : NULL, &script, NULL, &error))
        {
            MidoriBrowser* browser = midori_browser_new ();
            MidoriWebSettings* settings = midori_browser_get_settings (browser);
#ifndef HAVE_WEBKIT2
            g_object_set_data (G_OBJECT (webkit_get_default_session ()), "pass-through-console", (void*)1);
#endif
            midori_load_soup_session (settings);

            gchar* msg = NULL;
            GtkWidget* view = midori_view_new_with_item (NULL, settings);
            g_object_set (settings, "open-new-pages-in", MIDORI_NEW_PAGE_WINDOW, NULL);
            midori_browser_add_tab (browser, view);
            gtk_widget_show_all (GTK_WIDGET (browser));
            gtk_widget_hide (GTK_WIDGET (browser));
            midori_view_execute_script (MIDORI_VIEW (view), script, &msg);
            if (msg != NULL)
            {
                g_error ("%s\n", msg);
                g_free (msg);
            }
            gtk_main ();
        }
        else if (error != NULL)
        {
            g_error ("%s\n", error->message);
            g_error_free (error);
        }
        else
            g_error ("%s\n", _("An unknown error occured"));
        g_free (script);
        return 0;
    }

    if (private)
    {
        MidoriBrowser* browser = midori_private_app_new (config, webapp,
            execute ? NULL : uris, execute ? uris : NULL, inactivity_reset, block_uris);
        g_signal_connect (browser, "destroy", G_CALLBACK (gtk_main_quit), NULL);
        g_signal_connect (browser, "quit", G_CALLBACK (gtk_main_quit), NULL);
        gtk_main ();
        return 0;
    }

    if (webapp)
    {
        MidoriBrowser* browser = midori_web_app_new (config, webapp,
            execute ? NULL : uris, execute ? uris : NULL, inactivity_reset, block_uris);
        g_signal_connect (browser, "destroy", G_CALLBACK (gtk_main_quit), NULL);
        g_signal_connect (browser, "quit", G_CALLBACK (gtk_main_quit), NULL);
        gtk_main ();
        return 0;
    }

    MidoriApp* app = midori_normal_app_new (config,
        portable ? "portable" : "normal", diagnostic_dialog, webapp,
        execute ? NULL : uris, execute ? uris : NULL, inactivity_reset, block_uris);
    if (app == NULL)
        return 0;
    if (app == (void*)0xdeadbeef)
        return 1;

    g_signal_connect (app, "quit", G_CALLBACK (gtk_main_quit), NULL);
    gtk_main ();
    midori_normal_app_on_quit (app);
    return 0;
}

