/*
 * Copyright (C) 2003-2006 the xine project
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 *
 * GtkComboBox with history
 *
 */

#include "globals.h"

#include <string.h>
#include <stdlib.h>

#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#if GTK_CHECK_VERSION(3, 0, 0)
#include <gdk/gdkkeysyms-compat.h>
#endif

#include "history.h"

static char *eval_text = NULL;

static void
activate_cb (GtkWidget *w, gpointer cb)
{
  char *text = gtk_combo_box_text_get_active_text (cb);
  if (text)
  {
    GtkTreeModel *tree = gtk_combo_box_get_model (cb);
    gint textcol = gtk_combo_box_get_entry_text_column (cb);
    GtkTreeIter iter;
    gboolean found = FALSE;
    if (gtk_tree_model_get_iter_first (tree, &iter))
    {
      do
      {
        GValue v = G_VALUE_INIT;
	gtk_tree_model_get_value (tree, &iter, textcol, &v);
	const char *str = g_value_peek_pointer (&v);
	if (*str == *text && !strcmp (str, text))
	  found = TRUE;
	g_value_unset (&v);
      }
      while (!found && gtk_tree_model_iter_next (tree, &iter));
    }
    if (!found)
      gtk_combo_box_text_prepend_text (cb, text);

    history_activate_t fn =
      (history_activate_t) g_object_get_data (G_OBJECT (cb), "activate-fn");
    fn (cb, text);

    free (text);
  }
  free (eval_text);
  eval_text = NULL;
}

static void
set_iter (GtkComboBox *w, GtkScrollType dir)
{
  GtkEditable *edit = GTK_EDITABLE (gtk_bin_get_child (GTK_BIN (w)));
  int item = gtk_combo_box_get_active (w);
  int prev = item;
  int last = gtk_tree_model_iter_n_children
    (gtk_combo_box_get_model (w), NULL) - 1;

  switch (dir)
  {
  case GTK_SCROLL_STEP_BACKWARD: if (item >= 0)   --item; break;
  case GTK_SCROLL_STEP_FORWARD:  if (item < last) ++item; break;
  case GTK_SCROLL_START:	 item = 0;		  break;
  case GTK_SCROLL_END:		 item = last;		  break;

  default:
    g_printerr (_("gxine: eek, unexpected scroll type %d\n"), dir);
    abort ();
  }

  if (prev == item)
    return;

  if (prev < 0)
  {
    free (eval_text);
    eval_text = gtk_editable_get_chars (edit, 0, -1);
  }

  gtk_combo_box_set_active (w, item);

  if (item < 0)
  {
    gint pos = 0;
    gtk_editable_delete_text (edit, 0, -1);
    if (eval_text)
      gtk_editable_insert_text (edit, eval_text, -1, &pos);
  }
}

static gboolean
scroll_cb (GtkComboBox *w, GdkEventKey *e, GtkWidget *t)
{
  switch (e->state & GXINE_MODIFIER_MASK)
  {
  default:
    return FALSE;

  case 0:
    switch (e->keyval)
    {
    default:		return FALSE;
    case GDK_Up:	set_iter (w, GTK_SCROLL_STEP_BACKWARD);	break;
    case GDK_Down:	set_iter (w, GTK_SCROLL_STEP_FORWARD);	break;
    }
    break;

  case GDK_CONTROL_MASK:
    switch (e->keyval)
    {
    default:		return FALSE;
    case GDK_Up:	set_iter (w, GTK_SCROLL_START);	return TRUE;
    case GDK_Down:	set_iter (w, GTK_SCROLL_END);	return TRUE;
    }
    break;
  }

  return TRUE;
}

GtkWidget *
history_combo_box_new (history_activate_t fn)
{
  GtkWidget *w = gtk_combo_box_text_new_with_entry ();
  g_object_set_data (G_OBJECT (w), "activate-fn", fn);
  g_signal_connect (gtk_bin_get_child (GTK_BIN (w)),
                    "activate",
		    G_CALLBACK (activate_cb), w);
  g_signal_connect (w, "key-press-event",
		    G_CALLBACK (scroll_cb), NULL);
  return w;
}

void
history_combo_box_set_activate_button (GtkWidget *cb, GtkWidget *activate)
{
  g_signal_connect (activate, "clicked", G_CALLBACK (activate_cb), cb);
}

void
history_combo_box_activate (GtkWidget *cb)
{
  activate_cb (NULL, cb);
}

void history_combo_box_clear (GtkWidget *w, gpointer data)
{
  free (eval_text);
  eval_text = NULL;
  gtk_combo_box_set_active ((GtkComboBox *)w, -1);
  gtk_list_store_clear
    ((GtkListStore *)gtk_combo_box_get_model ((GtkComboBox *)w));
}
