#include <gtk/gtk.h>

typedef struct {
    GtkWidget *window;
    GtkWidget *textview;
    GtkToolItem *recent;
} Widgets;

static void open_file (GtkButton *, Widgets *);
static void save_file (GtkButton *, Widgets *);
static void open_recent_file (GtkButton *, Widgets *);
static void menu_activated (GtkMenuShell *, Widgets *);

int main (int argc, char *argv[])
{
    GtkWidget *vbox, *hbox, *open, *save, *swin, *icon, *menu;
    PangoFontDescription *fd;
    GtkRecentManager *manager;
    Widgets *w;

    gtk_init (&argc, &argv);

    w = g_slice_new (Widgets);
    w->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title (GTK_WINDOW (w->window), "Recent Files");
    gtk_container_set_border_width (GTK_CONTAINER (w->window), 5);
    gtk_widget_set_size_request (w->window, 640, 680);

    g_signal_connect (G_OBJECT (w->window), "destroy",
                      G_CALLBACK (gtk_main_quit), NULL);

    w->textview = gtk_text_view_new ();
    fd = pango_font_description_from_string ("Monospace 8");
    gtk_widget_modify_font (w->textview, fd);
    pango_font_description_free (fd);

    swin = gtk_scrolled_window_new (NULL, NULL);
    open = gtk_button_new_from_stock (GTK_STOCK_OPEN);
    save = gtk_button_new_from_stock (GTK_STOCK_SAVE);
    icon = gtk_image_new_from_stock (GTK_STOCK_OPEN, GTK_ICON_SIZE_BUTTON);
    w->recent = gtk_menu_tool_button_new (icon, "Recent Files");

    /* Load the default recent chooser menu and create a menu from it. */
    manager = gtk_recent_manager_get_default ();
    menu = gtk_recent_chooser_menu_new_for_manager (manager);
    gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (w->recent), menu);

    gtk_recent_chooser_set_show_not_found (GTK_RECENT_CHOOSER (menu), FALSE);
    gtk_recent_chooser_set_local_only (GTK_RECENT_CHOOSER (menu), TRUE);
    gtk_recent_chooser_set_limit (GTK_RECENT_CHOOSER (menu), 10);
    gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (menu),
                                      GTK_RECENT_SORT_MRU);

    g_signal_connect (G_OBJECT (menu), "selection-done",
                      G_CALLBACK (menu_activated), (gpointer) w);
    g_signal_connect (G_OBJECT (open), "clicked",
                      G_CALLBACK (open_file), (gpointer) w);
    g_signal_connect (G_OBJECT (save), "clicked",
                      G_CALLBACK (save_file), (gpointer) w);
    g_signal_connect (G_OBJECT (w->recent), "clicked",
                      G_CALLBACK (open_recent_file), (gpointer) w);

    hbox = gtk_hbox_new (FALSE, 5);
    gtk_box_pack_start (GTK_BOX (hbox), open, FALSE, FALSE, 0);
    gtk_box_pack_start (GTK_BOX (hbox), save, FALSE, FALSE, 0);
    gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (w->recent), FALSE, FALSE,
                        0);

    vbox = gtk_vbox_new (FALSE, 5);
    gtk_container_add (GTK_CONTAINER (swin), w->textview);
    gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
    gtk_box_pack_start (GTK_BOX (vbox), swin, TRUE, TRUE, 0);

    gtk_container_add (GTK_CONTAINER (w->window), vbox);
    gtk_widget_show_all (w->window);

    gtk_main ();
    return 0;
}

/* Save the changes that the user made to the file to disk. */
static void save_file (GtkButton * save, Widgets * w)
{
    const gchar *filename;
    gchar *content;
    GtkTextBuffer *buffer;
    GtkTextIter start, end;

    filename = gtk_window_get_title (GTK_WINDOW (w->window));
    buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (w->textview));
    gtk_text_buffer_get_bounds (buffer, &start, &end);
    content = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);

    if (!g_file_set_contents (filename, content, -1, NULL))
        g_warning ("The file '%s' could not be written!", filename);
    g_free (content);

    if (save) {}
}

/* A menu item was activated. So, retrieve the file URI and open it. */
static void menu_activated (GtkMenuShell * menu, Widgets * w)
{
    GtkTextBuffer *buffer;
    gchar *filename, *content, *fn;
    gsize length;

    filename = gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menu));

    if (filename != NULL) {
        /* Remove the "file://" prefix from the beginning of the URI if it exists. */
        fn = g_filename_from_uri (filename, NULL, NULL);

        if (g_file_get_contents (fn, &content, &length, NULL)) {
            gtk_window_set_title (GTK_WINDOW (w->window), fn);
            buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (w->textview));
            gtk_text_buffer_set_text (buffer, content, -1);
            g_free (content);
        } else
            g_warning ("The file '%s' could not be read!", filename);

        g_free (filename);
        g_free (fn);
    }
}

/* Open a file selected by the user and add it as a new recent file. */
static void open_file (GtkButton * open, Widgets * w)
{
    GtkWidget *dialog;
    GtkRecentManager *manager;
    GtkRecentData *data;
    GtkTextBuffer *buffer;
    gchar *filename, *content, *uri;
    gsize length;

    static gchar *groups[2] = {
        "testapp",
        NULL
    };

    dialog = gtk_file_chooser_dialog_new ("Open File", GTK_WINDOW (w->window),
                                          GTK_FILE_CHOOSER_ACTION_OPEN,
                                          GTK_STOCK_CANCEL,
                                          GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN,
                                          GTK_RESPONSE_OK, NULL);

    if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
        filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));

        if (g_file_get_contents (filename, &content, &length, NULL)) {
            /* Create a new recently used resource. */
            data = g_slice_new (GtkRecentData);
            data->display_name = NULL;
            data->description = NULL;
            data->mime_type = "text/plain";
            data->app_name = (gchar *) g_get_application_name ();
            data->app_exec = g_strjoin (" ", g_get_prgname (), "%u", NULL);
            data->groups = groups;
            data->is_private = FALSE;
            uri = g_filename_to_uri (filename, NULL, NULL);

            /* Add the recently used resource to the default recent manager. */
            manager = gtk_recent_manager_get_default ();
            gtk_recent_manager_add_full (manager, uri, data);

            /* Load the file and set the filename as the title of the window. */
            gtk_window_set_title (GTK_WINDOW (w->window), filename);
            buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (w->textview));
            gtk_text_buffer_set_text (buffer, content, -1);

            g_free (content);
            g_free (uri);
            g_free (data->app_exec);
            g_slice_free (GtkRecentData, data);
        } else
            g_warning ("The file '%s' could not be read!", filename);

        g_free (filename);
    }

    gtk_widget_destroy (dialog);

    if (open) {}
}

/* Allow the user to choose a recent file from the list in the gtk_recent_chooser_dialog.
 * https://bugzilla.gnome.org/show_bug.cgi?id=779605
 * (recentfiles_tstcase:14250): GLib-CRITICAL **: Source ID 86 was not found
 *  when attempting to remove it
 */
static void open_recent_file (GtkButton * recent, Widgets * w)
{
    GtkWidget *dialog;
    GtkTextBuffer *buffer;
    const gchar *uri;
    gchar *filename, *content;
    gsize length;

    dialog = gtk_recent_chooser_dialog_new ("Recent Documents",
                                            GTK_WINDOW (w->window),
                                            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                                            GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
                                            NULL);

    if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
    {
        GtkRecentInfo *info;
        info = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (dialog));
        uri = gtk_recent_info_get_uri (info);

        if (uri) {
            filename = g_filename_from_uri (uri, NULL, NULL);

            if (g_file_get_contents (filename, &content, &length, NULL)) {
                gtk_window_set_title (GTK_WINDOW (w->window), filename);
                buffer =
                    gtk_text_view_get_buffer (GTK_TEXT_VIEW (w->textview));
                gtk_text_buffer_set_text (buffer, content, -1);
                g_free (content);
            } else
                g_warning ("The file '%s' could not be read!", filename);

            g_free (filename);
        }
        gtk_recent_info_unref (info);
    }
    gtk_widget_destroy (dialog);

    if (recent) {}
}
