/*
 * Copyright (c) 2004 Jean-Yves Lefort
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of Jean-Yves Lefort nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include <glib/gi18n.h>
#include "st-stream-columns-dialog.h"
#include "sg-util.h"
#include "st-settings.h"

/*** type definitions ********************************************************/

enum {
  /* invisible columns */
  COLUMN_COLUMN,

  /* visible columns */
  COLUMN_VISIBLE, COLUMN_FIELD,

  N_COLUMNS
};
    
struct _STStreamColumnsDialogPrivate
{
  GtkWidget	*view;
  STStreamView	*stream_view;
};

/*** variable declarations ***************************************************/

static GObjectClass *parent_class = NULL;

/*** function declarations ***************************************************/

static void st_stream_columns_dialog_class_init (STStreamColumnsDialogClass *class);
static void st_stream_columns_dialog_init (STStreamColumnsDialog *dialog);
static void st_stream_columns_dialog_finalize (GObject *object);

static void st_stream_columns_dialog_update (STStreamColumnsDialog *dialog);

static void st_stream_columns_dialog_unset_stream_view (STStreamColumnsDialog *dialog);

static void st_stream_columns_dialog_changed_h (GtkTreeView *view, gpointer user_data);
static void st_stream_columns_dialog_notify_visible_h (GObject *object,
						       GParamSpec *pspec,
						       gpointer data);

static void st_stream_columns_dialog_toggled_h (GtkCellRendererToggle *renderer,
						const char *path,
						gpointer user_data);
     
/*** implementation **********************************************************/

GType
st_stream_columns_dialog_get_type (void)
{
  static GType stream_columns_dialog_type = 0;
  
  if (! stream_columns_dialog_type)
    {
      static const GTypeInfo stream_columns_dialog_info = {
	sizeof(STStreamColumnsDialogClass),
	NULL,
	NULL,
	(GClassInitFunc) st_stream_columns_dialog_class_init,
	NULL,
	NULL,
	sizeof(STStreamColumnsDialog),
	0,
	(GInstanceInitFunc) st_stream_columns_dialog_init,
      };
      
      stream_columns_dialog_type = g_type_register_static(SGTK_TYPE_DIALOG,
							  "STStreamColumnsDialog",
							  &stream_columns_dialog_info,
							  0);
    }

  return stream_columns_dialog_type;
}

static void
st_stream_columns_dialog_class_init (STStreamColumnsDialogClass *class)
{
  GObjectClass *object_class = G_OBJECT_CLASS(class);

  parent_class = g_type_class_peek_parent(class);

  g_type_class_add_private(class, sizeof(STStreamColumnsDialogPrivate));

  object_class->finalize = st_stream_columns_dialog_finalize;
}

static void
st_stream_columns_dialog_init (STStreamColumnsDialog *dialog)
{
  GtkListStore *store;
  GtkWidget *scrolled;
  GtkTreeViewColumn *column;
  GtkCellRenderer *renderer;

  dialog->priv = G_TYPE_INSTANCE_GET_PRIVATE(dialog, ST_TYPE_STREAM_COLUMNS_DIALOG, STStreamColumnsDialogPrivate);

  gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
  
  gtk_window_set_title(GTK_WINDOW(dialog), _("Stream Columns"));

  store = gtk_list_store_new(N_COLUMNS,
			     GTK_TYPE_TREE_VIEW_COLUMN,
			     G_TYPE_BOOLEAN,
			     G_TYPE_STRING);
  dialog->priv->view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
  g_object_unref(store);

  gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(dialog->priv->view), FALSE);
  gtk_tree_view_set_search_column(GTK_TREE_VIEW(dialog->priv->view), COLUMN_FIELD);

  column = gtk_tree_view_column_new();
  gtk_tree_view_column_set_title(column, _("Column"));

  renderer = gtk_cell_renderer_toggle_new();
  gtk_tree_view_column_pack_start(column, renderer, FALSE);
  gtk_tree_view_column_set_attributes(column, renderer, "active", COLUMN_VISIBLE, NULL);
  g_signal_connect(renderer, "toggled", G_CALLBACK(st_stream_columns_dialog_toggled_h), dialog);
  
  renderer = gtk_cell_renderer_text_new();
  gtk_tree_view_column_pack_start(column, renderer, TRUE);
  gtk_tree_view_column_set_attributes(column, renderer, "markup", COLUMN_FIELD, NULL);

  gtk_tree_view_append_column(GTK_TREE_VIEW(dialog->priv->view), column);

  scrolled = gtk_scrolled_window_new(NULL, NULL);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
  gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);

  gtk_container_add(GTK_CONTAINER(scrolled), dialog->priv->view);
  gtk_container_add(GTK_CONTAINER(SGTK_DIALOG(dialog)->contents), scrolled);
  gtk_widget_show_all(scrolled);

  sgtk_window_link_size(GTK_WINDOW(dialog),
			&st_settings.stream_columns_window_width,
			&st_settings.stream_columns_window_height);
}

static void
st_stream_columns_dialog_finalize (GObject *object)
{
  STStreamColumnsDialog *dialog = ST_STREAM_COLUMNS_DIALOG(object);

  if (dialog->priv->stream_view)
    st_stream_columns_dialog_unset_stream_view(dialog);

  parent_class->finalize(object);
}

static void
st_stream_columns_dialog_update (STStreamColumnsDialog *dialog)
{
  GtkTreeModel *model;
  GSList *columns;
  GSList *l;

  g_return_if_fail(ST_IS_STREAM_COLUMNS_DIALOG(dialog));

  model = gtk_tree_view_get_model(GTK_TREE_VIEW(dialog->priv->view));
  gtk_list_store_clear(GTK_LIST_STORE(model));

  columns = st_stream_view_get_columns(dialog->priv->stream_view);
  SG_LIST_FOREACH(l, columns)
    {
      GtkTreeViewColumn *column = l->data;
      STHandlerField *field = st_stream_view_column_get_field(column);
      GString *markup;
      const char *description;
      GtkTreeIter iter;

      markup = g_string_new(NULL);
      sg_string_append_printf_escaped(markup, "<span weight=\"bold\">%s</span>", st_handler_field_get_label(field));

      description = st_handler_field_get_description(field);
      if (description)
	sg_string_append_printf_escaped(markup, "\n%s", description);

      gtk_list_store_append(GTK_LIST_STORE(model), &iter);
      gtk_list_store_set(GTK_LIST_STORE(model), &iter,
			 COLUMN_COLUMN, column,
			 COLUMN_VISIBLE, gtk_tree_view_column_get_visible(column),
			 COLUMN_FIELD, markup->str,
			 -1);

      g_string_free(markup, TRUE);
    }
  g_slist_free(columns);
}

GtkWidget *
st_stream_columns_dialog_new (GtkWindow *parent)
{
  STStreamColumnsDialog *dialog;

  dialog = g_object_new(ST_TYPE_STREAM_COLUMNS_DIALOG, NULL);

  if (parent)
    gtk_window_set_transient_for(GTK_WINDOW(dialog), parent);

  return GTK_WIDGET(dialog);
}

static void
st_stream_columns_dialog_unset_stream_view (STStreamColumnsDialog *dialog)
{
  GSList *columns;
  GSList *l;

  g_return_if_fail(ST_IS_STREAM_COLUMNS_DIALOG(dialog));
  g_return_if_fail(dialog->priv->stream_view != NULL);

  g_signal_handlers_disconnect_by_func(dialog->priv->stream_view,
				       st_stream_columns_dialog_changed_h,
				       dialog);

  columns = st_stream_view_get_columns(dialog->priv->stream_view);
  SG_LIST_FOREACH(l, columns)
    {
      GtkTreeViewColumn *column = l->data;
      g_signal_handlers_disconnect_by_func(column,
					   st_stream_columns_dialog_notify_visible_h,
					   dialog);
    }
  g_slist_free(columns);
}

void 
st_stream_columns_dialog_set_stream_view (STStreamColumnsDialog *dialog,
					  STStreamView *stream_view)
{
  GSList *columns;
  GSList *l;
  STHandler *handler;
  char *title;

  g_return_if_fail(ST_IS_STREAM_COLUMNS_DIALOG(dialog));
  g_return_if_fail(ST_IS_STREAM_VIEW(stream_view));

  if (dialog->priv->stream_view)
    st_stream_columns_dialog_unset_stream_view(dialog);

  dialog->priv->stream_view = stream_view;
  st_stream_columns_dialog_update(dialog);

  g_signal_connect(dialog->priv->stream_view,
		   "columns-changed",
		   G_CALLBACK(st_stream_columns_dialog_changed_h),
		   dialog);
  
  columns = st_stream_view_get_columns(dialog->priv->stream_view);
  SG_LIST_FOREACH(l, columns)
    {
      GtkTreeViewColumn *column = l->data;
      g_signal_connect(column,
		       "notify::visible",
		       G_CALLBACK(st_stream_columns_dialog_notify_visible_h),
		       dialog);
    }
  g_slist_free(columns);

  handler = st_stream_view_get_handler(dialog->priv->stream_view);
  title = g_strdup_printf(_("%s Stream Columns"), st_handler_get_label(handler));
  gtk_window_set_title(GTK_WINDOW(dialog), title);
  g_free(title);
}

static void
st_stream_columns_dialog_changed_h (GtkTreeView *view, gpointer user_data)
{
  STStreamColumnsDialog *dialog = user_data;
  st_stream_columns_dialog_update(dialog);
}

static void
st_stream_columns_dialog_notify_visible_h (GObject *object,
					   GParamSpec *pspec,
					   gpointer data)
{
  STStreamColumnsDialog *dialog = data;
  GtkTreeModel *model;
  GtkTreeIter iter;
  gboolean valid;

  model = gtk_tree_view_get_model(GTK_TREE_VIEW(dialog->priv->view));
  valid = gtk_tree_model_get_iter_first(model, &iter);

  while (valid)
    {
      GtkTreeViewColumn *column;
      gboolean found;

      gtk_tree_model_get(model, &iter, COLUMN_COLUMN, &column, -1);
      if (column == (GtkTreeViewColumn *) object)
	{
	  found = TRUE;
	  gtk_list_store_set(GTK_LIST_STORE(model), &iter,
			     COLUMN_VISIBLE, gtk_tree_view_column_get_visible(column),
			     -1);
	}
      else
	found = FALSE;
      g_object_unref(column);

      if (found)
	break;

      valid = gtk_tree_model_iter_next(model, &iter);
    }
}

static void
st_stream_columns_dialog_toggled_h (GtkCellRendererToggle *renderer,
				    const char *path,
				    gpointer user_data)
{
  STStreamColumnsDialog *dialog = user_data;
  GtkTreeModel *model;
  GtkTreeIter iter;
  gboolean status;
  GtkTreeViewColumn *column;

  model = gtk_tree_view_get_model(GTK_TREE_VIEW(dialog->priv->view));

  status = gtk_tree_model_get_iter_from_string(model, &iter, path);
  g_return_if_fail(status == TRUE);

  gtk_tree_model_get(model, &iter, COLUMN_COLUMN, &column, -1);
  gtk_tree_view_column_set_visible(column, ! gtk_tree_view_column_get_visible(column));
  g_object_unref(column);
}
