/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
   Copyright (C) 2010-2015 Red Hat, Inc.

   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.

   This library 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 this library; if not, see <http://www.gnu.org/licenses/>.
*/

#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include "spice-common.h"
#include "spicy-connect.h"

typedef struct
{
    gboolean connecting;
    GMainLoop *loop;
    SpiceSession *session;
} ConnectionInfo;

static struct {
    const char *text;
    const char *prop;
    GtkWidget *entry;
} connect_entries[] = {
    { .text = "Hostname",   .prop = "host"      },
    { .text = "Port",       .prop = "port"      },
    { .text = "TLS Port",   .prop = "tls-port"  },
};

static gboolean can_connect(void)
{
    if ((gtk_entry_get_text_length(GTK_ENTRY(connect_entries[0].entry)) > 0) &&
        ((gtk_entry_get_text_length(GTK_ENTRY(connect_entries[1].entry)) > 0) ||
         (gtk_entry_get_text_length(GTK_ENTRY(connect_entries[2].entry)) > 0)))
        return TRUE;

    return FALSE;
}

static void set_connection_info(SpiceSession *session)
{
    const gchar *txt;
    int i;

    for (i = 0; i < SPICE_N_ELEMENTS(connect_entries); i++) {
        txt = gtk_entry_get_text(GTK_ENTRY(connect_entries[i].entry));
        g_object_set(session, connect_entries[i].prop, txt, NULL);
    }
}

static gboolean close_cb(gpointer data)
{
    ConnectionInfo *info = data;
    info->connecting = FALSE;
    if (g_main_loop_is_running(info->loop))
        g_main_loop_quit(info->loop);

    return TRUE;
}

static void entry_changed_cb(GtkEditable* entry, gpointer data)
{
    GtkButton *connect_button = data;
    gtk_widget_set_sensitive(GTK_WIDGET(connect_button), can_connect());
}

static gboolean entry_focus_in_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
{
    GtkRecentChooser *recent = GTK_RECENT_CHOOSER(data);
    gtk_recent_chooser_unselect_all(recent);
    return TRUE;
}

static gboolean key_pressed_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
{
    gboolean tst;
    if (event->type == GDK_KEY_PRESS) {
        switch (event->key.keyval) {
            case GDK_KEY_Escape:
                g_signal_emit_by_name(GTK_WIDGET(data), "delete-event", NULL, &tst);
                return TRUE;
            default:
                return FALSE;
        }
    }

    return FALSE;
}

static void recent_selection_changed_dialog_cb(GtkRecentChooser *chooser, gpointer data)
{
    GtkRecentInfo *info;
    gchar *txt = NULL;
    const gchar *uri;
    SpiceSession *session = data;
    int i;

    info = gtk_recent_chooser_get_current_item(chooser);
    if (info == NULL)
        return;

    uri = gtk_recent_info_get_uri(info);
    g_return_if_fail(uri != NULL);

    g_object_set(session, "uri", uri, NULL);

    for (i = 0; i < SPICE_N_ELEMENTS(connect_entries); i++) {
        g_object_get(session, connect_entries[i].prop, &txt, NULL);
        gtk_entry_set_text(GTK_ENTRY(connect_entries[i].entry), txt ? txt : "");
        g_free(txt);
    }

    gtk_recent_info_unref(info);
}

static void connect_cb(gpointer data)
{
    ConnectionInfo *info = data;
    if (can_connect())
    {
        info->connecting = TRUE;
        set_connection_info(info->session);
        if (g_main_loop_is_running(info->loop))
            g_main_loop_quit(info->loop);
    }
}

gboolean spicy_connect_dialog(SpiceSession *session)
{
    GtkWidget *connect_button, *cancel_button, *label;
    GtkBox *main_box, *recent_box, *button_box;
    GtkWindow *window;
    GtkGrid *grid;
    int i;

    ConnectionInfo info = {
        FALSE,
        NULL,
        session
    };

    /* Create the widgets */
    window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
    gtk_window_set_title(window, "Connect to SPICE");
    gtk_window_set_resizable(window, FALSE);
    gtk_container_set_border_width(GTK_CONTAINER(window), 5);

    main_box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0));
    gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(main_box));

    grid = GTK_GRID(gtk_grid_new());
    gtk_box_pack_start(main_box, GTK_WIDGET(grid), FALSE, TRUE, 0);
    gtk_container_set_border_width(GTK_CONTAINER(grid), 5);
    gtk_grid_set_row_spacing(grid, 5);
    gtk_grid_set_column_spacing(grid, 5);

    for (i = 0; i < SPICE_N_ELEMENTS(connect_entries); i++) {
        gchar *txt;
        label = gtk_label_new(connect_entries[i].text);
        gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
        gtk_grid_attach(grid, label, 0, i, 1, 1);
        connect_entries[i].entry = GTK_WIDGET(gtk_entry_new());
        gtk_grid_attach(grid, connect_entries[i].entry, 1, i, 1, 1);
        g_object_get(session, connect_entries[i].prop, &txt, NULL);
        SPICE_DEBUG("%s: #%i [%s]: \"%s\"",
                __FUNCTION__, i, connect_entries[i].prop, txt);
        if (txt) {
            gtk_entry_set_text(GTK_ENTRY(connect_entries[i].entry), txt);
            g_free(txt);
        }
    }

    recent_box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0));
    gtk_box_pack_start(main_box, GTK_WIDGET(recent_box), TRUE, TRUE, 0);
    gtk_container_set_border_width(GTK_CONTAINER(recent_box), 5);

    label = gtk_label_new("Recent connections:");
    gtk_box_pack_start(recent_box, label, FALSE, TRUE, 0);
    gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);

    button_box = GTK_BOX(gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL));
    gtk_button_box_set_layout(GTK_BUTTON_BOX(button_box), GTK_BUTTONBOX_END);
    gtk_box_set_spacing(button_box, 5);
    gtk_container_set_border_width(GTK_CONTAINER(button_box), 5);
    connect_button = gtk_button_new_with_label("Connect");
    cancel_button = gtk_button_new_with_label("Cancel");
    gtk_box_pack_start(button_box, cancel_button, FALSE, TRUE, 0);
    gtk_box_pack_start(button_box, connect_button, FALSE, TRUE, 1);

    gtk_box_pack_start(main_box, GTK_WIDGET(button_box), FALSE, TRUE, 0);

    gtk_widget_set_sensitive(GTK_WIDGET(connect_button), can_connect());

    g_signal_connect(window, "key-press-event",
                     G_CALLBACK(key_pressed_cb), window);
    g_signal_connect_swapped(window, "delete-event",
                             G_CALLBACK(close_cb), &info);
    g_signal_connect_swapped(connect_button, "clicked",
                             G_CALLBACK(connect_cb), &info);
    g_signal_connect_swapped(cancel_button, "clicked",
                             G_CALLBACK(close_cb), &info);

    GtkRecentFilter *rfilter;
    GtkWidget *recent;

    recent = GTK_WIDGET(gtk_recent_chooser_widget_new());
    gtk_recent_chooser_set_show_icons(GTK_RECENT_CHOOSER(recent), FALSE);
    gtk_box_pack_start(recent_box, recent, TRUE, TRUE, 0);

    rfilter = gtk_recent_filter_new();
    gtk_recent_filter_add_mime_type(rfilter, "application/x-spice");
    gtk_recent_chooser_set_filter(GTK_RECENT_CHOOSER(recent), rfilter);
    gtk_recent_chooser_set_local_only(GTK_RECENT_CHOOSER(recent), FALSE);
    g_signal_connect(recent, "selection-changed",
                     G_CALLBACK(recent_selection_changed_dialog_cb), session);
    g_signal_connect_swapped(recent, "item-activated",
                             G_CALLBACK(connect_cb), &info);

    for (i = 0; i < SPICE_N_ELEMENTS(connect_entries); i++) {
        g_signal_connect_swapped(connect_entries[i].entry, "activate",
                                 G_CALLBACK(connect_cb), &info);
        g_signal_connect(connect_entries[i].entry, "changed",
                         G_CALLBACK(entry_changed_cb), connect_button);
        g_signal_connect(connect_entries[i].entry, "focus-in-event",
                         G_CALLBACK(entry_focus_in_cb), recent);
    }

    /* show and wait for response */
    gtk_widget_show_all(GTK_WIDGET(window));

    info.loop = g_main_loop_new(NULL, FALSE);
    g_main_loop_run(info.loop);
    g_clear_pointer(&info.loop, g_main_loop_unref);

    gtk_widget_destroy(GTK_WIDGET(window));

    return info.connecting;
}
