#include "gtk-menu.h"

#include "gcore/gcomm.h"
#include "gcore/glaunch.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef WIN32
#include <unistd.h>
#endif /* WIN32 */
#ifdef darwin
#ifndef PATH_MAX
#include <sys/syslimits.h>  /* only if PATH_MAX missing from limits.h */
#endif
#endif /* darwin */
#include <gtk/gtk.h>
#ifndef WIN32
#define GGTK_PATH_MAX PATH_MAX
#else /* WIN32 */
#include <gdk/gdkwin32.h>
#define GGTK_PATH_MAX MAX_PATH
#define strdup _strdup
#endif /* WIN32 */

static void send_command( GtkWidget *w, char *command)
{
    if (sic_post_command_text( command) == -1) {
        gdk_display_beep(gtk_widget_get_display(w));
    }
}

static void _show_uri(char *path)
{
#ifdef WIN32
    char command[GGTK_PATH_MAX];
    sprintf(command, "start %s", path);
    system(command);
#elif !defined(darwin)
    {
        GError *error = NULL;
        GFile *gfile;
        char *uri;

        gfile = g_file_new_for_commandline_arg(path);
        uri = g_file_get_uri(gfile);

        /* GTK3+: prefer gtk_show_uri_on_window when available */
#if GTK_CHECK_VERSION(3,22,0)
        if (!gtk_show_uri_on_window(NULL, uri, GDK_CURRENT_TIME, &error) && error != NULL) {
            fprintf(stderr, "%s: Unable to launch %s\n", error->message, uri);
            g_error_free(error);
        }
#else
        if (!gtk_show_uri(NULL, uri, GDK_CURRENT_TIME, &error) && error != NULL) {
            fprintf(stderr, "%s: Unable to launch %s\n", error->message, uri);
            g_error_free(error);
        }
#endif
        g_object_unref(gfile);
        g_free(uri);
    }
#else
    if (!fork()) {
        /* hide possible errors */
        close(2);
#  ifdef darwin
        execlp("open", "open", path, NULL);
#  endif
        execlp("xdg-open", "xdg-open", path, NULL);
        execlp("htmlview", "htmlview", path, NULL);
        execlp("firefox", "firefox", path, NULL);
        fprintf(stderr, "Error: unable to open \"%s\"\n", path);
        fprintf(stderr, "Neither xdg-open, nor htmlview, nor firefox is available\n");
        exit(1);
    }
#endif
}

static void open_uri( GtkWidget *w, char *uri)
{
    _show_uri(uri);
}

static GtkWidget *s_menu_window = NULL;

/* This callback closes the menu window */
static void gtk_destroy_event( GtkWidget *widget, gpointer data)
{
    s_menu_window = NULL;
}

static int run_gtk_menu_args( int argc, char **argv)
{
    GtkWidget *window;
    GtkWidget *menu_bar;
    GtkWidget *menu_pane;
    GtkWidget *item;
    GtkWidget *menu_stack[10];
    int menu_stack_index = -1;
    int i;
    int comm_id;
    char filename[GGTK_PATH_MAX];
    FILE *fd;
    char windowtitle[TITLELENGTH];
    char helpfilename[HLPFILELNGTH];
    char line[512];

    i = 1;
    comm_id = atoi( argv[i++]);
    strcpy( filename, argv[i++]);

    fd = fopen( filename, "r");

    if (!fgets(windowtitle, TITLELENGTH, fd)) {
        fprintf(stderr, "Error: failed to read window title from file\n");
        fclose(fd);
        return -1;  /* or handle the error appropriately */
    }
    windowtitle[strlen( windowtitle) - 1] = '\0'; // suppress line feed

    if (!fgets(helpfilename, HLPFILELNGTH, fd)) {
        fprintf(stderr, "Error: failed to read help filename from file\n");
        fclose(fd);
        return -1;  /* or handle the error appropriately */
    }
    helpfilename[strlen( helpfilename) - 1] = '\0'; // suppress line feed


    if (s_menu_window != NULL) {
        /* Destroy last menu */
        gtk_widget_destroy( s_menu_window);
    }

    /* Create a new window */
    window = gtk_window_new( GTK_WINDOW_TOPLEVEL);
    gtk_window_set_focus_on_map( GTK_WINDOW(window), FALSE);
    s_menu_window = window;

    /* Set the window title */
    gtk_window_set_title( GTK_WINDOW(window), windowtitle);

    /* Destroy handler */
    g_signal_connect( window, "destroy",
                      G_CALLBACK(gtk_destroy_event), NULL);

    /* Border */
    gtk_container_set_border_width( GTK_CONTAINER(window), 1);

    menu_bar = gtk_menu_bar_new( );

    while (fgets( line, sizeof( line), fd) != NULL) {
        line[strlen( line) - 1] = '\0'; // suppress line feed
        if (strncmp( line, "MENU", 4) == 0) {
            if (!fgets( line, sizeof( line), fd)) {
                fprintf(stderr, "Error\n");
                fclose(fd);
                break;
            }
            line[strlen( line) - 1] = '\0'; // suppress line feed

            menu_pane = gtk_menu_new( );
            menu_stack[++menu_stack_index] = menu_pane;
            item = gtk_menu_item_new_with_label( line);
            gtk_menu_item_set_submenu( GTK_MENU_ITEM(item), menu_pane);
            if (menu_stack_index <= 0) {
                gtk_menu_shell_append( GTK_MENU_SHELL(menu_bar), item);
            } else {
                gtk_menu_shell_append(
                    GTK_MENU_SHELL(menu_stack[menu_stack_index - 1]), item);
            }

        } else if (strncmp( line, "ENDMENU", 7) == 0) {
            menu_stack_index--;
        } else {
            int uri;
            if (strncmp( line, "<URI>", 5) == 0) {
                uri = 1;
                if (!fgets( line, sizeof( line), fd)) {
                    fprintf(stderr, "Error\n");
                    fclose(fd);
                    break;
                }
                line[strlen( line) - 1] = '\0'; // suppress line feed
            } else {
                uri = 0;
            }

            item = gtk_menu_item_new_with_label( line);
            if (menu_stack_index < 0) {
                gtk_menu_shell_append( GTK_MENU_SHELL(menu_bar), item);
            } else {
                gtk_menu_shell_append(
                    GTK_MENU_SHELL(menu_stack[menu_stack_index]), item);
            }

            if (!fgets( line, sizeof( line), fd)) {
                fprintf(stderr, "Error\n");
                fclose(fd);
                break;
            }
            line[strlen( line) - 1] = '\0'; // suppress line feed

            g_signal_connect( item, "activate",
                G_CALLBACK(uri ? open_uri : send_command),
                (gpointer)strdup( line));
        }
    }

    fclose( fd);

    unlink( filename);

    gtk_container_add( GTK_CONTAINER(window), menu_bar);

    gtk_widget_show_all( window);

    return 0;
}

static int _on_run_menu( void *i)
{
    run_gtk_menu_args((int)(size_t)i, sic_get_static_argv( ));
    // do not call again
    return FALSE;
}

void run_gtk_menu( const char *file)
{
    int i;
    char **argv;

    launch_gtv_main_loop( NULL);

    argv = sic_get_static_argv( );
    i = 0;
    strcpy( argv[i++], "undefined");
    strcpy( argv[i++], "0");
    strcpy( argv[i++], file);
    argv[i] = NULL;

    g_idle_add(_on_run_menu, (gpointer)(size_t)i);
}

void kill_gtk_menu()
{
    if (s_menu_window != NULL)
        /* Destroy last menu */
        gtk_widget_destroy( s_menu_window);
}

