
#include <config.h>
#include <gtk/gtk.h>
#include <stdint.h>
#include <pop_upgrade_gtk.h>
#include "cc-upgrade-panel.h"

// Allow the upgrade widget to outlive the lifetime of its panel.
static PopUpgradeWidget *POP_UPGRADE = NULL;

// Atomic integer for tracking the current status.
extern gint POP_UPGRADE_STATUS = 0;

struct _CcUpgradePanel {
    CcPanel    parent_instance;
    GtkWidget *overlay;
    GtkWidget *info_bar;
    GtkWidget *info_msg;
};

CC_PANEL_REGISTER (CcUpgradePanel, cc_upgrade_panel)

static void info_bar_non_visible (GtkWidget *info_bar, gpointer user_data) {
    gtk_widget_set_visible (info_bar, FALSE);
}

/* When errors are encountered, they will be displayed in the info overlay. */
static void pop_upgrade_callback_error (const uint8_t *message, size_t len, CcUpgradePanel *priv) {
    // If the the pop upgrade widget has a parent widget, it's attached to `priv`.
    if (NULL != gtk_widget_get_parent (pop_upgrade_widget_container (POP_UPGRADE))) {
        g_autoptr (GString) gmessage = g_string_new_len (message, len);
        gtk_label_set_label (GTK_LABEL (priv->info_msg), gmessage->str);
        gtk_widget_set_visible (priv->info_bar, TRUE);
    }
}

/* As the upgrade status changes, this will update the atomic global status variable.
 *
 * This is useful primarily to prevent the application from exiting. */
static void pop_upgrade_callback_event (uint8_t event, gpointer user_data) {
    g_atomic_int_set (&POP_UPGRADE_STATUS, (gint) event);
    fprintf (stderr, "Setting status to %d\n", (gint) event);
}

/* Triggers when the upgrade ready notification is clicked. */
static void pop_upgrade_callback_ready (gpointer user_data) {
    g_autoptr(GError) error = NULL;
    gchar *argv[] = { "/usr/bin/gnome-control-center", "upgrade", NULL };
    if (!g_spawn_async (NULL, argv, NULL, 0, NULL, NULL, NULL, &error)) {
        g_warning ("Failed to open info overview: %s", error->message);
    }
}

/* Add an info bar into the panel overlay, for use by the upgrade widget. */
static void pop_os_info_overlay (CcUpgradePanel *self) {
    self->info_msg = gtk_label_new (NULL);
    gtk_label_set_line_wrap (GTK_LABEL (self->info_msg), TRUE);

    self->info_bar = gtk_info_bar_new ();
    gtk_widget_set_can_focus (self->info_bar, TRUE);
    gtk_widget_set_halign (self->info_bar, GTK_ALIGN_FILL);
    gtk_widget_set_valign (self->info_bar, GTK_ALIGN_START);
    gtk_info_bar_set_message_type (GTK_INFO_BAR (self->info_bar), GTK_MESSAGE_ERROR);
    gtk_info_bar_set_show_close_button (GTK_INFO_BAR (self->info_bar), TRUE);
    g_signal_connect (self->info_bar, "close", G_CALLBACK (info_bar_non_visible), NULL);
    g_signal_connect (self->info_bar, "response", G_CALLBACK (info_bar_non_visible), NULL);

    GtkWidget *info_bar_content = gtk_info_bar_get_content_area (GTK_INFO_BAR (self->info_bar));
    gtk_container_add (GTK_CONTAINER (info_bar_content), self->info_msg);

    gtk_overlay_add_overlay (GTK_OVERLAY (self->overlay), self->info_bar);
    gtk_widget_show_all (self->overlay);
    gtk_widget_hide (self->info_bar);
}

/* Lazily initialize the upgrade widget, and attach it to the panel. */
static void pop_os_upgrade_widget (CcUpgradePanel *self) {
    if (NULL == POP_UPGRADE) {
        POP_UPGRADE = pop_upgrade_widget_new ();

        pop_upgrade_widget_callback_event (
            POP_UPGRADE,
            (PopUpgradeWidgetEventCallback) pop_upgrade_callback_event,
            NULL
        );

        pop_upgrade_widget_callback_ready (
            POP_UPGRADE,
            (PopUpgradeWidgetReadyCallback) pop_upgrade_callback_ready,
            NULL
        );

        GtkWidget *widget = pop_upgrade_widget_container (POP_UPGRADE);
        gtk_widget_set_halign (widget, GTK_ALIGN_CENTER);
        gtk_widget_set_size_request (widget, 600, -1);
    }

    if (g_atomic_int_get (&POP_UPGRADE_STATUS) == 0) {
        pop_upgrade_widget_scan (POP_UPGRADE);
    }

    GtkWidget *upgrade_widget = pop_upgrade_widget_container (POP_UPGRADE);
    gtk_container_set_border_width (GTK_CONTAINER (upgrade_widget), 12);
    gtk_container_add (GTK_CONTAINER (self->overlay), upgrade_widget);
    pop_upgrade_widget_callback_error (POP_UPGRADE, (PopUpgradeWidgetErrorCallback) pop_upgrade_callback_error, self);
}

static void cc_upgrade_panel_dispose (GObject *object) {
    CcUpgradePanel *prefs = CC_UPGRADE_PANEL (object);

    // Detach the pop-upgrade widget on disposing this panel.
    GtkWidget *pop = pop_upgrade_widget_container (POP_UPGRADE);
    gtk_container_remove (GTK_CONTAINER (prefs->overlay), pop);

    G_OBJECT_CLASS (cc_upgrade_panel_parent_class)->dispose (object);
}

static void cc_upgrade_panel_finalize (GObject *object) {
    G_OBJECT_CLASS (cc_upgrade_panel_parent_class)->finalize (object);
}

static void cc_upgrade_panel_class_init (CcUpgradePanelClass *klass) {
    GObjectClass *object_class = G_OBJECT_CLASS (klass);

    object_class->dispose = cc_upgrade_panel_dispose;
    object_class->finalize = cc_upgrade_panel_finalize;
}

static void cc_upgrade_panel_init (CcUpgradePanel *prefs) {
    prefs->overlay = gtk_overlay_new ();
    pop_os_info_overlay (prefs);
    pop_os_upgrade_widget (prefs);

    gtk_container_add (GTK_CONTAINER (prefs), prefs->overlay);
}
