
#include <gtk/gtksignal.h>

#include <gtk/gtkmain.h>
#include <gtk/gtkcellrenderer.h>
#include <gtk/gtkcellrenderertext.h>
#include <gtk/gtktreeviewcolumn.h>
#include <gtk/gtktreeselection.h>
#include <gtk/gtkbutton.h>

#include "gw_list.h"

enum {
  GW_LIST_SIGNAL,
  GW_LIST_EVENT,
  LAST_SIGNAL
};


static gint num_list = 0;

static void gw_list_class_init          (Gw_listClass *klass);
static void gw_list_init                (Gw_list      *ttt);

static guint gw_list_signals[LAST_SIGNAL] = { 0 };

GType gw_list_get_type (void)
{
  static GType ttt_type = 0;

  if (!ttt_type)
    {
      static const GTypeInfo ttt_info =
	{
	  sizeof (Gw_listClass),
	  NULL, /* base_init */
	  NULL, /* base_finalize */
	  (GClassInitFunc) gw_list_class_init,
	  NULL, /* class_finalize */
	  NULL, /* class_data */
	  sizeof (Gw_list),
	  0,
	  (GInstanceInitFunc) gw_list_init,
	};

      ttt_type = g_type_register_static (GTK_TYPE_SCROLLED_WINDOW, "Gw_list", &ttt_info, 0);
    }

  return ttt_type;
}

static void
gw_list_class_init (Gw_listClass *klass)
{
  gw_list_signals[GW_LIST_SIGNAL] = g_signal_new ("gw_list",
						  G_TYPE_FROM_CLASS (klass),
						  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
						  G_STRUCT_OFFSET (Gw_listClass, gw_list),
						  NULL, 
						  NULL,                
						  g_cclosure_marshal_VOID__VOID,
						  G_TYPE_NONE, 0);

  gw_list_signals[GW_LIST_EVENT] = g_signal_new ("gw_list_event",
						 G_TYPE_FROM_CLASS (klass),
						 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
						 G_STRUCT_OFFSET (Gw_listClass, gw_list),
						 NULL, 
						 NULL,                
						 g_cclosure_marshal_VOID__BOXED,
						 G_TYPE_NONE, 1,
						 GDK_TYPE_EVENT);


}

/* Appelée par gw_list_new via g_object_new */
static void gw_list_init (Gw_list *ttt)
{

}

static void gw_list_emit (GtkWidget *select ,Gw_list *list)
{
  GdkEvent *event;

  event = gtk_get_current_event ();
  g_signal_emit (G_OBJECT (list) ,gw_list_signals[GW_LIST_SIGNAL], 0);
  g_signal_emit (G_OBJECT (list) ,gw_list_signals[GW_LIST_EVENT], 0 ,event);



}


GtkWidget* gw_list_new (char *title ,char *title_col1 ,gint type_select)
{
  Gw_list *ttt;

  GtkCellRenderer   *renderer;
  GtkTreeViewColumn *col;
  GtkTreeSelection  *select;


  ttt = g_object_new (GW_LIST_TYPE, NULL);

  /* Create the graph list */
  ttt->store = gtk_list_store_new ( GW_LIST_NB_COLS
				    ,G_TYPE_STRING
				    ,G_TYPE_INT
				    ,G_TYPE_BOOLEAN
				    );
  ttt->model = GTK_TREE_MODEL(ttt->store);
  ttt->view = gtk_tree_view_new_with_model (ttt->model);
  
  /* TreeView definitions */
  
  /* First column:  string   */
  renderer = gtk_cell_renderer_text_new ();
  g_object_set (renderer,"family" ,"Monospace" ,NULL);
  col = gtk_tree_view_column_new_with_attributes (title_col1
  						  ,renderer
  						  ,"text" ,GW_LIST_STR_COL
  						  ,NULL);
  gtk_tree_view_append_column (GTK_TREE_VIEW (ttt->view), col);
  
  /* Second column: index number  */
  renderer = gtk_cell_renderer_text_new ();
  col = gtk_tree_view_column_new_with_attributes ("num"
  						  ,renderer
  						  ,"text" ,GW_LIST_NUM_COL
  						  ,NULL);
  
  /* Third column: hidden/visible flag   */
  renderer = gtk_cell_renderer_text_new ();
  col = gtk_tree_view_column_new_with_attributes ("key"
  						  ,renderer
  						  ,"text" ,GW_LIST_BOOL_COL
  						  ,NULL);
  
  gtk_scrolled_window_set_policy  (GTK_SCROLLED_WINDOW(ttt)
				   ,GTK_POLICY_AUTOMATIC
				   ,GTK_POLICY_AUTOMATIC);

  /* Set selection mode */
  select = gtk_tree_view_get_selection (GTK_TREE_VIEW (ttt->view));
  gtk_tree_selection_set_mode (select, type_select);
  ttt->type_select = type_select;

  g_signal_connect (select ,"changed" ,G_CALLBACK (gw_list_emit) ,ttt);
  

  gtk_container_add(GTK_CONTAINER(ttt) ,ttt->view);

  num_list++;

  return GTK_WIDGET (ttt);
}


void gw_list_append (Gw_list *ttt ,gchar *buf ,gint n ,gboolean bool)
{
  GtkTreeIter iter;

  gtk_list_store_append (ttt->store , &iter);
  gtk_list_store_set (ttt->store ,&iter
		      ,GW_LIST_STR_COL ,buf
		      ,GW_LIST_NUM_COL  ,n
		      ,GW_LIST_BOOL_COL ,bool
		      ,-1);
}

void gw_list_clear (Gw_list *ttt)
{
  gtk_list_store_clear (ttt->store);
}


gboolean gw_list_set (Gw_list *ttt ,gint row ,gchar *buf ,gint n ,gboolean bool)
{
  GtkTreeIter   iter;
  gchar ibuf[6];

  snprintf (ibuf ,5 ,"%d" ,row);
  if (gtk_tree_model_get_iter_from_string (ttt->model ,&iter ,ibuf)) {
    gtk_list_store_set (ttt->store ,&iter
			,GW_LIST_STR_COL ,buf
			,GW_LIST_NUM_COL  ,n
			,GW_LIST_BOOL_COL ,bool
			,-1);
    return TRUE;
  }
  return FALSE;
}

gboolean gw_list_get (Gw_list *ttt ,gint row ,gchar **buf ,gint *n ,gboolean *bool)
{
  GtkTreeIter iter;
  gchar ibuf[6];
  
  snprintf (ibuf ,5 ,"%d" ,row);
  if (gtk_tree_model_get_iter_from_string (ttt->model ,&iter ,ibuf)) {
    gtk_tree_model_get (ttt->model, &iter
			,GW_LIST_STR_COL ,buf
			,GW_LIST_NUM_COL  ,n
			,GW_LIST_BOOL_COL ,bool
			, -1);
    return TRUE;
  }
  return FALSE;
}

void gw_list_remove (Gw_list *ttt ,gint row)
{
  GtkTreeIter   iter;
  gchar ibuf[6];

  snprintf (ibuf ,5 ,"%d" ,row);
  if (gtk_tree_model_get_iter_from_string (ttt->model ,&iter ,ibuf)) {
    gtk_list_store_remove (ttt->store ,&iter);
  }
}

/** Return in the boolean array rows[]
 *       TRUE  if the rows is selected
 *       FALSE otherwise
 *       The array must be allocated before the call.
 */
void gw_list_get_selected_rows (Gw_list *ttt ,gboolean *rows ,gint *last)
{
  GtkTreeSelection *select;
  GtkTreeIter iter;
  gint i;
 
  select = gtk_tree_view_get_selection (GTK_TREE_VIEW (ttt->view));
  if (gtk_tree_model_get_iter_first (ttt->model ,&iter)) {
    do {
      gtk_tree_model_get (ttt->model, &iter ,GW_LIST_NUM_COL ,&i ,-1);
      rows[i] = gtk_tree_selection_iter_is_selected (select ,&iter);
      if (rows[i]) *last = i;
    } while (gtk_tree_model_iter_next (ttt->model ,&iter));
  }
}

/**  Create and return an array of gint with the index
 *   of the selected rows.
 *   On return, ns is the number of selected rows.
 */
gint *gw_list_selected_list (Gw_list *ttt ,gint *nb)
{
  GtkTreeSelection *select;
  GtkTreeIter iter;
  gint i ,nal;
  gint *retval;
  gint n = 0;
 
  *nb = nal = gw_list_count_rows_selected (ttt);
  if (nal == 0) nal = 1; 
  retval = g_malloc (nal * sizeof(gint));

  select = gtk_tree_view_get_selection (GTK_TREE_VIEW (ttt->view));
  if (gtk_tree_model_get_iter_first (ttt->model ,&iter)) {
    do {
      if (gtk_tree_selection_iter_is_selected (select ,&iter)) {
	gtk_tree_model_get (ttt->model, &iter ,GW_LIST_NUM_COL ,&i ,-1);
	retval[n] = i;
	n++;
      }
    } while (gtk_tree_model_iter_next (ttt->model ,&iter));
  }
  return retval;
}

gint gw_list_get_first_selected_row_num (Gw_list *ttt)
{
  GtkTreeSelection *select;
  GtkTreeIter iter;
  gint i;
 
  select = gtk_tree_view_get_selection (GTK_TREE_VIEW (ttt->view));
  if (gtk_tree_model_get_iter_first (ttt->model ,&iter)) {
    do {
      if (gtk_tree_selection_iter_is_selected (select ,&iter)) {
	gtk_tree_model_get (ttt->model, &iter ,GW_LIST_NUM_COL ,&i ,-1);
	return i;
      }
    } while (gtk_tree_model_iter_next (ttt->model ,&iter));
  }
  return (-1);
}

/**
 *  Select a row in the list
 */
void gw_list_select (Gw_list *ttt ,gint row)
{
  GtkTreeSelection *select;
  GtkTreeIter iter;
  gchar ibuf[6];

  select = gtk_tree_view_get_selection (GTK_TREE_VIEW (ttt->view));
  sprintf (ibuf ,"%5d" ,row);
  if (gtk_tree_model_get_iter_from_string (ttt->model ,&iter ,ibuf)) {
    gtk_tree_selection_select_iter (select ,&iter);
  }
}

void gw_list_select_all (Gw_list *ttt)
{
  GtkTreeSelection *select;

  select = gtk_tree_view_get_selection (GTK_TREE_VIEW (ttt->view));
  gtk_tree_selection_select_all (select);
}

void gw_list_unselect_all (Gw_list *ttt)
{
  GtkTreeSelection *select;

  select = gtk_tree_view_get_selection (GTK_TREE_VIEW (ttt->view));
  gtk_tree_selection_unselect_all (select);
}

void gw_list_inverse_selection (Gw_list *ttt)
{
  GtkTreeSelection *select;
  GtkTreeIter iter;

  select = gtk_tree_view_get_selection (GTK_TREE_VIEW (ttt->view));
  if (gtk_tree_model_get_iter_first (ttt->model ,&iter)) {
    do {
      if (gtk_tree_selection_iter_is_selected (select ,&iter)) {
	gtk_tree_selection_unselect_iter (select ,&iter);
      } else {
	gtk_tree_selection_select_iter (select ,&iter);	
      }
    } while (gtk_tree_model_iter_next (ttt->model ,&iter));
  }
}

gint gw_list_count_rows (Gw_list *ttt)
{
  GtkTreeIter iter;
  gint n = 0;

  if (gtk_tree_model_get_iter_first (ttt->model ,&iter)) {
    do {
      n++;
    } while (gtk_tree_model_iter_next (ttt->model ,&iter));
  }
  return (n);
}

gint gw_list_count_rows_selected (Gw_list *ttt)
{
  GtkTreeSelection *select;
  GtkTreeIter iter;
  gint n = 0;
 
  select = gtk_tree_view_get_selection (GTK_TREE_VIEW (ttt->view));
  if (gtk_tree_model_get_iter_first (ttt->model ,&iter)) {
    do {
      if (gtk_tree_selection_iter_is_selected (select ,&iter)) n++;
    } while (gtk_tree_model_iter_next (ttt->model ,&iter));
  }
  return (n);
}

static void (*func) (gint userdata ,gint nbsel ,gchar *buf ,gint n ,gboolean bool);
static void (*final) (GtkWidget *liste  ,gpointer puserdata);


static void gw_list_call_foreach (GtkTreeModel  *model,
				  GtkTreePath   *path,
				  GtkTreeIter   *iter,
				  gpointer      p)
{
  gchar *buf;
  gint i;
  gboolean bool;
  Gw_listData *data;
  Gw_list *liste;
  
  gtk_tree_model_get (model, iter
		      ,GW_LIST_STR_COL ,&buf
		      ,GW_LIST_NUM_COL  ,&i
		      ,GW_LIST_BOOL_COL ,&bool
		      , -1);

  data = (Gw_listData *)p;
  liste = GW_LIST(data->liste);
  func = data->func;
  func (data->userdata ,liste->nb_selected ,buf ,i ,bool);

}

static void gw_list_call (GtkWidget *button ,Gw_listData *p)
{
  GtkTreeSelection *select;
  Gw_list *liste;

  liste = GW_LIST(p->liste);

  select = gtk_tree_view_get_selection (GTK_TREE_VIEW (liste->view));
  liste->nb_selected  = gtk_tree_selection_count_selected_rows (select);
  if (p->func != NULL) {
    gtk_tree_selection_selected_foreach (GTK_TREE_SELECTION(select)
					 ,gw_list_call_foreach ,p
					 );
  }
  final =  p->final;
  final (p->liste ,GINT_TO_POINTER (p->userdata));
}

void gw_list_connect (GtkWidget *menu_item
		      ,void (*func) (gint userdata ,gint nbsel ,gchar *buf ,gint i ,gboolean bool)
		      ,void (*final) (GtkWidget *liste  ,gpointer puserdata)
		      ,GtkWidget *liste ,gint userdata
		      )
{
  Gw_listData *p;

  p = g_malloc (sizeof(Gw_listData));
  p->liste = liste;
  p->userdata = userdata;
  p->func = func;
  p->final = final;

  if (GTK_IS_BUTTON (menu_item)) {
      g_signal_connect (menu_item ,"clicked" ,G_CALLBACK (gw_list_call) ,p);
    } else {
      g_signal_connect (menu_item ,"activate" ,G_CALLBACK (gw_list_call) ,p);
    }
}
