#include "eggfileformatchooser.h"

#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <string.h>

enum 
{
  MODEL_COLUMN_ICON,
  MODEL_COLUMN_NAME,
  MODEL_COLUMN_EXTENSIONS,
  MODEL_COLUMN_FORMAT
};

struct _EggFileFormatChooserPrivate
{
  GtkTreeStore *model;
  GtkTreeSelection *selection;
  guint idle_hack;
};

G_DEFINE_TYPE (EggFileFormatChooser, 
	       egg_file_format_chooser,
               GTK_TYPE_EXPANDER);

static void
selection_changed (GtkTreeSelection     *selection,
                   EggFileFormatChooser *self)
{
  gchar *label;
  gchar *name;

  GtkTreeModel *model;
  GtkTreeIter iter;

  if (gtk_tree_selection_get_selected (selection, &model, &iter)) 
    {
      gtk_tree_model_get (model, &iter, 
                          MODEL_COLUMN_NAME, &name,
                          -1);

      label = g_strdup_printf (_("File Format: %s"), name);
      gtk_expander_set_label (GTK_EXPANDER (self), label);

      g_free (name);
      g_free (label);
    }
}

/* XXX This hack is needed, as gtk_expander_set_label seems 
 * not to work from egg_file_format_chooser_init */
static gboolean
select_default_file_format (gpointer data)
{
  EggFileFormatChooser *self = EGG_FILE_FORMAT_CHOOSER (data);
  egg_file_format_chooser_set_format (self, -1, -1);
  self->priv->idle_hack = 0;
  return FALSE;
}

static void
egg_file_format_chooser_init (EggFileFormatChooser *self)
{
  GtkWidget *scroller;
  GtkWidget *view;

  GtkTreeViewColumn *column;
  GtkCellRenderer *cell;
  GtkTreeIter iter;

  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EGG_TYPE_FILE_FORMAT_CHOOSER, 
                                            EggFileFormatChooserPrivate);
  self->priv->model = gtk_tree_store_new (3, GDK_TYPE_PIXBUF, 
                                             G_TYPE_STRING, 
                                             G_TYPE_STRING);

  gtk_tree_store_append (self->priv->model, &iter, NULL);
  gtk_tree_store_set (self->priv->model, &iter,
                      MODEL_COLUMN_NAME, _("By Extension"),
                      -1);

  view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (self->priv->model));
  self->priv->selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
  gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (view), TRUE);

/* file format column */

  column = gtk_tree_view_column_new ();
  gtk_tree_view_column_set_expand (column, TRUE);
  gtk_tree_view_column_set_title (column, _("File Format"));
  gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);

  cell = gtk_cell_renderer_pixbuf_new ();
  gtk_tree_view_column_pack_start (column, cell, FALSE);
  gtk_tree_view_column_set_attributes (column, cell,
                                       "pixbuf", MODEL_COLUMN_ICON,
                                       NULL);

  cell = gtk_cell_renderer_text_new ();
  gtk_tree_view_column_pack_start (column, cell, TRUE);
  gtk_tree_view_column_set_attributes (column, cell,
                                       "text", MODEL_COLUMN_NAME,
                                       NULL);

/* extensions column */

  column = gtk_tree_view_column_new_with_attributes (
    _("Extension(s)"), gtk_cell_renderer_text_new (),
    "text", MODEL_COLUMN_EXTENSIONS, NULL);
  gtk_tree_view_column_set_expand (column, FALSE);
  gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);

  gtk_tree_selection_set_mode (self->priv->selection, GTK_SELECTION_BROWSE);
  g_signal_connect (self->priv->selection, "changed", G_CALLBACK (selection_changed), self);
  self->priv->idle_hack = g_idle_add (select_default_file_format, self);

  scroller = gtk_scrolled_window_new (NULL, NULL);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroller),
                                  GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroller),
                                       GTK_SHADOW_IN);
  gtk_widget_set_size_request (scroller, -1, 150);
  gtk_container_add (GTK_CONTAINER (scroller), view);
  gtk_widget_show_all (scroller);

  gtk_container_add (GTK_CONTAINER (self), scroller);
}

static void
egg_file_format_chooser_class_init (EggFileFormatChooserClass *cls)
{
  g_type_class_add_private (cls, sizeof (EggFileFormatChooserPrivate));
}

GtkWidget*
egg_file_format_chooser_new (void)
{
  return g_object_new (EGG_TYPE_FILE_FORMAT_CHOOSER, NULL);
}

static void
append_file_format (EggFileFormatChooser *self,
                    GtkTreeIter          *parent,
                    GdkPixbuf            *icon,
                    const gchar          *name,
                    va_list              extensions)
{
  const gchar* currext = NULL;
  GString *buffer = NULL;
  GtkTreeIter iter;

  while (NULL != (currext = va_arg (extensions, const gchar*)))
    {
      if (NULL == buffer)
        buffer = g_string_new (NULL);
      else
        g_string_append (buffer, ", ");

      g_string_append (buffer, currext);
    }

  gtk_tree_store_append (self->priv->model, &iter, parent);
  gtk_tree_store_set (self->priv->model, &iter,
                      MODEL_COLUMN_ICON, icon,
                      MODEL_COLUMN_NAME, name,
                      MODEL_COLUMN_EXTENSIONS, buffer ? buffer->str : NULL,
                      -1);

  if (buffer)
    g_string_free (buffer, TRUE);
}

void
egg_file_format_chooser_add_format (EggFileFormatChooser *self,
                                    GdkPixbuf            *icon,
                                    const gchar          *name,
                                    ...)
{
  va_list extensions;

  g_return_if_fail (EGG_IS_FILE_FORMAT_CHOOSER (self));
  g_return_if_fail (NULL != name);

  va_start (extensions, name);
  append_file_format (self, NULL, icon, name,
                      extensions);
  va_end (extensions);
}

void
egg_file_format_chooser_add_sub_format (EggFileFormatChooser *self,
                                        GdkPixbuf            *icon,
                                        const gchar          *name,
                                        ...)
{
  va_list extensions;
  GtkTreeModel *model;
  GtkTreeIter iter;
  gint n_formats;

  g_return_if_fail (EGG_IS_FILE_FORMAT_CHOOSER (self));
  g_return_if_fail (NULL != name);

  model = GTK_TREE_MODEL (self->priv->model);
  n_formats = gtk_tree_model_iter_n_children (model, NULL);
  gtk_tree_model_iter_nth_child (model, &iter, NULL, n_formats - 1);

  va_start (extensions, name);
  append_file_format (self, &iter, icon, name, extensions);
  va_end (extensions);
}

void            
egg_file_format_chooser_set_format (EggFileFormatChooser *self,
                                    gint                  format,
                                    gint                  subformat)
{
  GtkTreeModel *model;
  GtkTreePath *path;
  GtkTreeIter iter;

  gboolean subformat_exists = TRUE;
  gboolean format_exists = TRUE;

  g_return_if_fail (EGG_IS_FILE_FORMAT_CHOOSER (self));

  g_return_if_fail (format >= -1);
  g_return_if_fail (subformat >= -1);

  gtk_tree_selection_unselect_all (self->priv->selection);
  model = GTK_TREE_MODEL (self->priv->model);

  format_exists = gtk_tree_model_iter_nth_child (model, &iter, NULL, format + 1);
  g_return_if_fail (format_exists);
                               
  if (-1 != subformat)
    {
      GtkTreeView *view;

      subformat_exists = (subformat < gtk_tree_model_iter_n_children (model, &iter));
      g_return_if_fail (subformat_exists);

      view = gtk_tree_selection_get_tree_view (self->priv->selection);
      path = gtk_tree_path_new_from_indices (format + 1, -1);

      gtk_tree_view_expand_row (view, path, TRUE);
      gtk_tree_path_free (path);
    }

  path = gtk_tree_path_new_from_indices (format + 1, subformat, -1);
  gtk_tree_selection_select_path (self->priv->selection, path);

  if (self->priv->idle_hack > 0)
    {
      g_source_remove (self->priv->idle_hack);
      self->priv->idle_hack = 0;
    }

  gtk_tree_path_free (path);
}

static gboolean
find_in_list (gchar *list, const gchar *needle)
{
  gchar *saveptr;
  gchar *token;

  for(token = strtok_r (list, ",", &saveptr); NULL != token;
      token = strtok_r (NULL, ",", &saveptr))
    {
      token = g_strstrip (token);

      if (g_str_equal (needle, token))
        return TRUE;
    }

  return FALSE;
}

static gint
guess_file_format (GtkTreeModel *model,
                   GtkTreeIter  *parent,
                   const gchar  *extension,
                   gint         *subformat)
{
  GtkTreeIter iter;
  gint format = -1;

  if (gtk_tree_model_iter_nth_child (model, &iter, parent,
                                     parent ? 0 : 1))
    {
      int i = 0;

      do
        {
          gchar *extension_list = NULL;

          if (-1 == format && 
              gtk_tree_model_iter_has_child (model, &iter))
            {
              format = guess_file_format (model, &iter, extension, NULL);

              if (-1 != format)
                {
                  if (NULL != subformat)
                    *subformat = format;

                  format = i;
                  break;
                }
            }

          gtk_tree_model_get (model, &iter,
                              MODEL_COLUMN_EXTENSIONS, &extension_list,
                              -1);

          if (extension_list)
            {
              if (find_in_list (extension_list, extension))
                format = i;

              g_free (extension_list);
            }
        }
      while (++i, -1 == format && gtk_tree_model_iter_next (model, &iter));
    }

  return format;
}

gint
egg_file_format_chooser_get_format (EggFileFormatChooser *self,
                                    const gchar          *filename G_GNUC_UNUSED,
                                    gint                 *subformat)
{
  const gchar *extension = NULL;
  GtkTreeModel *model;
  GtkTreeIter iter;
  gint format = -1;

  g_return_val_if_fail (EGG_IS_FILE_FORMAT_CHOOSER (self), -1);

  if (gtk_tree_selection_get_selected (self->priv->selection, &model, &iter))
    {
      GtkTreePath *path = gtk_tree_model_get_path (model, &iter);
      gint *indices = gtk_tree_path_get_indices (path);

      format = indices[0] - 1;

      if (NULL != subformat)
        *subformat = gtk_tree_path_get_depth (path) > 1 ? indices[1] : -1;

      gtk_tree_path_free (path);
    }

  if (-1 == format && NULL != filename &&
      NULL != (extension = strrchr(filename, '.')))
    format = guess_file_format (model, NULL, extension, subformat);

  return format;
}

/* vim: set sw=2 sta et: */
