/*
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * See the COPYING file for license information.
 *
 * Guillaume Chazarain <guichaz@gmail.com>
 */

/*****************************************
 * The thumbnails browser in a tree view *
 *****************************************/

#include <string.h>             /* memset() */

#include "gliv.h"
#include "tree_browser.h"
#include "tree.h"
#include "thumbnails.h"
#include "images_menus.h"
#include "next_image.h"
#include "messages.h"
#include "loading.h"
#include "rendering.h"

extern GlivImage *current_image;

static GtkTreeStore *tree_store;
static GtkTreeView *tree_view;

/*
 * Association between a directory and a GtkTreePath
 * Used when adding filenames.
 */
static GHashTable *dir_path_hash = NULL;

/* Avoid reentrance */
static gint disable_tree = 0;

/*
 * If a row is selected when we cannot load an image, we
 * record the filename to load it when possible.
 */
static const gchar *next_filename;

/* The tree columns (they are not all displayed) */
enum {
    PIXBUF_COLUMN,
    NAME_COLUMN,
    PATH_COLUMN,
    N_COLUMNS
};

static tree_item *make_tree_rec(GtkTreeIter * where, GNode * node)
{
    static const gchar *browser = NULL;
    static gint percent = 0, number = 0;
    tree_item *item, *first_item;
    GNode *child;

    if (where == NULL) {
        /* First time for this browser */
        number = 0;
        percent = 0;
        set_progress(NULL, NULL, -1);

        if (browser == NULL)
            /* First time */
            browser = _("Browser");
        return NULL;
    }

    item = node->data;

    if (G_NODE_IS_LEAF(node)) {
        fill_thumbnail(item);
        gtk_tree_store_set(tree_store, where,
                           PIXBUF_COLUMN, item->thumb,
                           NAME_COLUMN, item->name,
                           PATH_COLUMN, item->path, -1);
        set_progress(browser, &percent, number);
        number++;
        return item;
    }

    g_hash_table_insert(dir_path_hash, item->path,
                        gtk_tree_model_get_path(GTK_TREE_MODEL(tree_store),
                                                where));

    first_item = NULL;
    for (child = g_node_first_child(node); child; child = child->next) {
        GtkTreeIter iter;
        gtk_tree_store_append(tree_store, &iter, where);
        item = make_tree_rec(&iter, child);
        if (first_item == NULL && item != NULL && item->thumb != NULL)
            first_item = item;
    }

    item = node->data;
    gtk_tree_store_set(tree_store, where,
                       PIXBUF_COLUMN, first_item ? first_item->thumb : NULL,
                       NAME_COLUMN, item->path,
                       PATH_COLUMN, first_item ? first_item->path : NULL, -1);

    return first_item;
}

void load_later(void)
{
    if (next_filename != NULL && !currently_loading() && current_image->node) {
        menu_load(next_filename);
        if (current_image->node->data == next_filename)
            next_filename = NULL;
    }
}

static void activate_row(GtkTreeSelection * selection)
{
    GtkTreeIter iter;
    GtkTreeModel *model;
    gchar *path;

    if (!gtk_tree_selection_get_selected(selection, &model, &iter))
        return;

    gtk_tree_model_get(model, &iter, PATH_COLUMN, &path, -1);
    next_filename = path;
    do_later(G_PRIORITY_DEFAULT, load_later);
}

static gboolean build_tree_browser(void)
{
    GtkTreeIter iter;
    GNode *tree;

    tree = get_tree();
    if (tree == NULL)
        return FALSE;

    if (dir_path_hash != NULL)
        g_hash_table_destroy(dir_path_hash);

    dir_path_hash = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
                                          (GDestroyNotify) gtk_tree_path_free);

    if (tree_store == NULL)
        /* First time */
        tree_store = gtk_tree_store_new(N_COLUMNS,
                                        GDK_TYPE_PIXBUF, G_TYPE_STRING,
                                        G_TYPE_POINTER);
    else
        gtk_tree_store_clear(tree_store);

    gtk_tree_store_append(tree_store, &iter, NULL);
    make_tree_rec(NULL, NULL);
    make_tree_rec(&iter, tree);

    set_progress(NULL, NULL, 0);
    end_using_tree();
    return TRUE;
}

static void destroy_tree_view(GtkWindow * window)
{
    gtk_widget_destroy(GTK_WIDGET(window));
    tree_view = NULL;
}

void show_tree_browser(void)
{
    GtkCellRenderer *name_renderer;
    GtkTreeViewColumn *col;
    GtkTreeSelection *selection;
    GtkScrolledWindow *scroll;
    GtkWindow *window;

    if (tree_view != NULL)
        /* Currently displayed */
        return;

    if (tree_store == NULL && !build_tree_browser())
        return;

    tree_view =
        GTK_TREE_VIEW(gtk_tree_view_new_with_model(GTK_TREE_MODEL(tree_store)));

    gtk_tree_view_set_enable_search(tree_view, TRUE);

    col =
        gtk_tree_view_column_new_with_attributes(_("Thumb"),
                                                 gtk_cell_renderer_pixbuf_new(),
                                                 "pixbuf", PIXBUF_COLUMN, NULL);
    gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), col);

    name_renderer = gtk_cell_renderer_text_new();
    g_object_set(name_renderer,
                 "ellipsize-set", TRUE,
                 "ellipsize", PANGO_ELLIPSIZE_START, NULL);
    col =
        gtk_tree_view_column_new_with_attributes(_("Name"), name_renderer,
                                                 "text", NAME_COLUMN, NULL);
    gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), col);
    gtk_widget_show_all(GTK_WIDGET(tree_view));

    scroll = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(NULL, NULL));
    gtk_scrolled_window_set_policy(scroll,
                                   GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
    gtk_container_add(GTK_CONTAINER(scroll), GTK_WIDGET(tree_view));
    gtk_widget_show_all(GTK_WIDGET(scroll));

    window = new_window(_("Thumbnails browser"));
    gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(scroll));
    gtk_window_set_default_size(window, 300, 600);
    gtk_widget_show_all(GTK_WIDGET(window));

    selection = gtk_tree_view_get_selection(tree_view);
    g_signal_connect(selection, "changed", G_CALLBACK(activate_row), NULL);

    g_signal_connect(window, "delete-event", G_CALLBACK(destroy_tree_view),
                     NULL);

    highlight_current_image();
}

void highlight_current_image(void)
{
    gchar *path;
    GtkTreePath *tree_path;
    GtkTreeIter iter, child;

    if (tree_view == NULL || !GTK_WIDGET_VISIBLE(tree_view) ||
        current_image->node == NULL)
        return;

    if (next_filename) {
        do_later(G_PRIORITY_DEFAULT, load_later);
        return;
    }

    path = g_strdup(current_image->node->data);
    do {
        gchar *new_path = g_path_get_dirname(path);

        g_free(path);
        path = new_path;

        tree_path = g_hash_table_lookup(dir_path_hash, path);
    } while (!tree_path && !g_str_equal(path, "/") && !g_str_equal(path, "."));

    g_free(path);

    if (tree_path == NULL)
        return;

    if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(tree_store), &iter, tree_path))
        return;

    if (!gtk_tree_model_iter_children
        (GTK_TREE_MODEL(tree_store), &child, &iter))
        return;

    do {
        GValue tree_filename;
        memset(&tree_filename, 0, sizeof(tree_filename));

        gtk_tree_model_get_value(GTK_TREE_MODEL(tree_store), &child,
                                 PATH_COLUMN, &tree_filename);

        if (g_value_peek_pointer(&tree_filename) == current_image->node->data) {
            tree_path =
                gtk_tree_model_get_path(GTK_TREE_MODEL(tree_store), &child);

            disable_tree++;
            gtk_tree_view_expand_to_path(tree_view, tree_path);
            gtk_tree_view_expand_row(tree_view, tree_path, FALSE);
            gtk_tree_view_scroll_to_cell(tree_view, tree_path,
                                         NULL, FALSE, 0.0, 0.0);
            gtk_tree_view_set_cursor(tree_view, tree_path, NULL, FALSE);
            disable_tree--;

            gtk_tree_path_free(tree_path);
            break;
        }

        g_value_unset(&tree_filename);
    } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(tree_store), &child));
}

void cond_rebuild_tree_browser(void)
{
    if (dir_path_hash != NULL)
        build_tree_browser();
}
