/*
 * This file is part of GNAC - Gnome Audio Converter
 *
 * Copyright (C) 2007 - 2012 Gnac
 *    
 *    - DUPASQUIER  Benoit    <bdupasqu@src.gnome.org>
 *    - JOAQUIM     David     <djoaquim@src.gnome.org>
 *    - ROUX        Alexandre <alexroux@src.gnome.org>
 *
 * GNAC 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 3 of the License, or
 * (at your option) any later version.
 *
 * GNAC 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 GNAC; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, 
 * Boston, MA  02110-1301  USA
 */

#include <glib-object.h>

#include "gnac-bars.h"
#include "gnac-file-list.h"
#include "gnac-main.h"
#include "gnac-properties.h"
#include "gnac-ui.h"
#include "gnac-ui-utils.h"
#include "gnac-utils.h"



static GtkTreeView      *view = NULL;
static GtkTreeModel     *model = NULL;
static GtkTreeSelection *selection = NULL;
static GHashTable       *reference_table = NULL;


static void
gnac_file_list_display_stock(GtkTreeViewColumn *tree_column,
                             GtkCellRenderer   *cell,
                             GtkTreeModel      *tree_model,
                             GtkTreeIter       *iter,
                             gpointer           data)
{
  gchar *stock_id;
  gtk_tree_model_get(tree_model, iter, COL_STOCK, &stock_id, -1);
  g_object_set(G_OBJECT(cell), "stock-id", stock_id, NULL);
}


static gint
gnac_file_list_count_selected_rows(void)
{
  return gtk_tree_selection_count_selected_rows(selection);
}


guint
gnac_file_list_count_rows(void) 
{
  return g_hash_table_size(reference_table);
}


void
gnac_file_list_on_row_activated_cb(GtkTreeView       *treeview,
                                   GtkTreePath       *path,
                                   GtkTreeViewColumn *col,
                                   gpointer           user_data)
{
  gnac_properties_window_show();
}


static void
gnac_file_list_on_row_inserted_cb(GtkTreeModel *tree_model, 
                                  GtkTreePath  *path, 
                                  GtkTreeIter  *iter, 
                                  gpointer      user_data)
{
  gnac_properties_update_arrows();
}


static void
gnac_file_list_selection_changed_cb(GtkTreeSelection *selection, 
                                    gpointer          user_data)
{
  gint selected_rows = gnac_file_list_count_selected_rows();
  
  if (selected_rows != 0 && state == GNAC_AUDIO_READY_STATE) {
    gnac_bars_activate_remove(TRUE);
  }

  gnac_bars_activate_properties(selected_rows == 1);
}


GtkWidget *
gnac_file_list_new(void)
{
  view = GTK_TREE_VIEW(gnac_ui_get_widget("file_list"));
  model = GTK_TREE_MODEL(gtk_list_store_new(NUM_COLS, 
      G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING));
  reference_table = g_hash_table_new_full(g_str_hash, g_str_equal,
      g_free, (GDestroyNotify) gtk_tree_row_reference_free);

  GtkCellRenderer *renderer;

  renderer = gtk_cell_renderer_pixbuf_new();
  gtk_tree_view_insert_column_with_data_func(view, -1,
      "Status", renderer, gnac_file_list_display_stock, NULL, NULL);

  renderer = gtk_cell_renderer_text_new();
  g_object_set(G_OBJECT(renderer), "ypad", 5, NULL);
  gtk_tree_view_insert_column_with_attributes(view, -1,
      "Filelist", renderer, "text", COL_DISPLAY, NULL);

  gtk_tree_view_set_model(view, model);
  
  GtkTreeViewColumn *column;

  column = gtk_tree_view_get_column(view, COL_URI);
  gtk_tree_view_column_set_sort_column_id(column, COL_URI);
  gtk_tree_view_column_clicked(column);

  column = gtk_tree_view_get_column(view, COL_STOCK);
  gtk_tree_view_column_set_visible(column, FALSE);
  
  g_signal_connect(G_OBJECT(model), "row-inserted", 
      G_CALLBACK(gnac_file_list_on_row_inserted_cb), NULL);

  selection = gtk_tree_view_get_selection(view);
  gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
  g_signal_connect(G_OBJECT(selection), "changed", 
      G_CALLBACK(gnac_file_list_selection_changed_cb), NULL);
  
  g_object_unref(model);

  return GTK_WIDGET(view);
}


void
gnac_file_list_attach_default_model(void)
{
  gtk_tree_view_set_model(view, model);
  g_object_unref(model);
}


void
gnac_file_list_detach_default_model(void)
{
  g_object_ref(model);
  gtk_tree_view_set_model(view, NULL);
}


void
gnac_file_list_add_row(const gchar *uri)
{
  g_return_if_fail(uri);

  gchar *name = gnac_utils_get_display_name(uri, NULL);

  GtkTreeIter iter;
  gtk_list_store_append(GTK_LIST_STORE(model), &iter);
  gtk_list_store_set(GTK_LIST_STORE(model), &iter,
      COL_URI, uri, COL_DISPLAY, name, -1);

  g_free(name);

  GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
  if (!path) {
    g_debug("Unable to create path");
    return;
  }

  GtkTreeRowReference *ref = gtk_tree_row_reference_new(model, path);
  g_hash_table_insert(reference_table, g_strdup(uri), ref);

  gtk_tree_path_free(path);
}


gboolean
gnac_file_list_get(GtkTreeRowReference  *reference,
                   gchar               **file_uri)
{
  g_return_val_if_fail(reference, FALSE);

  GtkTreePath *path = gtk_tree_row_reference_get_path(reference);
  if (!path) return FALSE;
  
  GtkTreeIter iter;
  gboolean path_exists = gtk_tree_model_get_iter(model, &iter, path);

  if (path_exists) {
    gtk_tree_model_get(model, &iter, COL_URI, file_uri, -1);
  }

  gtk_tree_path_free(path);

  return path_exists;
}


void 
gnac_file_list_remove_row(const gchar *uri)
{
  GtkTreeRowReference *ref = g_hash_table_lookup(reference_table, uri);
  g_return_if_fail(ref);

  GtkTreePath *path = gtk_tree_row_reference_get_path(ref);
  if (!path) {
    g_hash_table_remove(reference_table, uri);
    return;
  }

  GtkTreeRowReference *new_ref = NULL;

  if (gnac_file_list_has_next_row(ref)) {
    new_ref = gtk_tree_row_reference_copy(ref);
    gnac_file_list_get_next_row(&new_ref);
  } else if (gnac_file_list_has_prev_row(ref)) {
    new_ref = gtk_tree_row_reference_copy(ref);
    gnac_file_list_get_prev_row(&new_ref);
  }

  GtkTreeIter iter;
  if (gtk_tree_model_get_iter(model, &iter, path)) {
    gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
  }

  if (new_ref) {
    gnac_file_list_select_row(new_ref);
    gnac_properties_set_row(new_ref);
  }

  g_hash_table_remove(reference_table, uri);

  gtk_tree_path_free(path);
}


void
gnac_file_list_remove_all(void)
{
  gnac_file_list_detach_default_model();
  gtk_list_store_clear(GTK_LIST_STORE(model));
  g_hash_table_remove_all(reference_table);
  gnac_file_list_attach_default_model();
  gtk_tree_view_columns_autosize(view);
}


GList *
gnac_file_list_get_selected_rows(void)
{

  GList *row_path = gtk_tree_selection_get_selected_rows(selection, &model);
  GList *next = row_path;
  GList *row_references = NULL;

  while (next) {
    row_references = g_list_prepend(row_references, 
        gtk_tree_row_reference_new(model, next->data));
    next = g_list_next(next);
  }

  row_references = g_list_reverse(row_references);

  g_list_free_full(row_path, (GDestroyNotify) gtk_tree_path_free);

  return row_references;
}


gboolean
gnac_file_list_get_current_row(GtkTreeRowReference **reference)
{
  gtk_tree_row_reference_free(*reference);

  GList *rows_path = gtk_tree_selection_get_selected_rows(selection, &model);

  /* select the first selected row */
  *reference = gtk_tree_row_reference_new(model, rows_path->data);

  g_list_free_full(rows_path, (GDestroyNotify) gtk_tree_path_free);

  return gtk_tree_row_reference_valid(*reference);
}


gboolean
gnac_file_list_has_next_row(GtkTreeRowReference *reference)
{
  g_return_val_if_fail(reference, FALSE);

  GtkTreePath *path = gtk_tree_row_reference_get_path(reference);
  if (!path) return FALSE;

  gtk_tree_path_next(path);
  GtkTreeRowReference *temp = gtk_tree_row_reference_new(model, path);
  gboolean has_next_row = gtk_tree_row_reference_valid(temp);

  gtk_tree_row_reference_free(temp);
  gtk_tree_path_free(path);

  return has_next_row;
}


gboolean
gnac_file_list_has_prev_row(GtkTreeRowReference *reference)
{
  g_return_val_if_fail(reference, FALSE);

  GtkTreePath *first = gtk_tree_path_new_first();
  GtkTreePath *path = gtk_tree_row_reference_get_path(reference);

  gboolean has_prev_row = path && gtk_tree_path_compare(path, first) != 0;

  gtk_tree_path_free(path);
  gtk_tree_path_free(first);

  return has_prev_row;
}


gboolean
gnac_file_list_get_next_row(GtkTreeRowReference **reference)
{
  g_return_val_if_fail(*reference, FALSE);

  GtkTreePath *path = gtk_tree_row_reference_get_path(*reference);
  gtk_tree_path_next(path);
  gtk_tree_row_reference_free(*reference);
  *reference = gtk_tree_row_reference_new(model, path);
  gtk_tree_path_free(path);

  return gtk_tree_row_reference_valid(*reference);
}


gboolean
gnac_file_list_get_prev_row(GtkTreeRowReference **reference)
{
  g_return_val_if_fail(*reference, FALSE);

  GtkTreePath *path = gtk_tree_row_reference_get_path(*reference);
  gboolean has_prev_row = gnac_file_list_has_prev_row(*reference);

  gtk_tree_row_reference_free(*reference);

  if (has_prev_row) {
    gtk_tree_path_prev(path);
    *reference = gtk_tree_row_reference_new(model, path);
  }

  gtk_tree_path_free(path);

  return has_prev_row;
}


void
gnac_file_list_select_row(GtkTreeRowReference *reference)
{
  g_return_if_fail(reference);

  GtkTreePath *path = gtk_tree_row_reference_get_path(reference);
  if (!path) return;
  
  gtk_tree_view_scroll_to_cell(view, path, NULL, FALSE, 0.0, 0.0);
  gtk_tree_selection_unselect_all(selection);
  gtk_tree_selection_select_path(selection, path);

  gtk_tree_path_free(path);
}


void
gnac_file_list_select_uri(const gchar *uri)
{
  GtkTreeRowReference *ref = g_hash_table_lookup(reference_table, uri);
  g_return_if_fail(ref);

  gnac_file_list_select_row(ref);
}


void
gnac_file_list_visual_error(const gchar *uri, 
                            const gchar *msg,
                            const gchar *stock_item)
{
  GtkTreeRowReference *ref = g_hash_table_lookup(reference_table, uri);
  g_return_if_fail(ref);

  GtkTreePath *path = gtk_tree_row_reference_get_path(ref);

  GtkTreeIter iter;
  if (gtk_tree_model_get_iter(model, &iter, path)) {
    gtk_list_store_set(GTK_LIST_STORE(model), &iter, 
        COL_STOCK, stock_item ? stock_item : GTK_STOCK_DIALOG_ERROR,
        COL_TOOLTIP, g_strdup(msg), -1);
    gtk_tree_path_free(path);

    GtkTreeViewColumn *column = gtk_tree_view_get_column(view, COL_STOCK);
    if (!gtk_tree_view_column_get_visible(column)) {
      gtk_tree_view_column_set_visible(column, TRUE);
    }
  }
}


void
gnac_file_list_hide_visual_bar(void)
{
  GtkTreeViewColumn *column = gtk_tree_view_get_column(view,COL_STOCK);
  gtk_tree_view_column_set_visible(column, FALSE);
}


void
gnac_file_list_remove_visual_error(const gchar *uri)
{
  GtkTreeRowReference *ref =  g_hash_table_lookup(reference_table, uri);
  g_return_if_fail(ref);

  GtkTreePath *path = gtk_tree_row_reference_get_path(ref);

  GtkTreeIter iter;
  if (gtk_tree_model_get_iter(model, &iter, path)) {
    gtk_list_store_set(GTK_LIST_STORE(model), &iter, 
        COL_STOCK, NULL, COL_TOOLTIP, NULL, -1);
  }

  gtk_tree_path_free(path);
}


gboolean
gnac_file_list_on_button_pressed(GtkWidget      *treeview, 
                                 GdkEventButton *event, 
                                 gpointer        user_data)
{  
  GtkTreePath *path;
  gboolean row_exists = gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(treeview),
      (gint) event->x, (gint) event->y, &path, NULL, NULL, NULL);

  if (gnac_ui_utils_event_is_double_left_click(event) && !row_exists) {
    gnac_ui_on_add_cb(NULL, NULL);
    gtk_tree_path_free(path);
    return TRUE;
  }

  gboolean ret = FALSE;

  if (gnac_ui_utils_event_is_single_right_click(event)) {
    if (row_exists && gnac_file_list_count_selected_rows() <= 1) {
      GtkTreeRowReference *reference = gtk_tree_row_reference_new(model, path);
      gnac_file_list_select_row(reference);
      gtk_tree_row_reference_free(reference);
    }

    gnac_ui_show_popup_menu(treeview, event, user_data);
    ret = TRUE;
  }

  gtk_tree_path_free(path);

  return ret;
}


gboolean
gnac_file_list_popup_menu(GtkWidget *treeview, 
                          gpointer   user_data)
{
  gnac_ui_show_popup_menu(treeview, NULL, user_data);
  return TRUE;
}


void
gnac_file_list_update_cursor(void)
{
  GdkCursor *cursor = NULL;
  if (state == GNAC_AUDIO_FILE_ACTION_STATE ||
      state == GNAC_AUDIO_CONVERT_STATE)
  {
    cursor = gdk_cursor_new(GDK_WATCH);
  }
  gdk_window_set_cursor(gtk_tree_view_get_bin_window(view), cursor);
  if (G_IS_OBJECT(cursor)) g_object_unref(cursor);
}


void
gnac_file_list_destroy(void)
{
  if (reference_table) {
    g_hash_table_unref(reference_table);
    reference_table = NULL;
  }
}
