#include "config.h"
#include <glib.h>
#include <glib/gi18n.h>

#include "msm-desktop-app-dialog.h"

struct _MsmDesktopAppDialog
{
    GtkDialog  parent;

    GtkWidget  *entry;
    GtkWidget  *listbox;
};

G_DEFINE_TYPE (MsmDesktopAppDialog, msm_desktop_app_dialog, GTK_TYPE_DIALOG)

static void
on_search_entry_changed (GtkSearchEntry      *entry,
                         MsmDesktopAppDialog *dialog)
{
    GtkListBoxRow *selected;

    gtk_list_box_invalidate_filter (GTK_LIST_BOX (dialog->listbox));
    selected = gtk_list_box_get_selected_row (GTK_LIST_BOX (dialog->listbox));

    if (selected != NULL && gtk_widget_get_mapped (GTK_WIDGET (selected)))
    {
        gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, TRUE);
    }
    else
    {
        gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
    }
}

static gint
list_sort_app_func (GtkListBoxRow *row1, GtkListBoxRow *row2, gpointer user_data)
{
    GAppInfo *app1, *app2;

    app1 = g_object_get_data (G_OBJECT (row1), "appinfo");
    app2 = g_object_get_data (G_OBJECT (row2), "appinfo");

    return g_utf8_collate (g_app_info_get_name (app1), g_app_info_get_name (app2));
}

static void
list_header_app_func (GtkListBoxRow *row, GtkListBoxRow *before, gpointer user_data)
{

    if (before != NULL && (gtk_list_box_row_get_header (row) == NULL))
    {
        gtk_list_box_row_set_header (row,
                                     gtk_separator_new (GTK_ORIENTATION_HORIZONTAL));
    }
}

static gboolean
list_filter_app_func (GtkListBoxRow *row,
                      gpointer       user_data)
{
    MsmDesktopAppDialog *dialog = MSM_DESKTOP_APP_DIALOG (user_data);
    GAppInfo *app;
    GString  *s1, *s2;

    app = g_object_get_data (G_OBJECT (row), "appinfo");

    s1 = g_string_new (gtk_entry_get_text (GTK_ENTRY (dialog->entry)));
    s2 = g_string_new (g_app_info_get_name (app));

    g_string_ascii_up (s1);
    g_string_ascii_up (s2);

    if (strstr (s2->str, s1->str) != NULL)
        return TRUE;

    return FALSE;
}

static void
on_row_selected (GtkListBox          *box,
                 GtkListBoxRow       *row,
                 MsmDesktopAppDialog *dialog)
{
    if (row != NULL && gtk_widget_get_mapped (GTK_WIDGET (row)))
    {
        gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, TRUE);
    }
    else
    {
        gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
    }
}

static void
setup_dialog (MsmDesktopAppDialog *dialog)
{
    GtkStyleContext *context;
    GtkWidget   *content_area;
    GtkWidget   *searchbar;
    GtkWidget   *searchbutton;
    GtkWidget   *searchimage;
    GtkWidget   *headerbar;
    GtkWidget   *sw;

    content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
    gtk_container_set_border_width (GTK_CONTAINER (content_area), 6);
    gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
    gtk_widget_set_size_request (GTK_WIDGET (dialog), 600, 400);
    gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);

    dialog->entry = gtk_search_entry_new ();
    g_signal_connect (dialog->entry,
                     "search-changed",
                      G_CALLBACK (on_search_entry_changed),
                      dialog);

    gtk_entry_set_placeholder_text (GTK_ENTRY (dialog->entry), _("Search Applications…"));
    gtk_entry_set_width_chars (GTK_ENTRY (dialog->entry), 30);
    gtk_entry_set_activates_default (GTK_ENTRY (dialog->entry), TRUE);
    gtk_entry_set_input_hints (GTK_ENTRY (dialog->entry), GTK_INPUT_HINT_NO_EMOJI);

    searchbar = gtk_search_bar_new ();
    gtk_container_add (GTK_CONTAINER (searchbar), dialog->entry);
    gtk_widget_set_hexpand (searchbar, TRUE);
    gtk_box_pack_start (GTK_BOX (content_area), searchbar, FALSE, FALSE, 0);

    dialog->listbox = gtk_list_box_new ();
    gtk_list_box_set_activate_on_single_click (GTK_LIST_BOX (dialog->listbox), FALSE);
    gtk_list_box_set_sort_func (GTK_LIST_BOX (dialog->listbox), list_sort_app_func, dialog, NULL);
    gtk_list_box_set_header_func (GTK_LIST_BOX (dialog->listbox), list_header_app_func, dialog, NULL);
    gtk_list_box_set_filter_func (GTK_LIST_BOX (dialog->listbox), list_filter_app_func, dialog, NULL);
    g_signal_connect (dialog->listbox,
                     "row-selected",
                      G_CALLBACK (on_row_selected),
                      dialog);

    gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Close"), GTK_RESPONSE_CANCEL);
    gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Add"), GTK_RESPONSE_OK);
    gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
    gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);

    sw = gtk_scrolled_window_new (NULL, NULL);
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
                                    GTK_POLICY_NEVER,
                                    GTK_POLICY_AUTOMATIC);
    gtk_container_add (GTK_CONTAINER (sw), dialog->listbox);
    gtk_box_pack_start (GTK_BOX (content_area), sw, TRUE, TRUE, 0);

    searchbutton = gtk_toggle_button_new ();
    gtk_widget_set_valign (searchbutton, GTK_ALIGN_CENTER);
    searchimage = gtk_image_new_from_icon_name ("edit-find", GTK_ICON_SIZE_MENU);
    gtk_container_add (GTK_CONTAINER (searchbutton), searchimage);

    context = gtk_widget_get_style_context (searchbutton);
    gtk_style_context_add_class (context, "image-button");
    gtk_style_context_remove_class (context, "text-button");

    headerbar = gtk_dialog_get_header_bar (GTK_DIALOG (dialog));
    gtk_header_bar_pack_end (GTK_HEADER_BAR (headerbar), searchbutton);
    g_object_bind_property (searchbutton, "active", searchbar, "search-mode-enabled", G_BINDING_BIDIRECTIONAL);
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (searchbutton), TRUE);
}

static GObject *
msm_desktop_app_dialog_constructor (GType                  type,
                                    guint                  n_construct_app,
                                    GObjectConstructParam *construct_app)
{
    MsmDesktopAppDialog *dialog;

    dialog = MSM_DESKTOP_APP_DIALOG (G_OBJECT_CLASS (msm_desktop_app_dialog_parent_class)->constructor (type,
                                                                                            n_construct_app,
                                                                                            construct_app));

    setup_dialog (dialog);

    return G_OBJECT (dialog);
}

static void
msm_desktop_app_dialog_dispose (GObject *object)
{
    g_return_if_fail (object != NULL);
    g_return_if_fail (MSM_IS_DESKTOP_APP_DIALOG (object));

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

static void
msm_desktop_app_dialog_class_init (MsmDesktopAppDialogClass *klass)
{
    GObjectClass   *object_class = G_OBJECT_CLASS (klass);

    object_class->constructor = msm_desktop_app_dialog_constructor;
    object_class->dispose = msm_desktop_app_dialog_dispose;
}

static void
msm_desktop_app_dialog_init (MsmDesktopAppDialog *dialog)
{

}

static GtkWidget *
create_app_info_row (GAppInfo *app)
{
    GtkWidget  *row;
    GtkWidget  *grid;
    GtkWidget  *image = NULL;
    GtkWidget  *label, *label2;
    gint        height;
    const char *app_name;
    const char *app_summary;
    GIcon      *app_icon;

    row = gtk_list_box_row_new ();
    grid = gtk_grid_new ();
    gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
    gtk_grid_set_row_spacing (GTK_GRID (grid), 6);

    app_name = g_app_info_get_name (app);
    app_icon = g_app_info_get_icon (app);
    app_summary = g_app_info_get_description (app);

    if (app_name == NULL)
        return NULL;

    if (app_icon != NULL)
    {
        image = gtk_image_new_from_gicon (app_icon, GTK_ICON_SIZE_DIALOG);
        gtk_icon_size_lookup (GTK_ICON_SIZE_DIALOG, NULL, &height);
        gtk_image_set_pixel_size (GTK_IMAGE (image), height);
        gtk_grid_attach (GTK_GRID (grid), image, 0, 0, 2, 2);
        gtk_widget_set_hexpand (image, FALSE);
    }

    label = gtk_label_new (app_name);
    gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
    gtk_label_set_max_width_chars (GTK_LABEL (label), 50);
    gtk_widget_set_hexpand (label, TRUE);
    gtk_widget_set_halign (label, GTK_ALIGN_START);
    gtk_widget_set_vexpand (label, FALSE);
    gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
    gtk_grid_attach_next_to (GTK_GRID (grid), label, image, GTK_POS_RIGHT, 1, 1);

    label2 = gtk_label_new (app_summary);
    gtk_label_set_ellipsize (GTK_LABEL (label2), PANGO_ELLIPSIZE_END);
    gtk_label_set_max_width_chars (GTK_LABEL (label2), 50);
    gtk_widget_set_hexpand (label2, TRUE);
    gtk_widget_set_halign (label2, GTK_ALIGN_START);
    gtk_widget_set_vexpand (label2, FALSE);
    gtk_widget_set_valign (label2, GTK_ALIGN_CENTER);
    gtk_grid_attach_next_to (GTK_GRID (grid), label2, label, GTK_POS_BOTTOM, 1, 1);

    gtk_container_add (GTK_CONTAINER (row), grid);
    g_object_set_data (G_OBJECT (row), "appinfo", app);

    return row;
}

GtkWidget *
msm_desktop_app_dialog_new (GspAppManager *manager)
{
    MsmDesktopAppDialog *dialog;
    gboolean   use_header;
    GList     *apps, *l;

    g_object_get (gtk_settings_get_default (),
                 "gtk-dialogs-use-header", &use_header,
                  NULL);

    dialog = g_object_new (MSM_TYPE_DESKTOP_APP_DIALOG,
                           "use-header-bar", use_header,
                           NULL);

    apps = g_app_info_get_all ();
    for (l = apps; l != NULL; l = l->next)
    {
        GAppInfo   *info = l->data;
        GtkWidget  *row;
        const char *id;

        id = g_app_info_get_id (info);
        if (id != NULL && gsp_app_manager_find_app_with_basename (manager, id) == NULL)
        {
            if (g_app_info_should_show (info))
            {
                row = create_app_info_row (info);
                if (row != NULL)
                {
                    gtk_list_box_prepend (GTK_LIST_BOX (dialog->listbox), row);
                }
            }
        }
    }

    return GTK_WIDGET (dialog);
}

const char *
msm_dektop_app_dialog_get_selected (MsmDesktopAppDialog *dialog)
{
    GtkListBoxRow *selected = NULL;
    GAppInfo *app;

    selected = gtk_list_box_get_selected_row (GTK_LIST_BOX (dialog->listbox));
    if (selected != NULL)
    {
        app = g_object_get_data (G_OBJECT (selected), "appinfo");
        return g_desktop_app_info_get_filename (G_DESKTOP_APP_INFO (app));
    }

    return NULL;
}
