/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 * E-Table-Group.c: Implements the grouping objects for elements on a table
 *
 * Author:
 *   Miguel de Icaza (miguel@gnu.org()
 *
 * Copyright 1999, Helix Code, Inc.
 */

#include <config.h>
#include <gtk/gtksignal.h>
#include "e-table-group.h"
#include "e-table-group-container.h"
#include "e-table-group-leaf.h"
#include "e-table-item.h"
#include <libgnomeui/gnome-canvas-rect-ellipse.h>
#include <gnome-xml/parser.h>
#include "e-util/e-util.h"
#include "e-util/e-xml-utils.h"

#define TITLE_HEIGHT         16
#define GROUP_INDENT         10

#define PARENT_TYPE gnome_canvas_group_get_type ()

#define ETG_CLASS(e) (E_TABLE_GROUP_CLASS(GTK_OBJECT(e)->klass))

static GnomeCanvasGroupClass *etg_parent_class;

enum {
	RESIZE,
	LAST_SIGNAL
};

static gint etg_signals [LAST_SIGNAL] = { 0, };

/* The arguments we take */
enum {
	ARG_0,
	ARG_HEIGHT,
	ARG_WIDTH,
	ARG_FROZEN
};

static void etg_set_arg (GtkObject *object, GtkArg *arg, guint arg_id);
static void etg_get_arg (GtkObject *object, GtkArg *arg, guint arg_id);
static gboolean etg_get_focus (ETableGroup      *etg);
static void etg_destroy (GtkObject *object);
#if 0
GnomeCanvasItem *
e_table_group_new (GnomeCanvasGroup *parent, ETableCol *ecol, 
		   gboolean open, gboolean transparent)
{
	ETableGroup *etg;

	g_return_val_if_fail (parent != NULL, NULL);
	g_return_val_if_fail (ecol != NULL, NULL);
	
	etg = gtk_type_new (e_table_group_get_type ());

	e_table_group_construct (parent, etg, ecol, open, transparent);

	return GNOME_CANVAS_ITEM (etg);
}
#endif

static void
etg_destroy (GtkObject *object)
{
	ETableGroup *etg = E_TABLE_GROUP(object);
	if ( etg->header )
		gtk_object_unref(GTK_OBJECT(etg->header));
	if ( etg->full_header )
		gtk_object_unref(GTK_OBJECT(etg->full_header));
	if ( etg->model )
		gtk_object_unref(GTK_OBJECT(etg->model));
	if ( GTK_OBJECT_CLASS (etg_parent_class)->destroy )
		GTK_OBJECT_CLASS (etg_parent_class)->destroy (object);
}

ETableGroup *
e_table_group_new (GnomeCanvasGroup *parent,
		   ETableHeader     *full_header,
		   ETableHeader     *header,
		   ETableModel      *model,
		   xmlNode          *rules)
{
	int column;
	int ascending;

	g_return_val_if_fail (model != NULL, NULL);

	column = e_xml_get_integer_prop_by_name(rules, "column");
	ascending = e_xml_get_integer_prop_by_name(rules, "ascending");

	if(rules && !xmlStrcmp(rules->name, "group")) {
		ETableCol *col;
		if ( column > e_table_header_count(full_header) )
			return e_table_group_leaf_new(parent, full_header, header, model, column, ascending);
		col = e_table_header_get_columns(full_header)[column];
		return e_table_group_container_new(parent, full_header, header, model, col, ascending, rules->childs);
	} else {
		return e_table_group_leaf_new(parent, full_header, header, model, column, ascending);
	}
	return NULL;
}

void
e_table_group_construct (GnomeCanvasGroup *parent,
			 ETableGroup      *etg,
			 ETableHeader     *full_header,
			 ETableHeader     *header,
			 ETableModel      *model)
{
	etg->full_header = full_header;
	gtk_object_ref(GTK_OBJECT(etg->full_header));
	etg->header = header;
	gtk_object_ref(GTK_OBJECT(etg->header));
	etg->model = model;
	gtk_object_ref(GTK_OBJECT(etg->model));
	gnome_canvas_item_constructv (GNOME_CANVAS_ITEM (etg), parent, 0, NULL);
}

void
e_table_group_add (ETableGroup *etg,
		   gint row)
{
	g_return_if_fail (etg != NULL);
	g_return_if_fail (E_IS_TABLE_GROUP (etg));

	if ( ETG_CLASS (etg)->add )
		ETG_CLASS (etg)->add (etg, row);
}

gboolean
e_table_group_remove (ETableGroup *etg,
		      gint row)
{
	g_return_val_if_fail (etg != NULL, FALSE);
	g_return_val_if_fail (E_IS_TABLE_GROUP (etg), FALSE);

	if ( ETG_CLASS (etg)->remove )
		return ETG_CLASS (etg)->remove (etg, row);
	else
		return FALSE;
}

gint
e_table_group_get_count (ETableGroup *etg)
{
	g_return_val_if_fail (etg != NULL, 0);
	g_return_val_if_fail (E_IS_TABLE_GROUP (etg), 0);

	if ( ETG_CLASS (etg)->get_count )
		return ETG_CLASS (etg)->get_count (etg);
	else
		return 0;
}

void
e_table_group_increment (ETableGroup *etg,
			 gint position,
			 gint amount)
{
	g_return_if_fail (etg != NULL);
	g_return_if_fail (E_IS_TABLE_GROUP (etg));

	if ( ETG_CLASS (etg)->increment )
		ETG_CLASS (etg)->increment (etg, position, amount);
}

void
e_table_group_set_focus (ETableGroup *etg,
			 EFocus direction,
			 gint row)
{
	g_return_if_fail (etg != NULL);
	g_return_if_fail (E_IS_TABLE_GROUP (etg));

	if ( ETG_CLASS (etg)->set_focus )
		ETG_CLASS (etg)->set_focus (etg, direction, row);
}

gboolean
e_table_group_get_focus (ETableGroup *etg)
{
	g_return_val_if_fail (etg != NULL, FALSE);
	g_return_val_if_fail (E_IS_TABLE_GROUP (etg), FALSE);

	if ( ETG_CLASS (etg)->get_focus )
		return ETG_CLASS (etg)->get_focus (etg);
	else
		return FALSE;
}

gboolean
e_table_group_get_focus_column (ETableGroup *etg)
{
	g_return_val_if_fail (etg != NULL, FALSE);
	g_return_val_if_fail (E_IS_TABLE_GROUP (etg), FALSE);

	if ( ETG_CLASS (etg)->get_focus_column )
		return ETG_CLASS (etg)->get_focus_column (etg);
	else
		return FALSE;
}

ETableCol *
e_table_group_get_ecol (ETableGroup *etg)
{
	g_return_val_if_fail (etg != NULL, NULL);
	g_return_val_if_fail (E_IS_TABLE_GROUP (etg), NULL);

	if ( ETG_CLASS (etg)->get_ecol )
		return ETG_CLASS (etg)->get_ecol (etg);
	else
		return NULL;
}

void
e_table_group_resize (ETableGroup *e_table_group)
{
	g_return_if_fail (e_table_group != NULL);
	g_return_if_fail (E_IS_TABLE_GROUP (e_table_group));

	gtk_signal_emit (GTK_OBJECT (e_table_group),
			 etg_signals [RESIZE]);
}

ETableHeader *
e_table_group_get_header (ETableGroup *etg)
{
	g_return_val_if_fail (etg != NULL, NULL);
	g_return_val_if_fail (E_IS_TABLE_GROUP (etg), NULL);

	return etg->header;
}

static int
etg_event (GnomeCanvasItem *item, GdkEvent *event)
{
	ETableGroup *etg = E_TABLE_GROUP (item);
	gboolean return_val = TRUE;

	switch (event->type) {

	case GDK_FOCUS_CHANGE:
		etg->has_focus = event->focus_change.in;
		return_val = FALSE;

	default:
		return_val = FALSE;
	}
	if ( return_val == FALSE ) {
		if ( GNOME_CANVAS_ITEM_CLASS(etg_parent_class)->event )
			return GNOME_CANVAS_ITEM_CLASS(etg_parent_class)->event(item, event);
	}
	return return_val;

}

static void
etg_thaw(ETableGroup *etg)
{
	g_return_if_fail (etg != NULL);
	g_return_if_fail (E_IS_TABLE_GROUP (etg));

	if ( ETG_CLASS (etg)->thaw )
		ETG_CLASS (etg)->thaw (etg);
}

static void
etg_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
{
	ETableGroup *etg = E_TABLE_GROUP (object);

	switch (arg_id) {
	case ARG_FROZEN:
		if ( GTK_VALUE_BOOL (*arg) )
			etg->frozen = TRUE;
		else {
			etg->frozen = FALSE;
			etg_thaw(etg);
		}
		break;
	case ARG_WIDTH:
		if ( ETG_CLASS(etg)->set_width )
			ETG_CLASS(etg)->set_width(etg, GTK_VALUE_DOUBLE (*arg));
		break;
	default:
		break;
	}
}

static void
etg_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
{
	ETableGroup *etg = E_TABLE_GROUP (object);

	switch (arg_id) {
	case ARG_FROZEN:
		GTK_VALUE_BOOL (*arg) = etg->frozen;
		break;
	case ARG_HEIGHT:
		if ( ETG_CLASS(etg)->get_height )
			GTK_VALUE_DOUBLE (*arg) = ETG_CLASS(etg)->get_height(etg);
		else
			arg->type = GTK_TYPE_INVALID;
		break;
	case ARG_WIDTH:
		if ( ETG_CLASS(etg)->get_width )
			GTK_VALUE_DOUBLE (*arg) = ETG_CLASS(etg)->get_width(etg);
		else
			arg->type = GTK_TYPE_INVALID;
		break;
	default:
		arg->type = GTK_TYPE_INVALID;
		break;
	}
}

static gboolean
etg_get_focus (ETableGroup      *etg)
{
	return etg->has_focus;
}

static void
etg_class_init (GtkObjectClass *object_class)
{
	GnomeCanvasItemClass *item_class = (GnomeCanvasItemClass *) object_class;
	ETableGroupClass *klass = (ETableGroupClass *) object_class;
	
	object_class->set_arg = etg_set_arg;
	object_class->get_arg = etg_get_arg;
	object_class->destroy = etg_destroy;

	item_class->event = etg_event;

	klass->resize = NULL;
	
	klass->add = NULL;
	klass->remove = NULL;
	klass->get_count = NULL;
	klass->increment = NULL;
	klass->set_focus = NULL;
	klass->get_focus = etg_get_focus;
	klass->get_ecol = NULL;

	klass->thaw = NULL;
	klass->get_height = NULL;
	klass->get_width = NULL;
	klass->set_width = NULL;
	
	etg_parent_class = gtk_type_class (PARENT_TYPE);

	etg_signals [RESIZE] =
		gtk_signal_new ("resize",
				GTK_RUN_LAST,
				object_class->type,
				GTK_SIGNAL_OFFSET (ETableGroupClass, resize),
				gtk_marshal_NONE__NONE,
				GTK_TYPE_NONE, 0);
	
	gtk_object_class_add_signals (object_class, etg_signals, LAST_SIGNAL);
}

E_MAKE_TYPE (e_table_group, "ETableGroup", ETableGroup, etg_class_init, NULL, PARENT_TYPE);