/*
 * Canvas item for testing purposes.
 */

#include <diacanvas/dia-canvas.h>
#include <diacanvas/dia-shape.h>
#include <diacanvas/dia-canvas-groupable.h>

typedef struct _TestItem TestItem;
typedef struct _TestItemClass TestItemClass;

struct _TestItem
{
	DiaCanvasItem item;

	GList *children;

	DiaShape *shape;

	gboolean did_update;
	gboolean did_get_shape_iter;
	gboolean did_shape_next;
	gboolean did_shape_value;
	gboolean did_point;
	gboolean did_move;
	gboolean did_handle_motion;
	gboolean did_glue;
	gboolean did_event;
	gboolean did_connect;
	gboolean did_disconnect;
	gboolean did_need_update;
	gboolean did_z_order;
	gboolean did_groupable_add;
	gboolean did_groupable_remove;
	gboolean did_groupable_get_iter;
	gboolean did_groupable_next;
	gboolean did_groupable_value;
	gboolean did_groupable_length;
	gboolean did_groupable_pos;
};

struct _TestItemClass
{
	DiaCanvasItemClass item_class;
};

#define TYPE_TEST_ITEM (test_item_get_type())
#define TEST_ITEM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_TEST_ITEM, TestItem))

GType test_item_get_type (void);

void test_item_clean (TestItem *test_item);


/***** Implementation of TestItem *****/

static void	test_item_init			(TestItem *canvas_group);
static void	test_item_class_init		(TestItemClass *klass);
static void	test_item_groupable_init	(DiaCanvasGroupableIface *groupable);
static void	test_item_dispose		(GObject *object);
static void	test_item_update		(DiaCanvasItem *item,
						 gdouble affine[6]);
static gboolean	test_item_get_shape_iter	 (DiaCanvasItem *item,
						 DiaCanvasIter *iter);
static gboolean	test_item_shape_next		(DiaCanvasItem *item,
						 DiaCanvasIter *iter);
static DiaShape* test_item_shape_value		(DiaCanvasItem *item,
						 DiaCanvasIter *iter);
static gdouble	test_item_point			(DiaCanvasItem *item,
						 gdouble x, gdouble y);
static void	test_item_move			(DiaCanvasItem *item,
						 gdouble dx, gdouble dy,
						 gboolean interactive);
static void	test_item_handle_motion		(DiaCanvasItem *item,
						 DiaHandle *handle,
						 gdouble *wx, gdouble *wy,
						 DiaEventMask mask);
static gdouble	test_item_glue			(DiaCanvasItem *item,
						 DiaHandle *handle,
						 gdouble *wx, gdouble *wy);
static gboolean	test_item_event			(DiaCanvasItem *item,
						 DiaEvent *event);
static gboolean	test_item_connect		(DiaCanvasItem *item,
						 DiaHandle *handle);
static gboolean	test_item_disconnect		(DiaCanvasItem *item,
						 DiaHandle *handle);
static void	test_item_need_update		(DiaCanvasItem *item);
static void	test_item_z_order		(DiaCanvasItem *item,
						 gint positions);

/* Interface functions: */
static gboolean test_item_groupable_add		(DiaCanvasGroupable *group,
						 DiaCanvasItem *item);
static gboolean test_item_groupable_remove	(DiaCanvasGroupable *group,
						 DiaCanvasItem *item);
static gboolean test_item_groupable_get_iter	(DiaCanvasGroupable *group,
						 DiaCanvasIter *iter);
static gboolean test_item_groupable_next	(DiaCanvasGroupable *group,
						 DiaCanvasIter *iter);
static DiaCanvasItem* test_item_groupable_value	(DiaCanvasGroupable *group,
						 DiaCanvasIter *iter);
static gint test_item_groupable_length		(DiaCanvasGroupable *group);
static gint test_item_groupable_pos		(DiaCanvasGroupable *group,
						 DiaCanvasItem *item);

static DiaCanvasItemClass *parent_class = NULL;

GType
test_item_get_type (void)
{
	static GType object_type = 0;

	if (!object_type) {
		static const GTypeInfo object_info = {
			sizeof (TestItemClass),
			(GBaseInitFunc) NULL,
			(GBaseFinalizeFunc) NULL,
			(GClassInitFunc) test_item_class_init,
			(GClassFinalizeFunc) NULL,
			(gconstpointer) NULL, /* class_data */
			sizeof (TestItem),
			(guint16) 0, /* n_preallocs */
			(GInstanceInitFunc) test_item_init,
		};
		static const GInterfaceInfo groupable_info = {
			(GInterfaceInitFunc) test_item_groupable_init,
			NULL,
			NULL,
		};
		object_type = g_type_register_static (DIA_TYPE_CANVAS_ITEM,
						      "TestItem",
						      &object_info, 0);
		g_type_add_interface_static (object_type,
					     DIA_TYPE_CANVAS_GROUPABLE,
					     &groupable_info);
	}

	return object_type;
}

void
test_item_clean (TestItem *test_item)
{
	if (test_item->shape) {
		dia_shape_free (test_item->shape);
		test_item->shape = NULL;
	}
	test_item->did_update = FALSE;
	test_item->did_get_shape_iter = FALSE;
	test_item->did_shape_next = FALSE;
	test_item->did_shape_value = FALSE;
	test_item->did_point = FALSE;
	test_item->did_move = FALSE;
	test_item->did_handle_motion = FALSE;
	test_item->did_glue = FALSE;
	test_item->did_event = FALSE;
	test_item->did_connect = FALSE;
	test_item->did_disconnect = FALSE;
	test_item->did_need_update = FALSE;
	test_item->did_z_order = FALSE;
	test_item->did_groupable_add = FALSE;
	test_item->did_groupable_remove = FALSE;
	test_item->did_groupable_get_iter = FALSE;
	test_item->did_groupable_next = FALSE;
	test_item->did_groupable_value = FALSE;
	test_item->did_groupable_length = FALSE;
	test_item->did_groupable_pos = FALSE;
}

static void
test_item_class_init (TestItemClass *klass)
{
	GObjectClass *object_class;
	DiaCanvasItemClass *item_class;
 
	object_class = G_OBJECT_CLASS (klass);
	item_class = DIA_CANVAS_ITEM_CLASS (klass);

	parent_class = g_type_class_peek_parent (klass);

	object_class->dispose = test_item_dispose;
	item_class->update = test_item_update;
	item_class->get_shape_iter = test_item_get_shape_iter;
	item_class->shape_next = test_item_shape_next;
	item_class->shape_value = test_item_shape_value;
	item_class->point = test_item_point;
	item_class->move = test_item_move;
	item_class->handle_motion = test_item_handle_motion;
	item_class->glue = test_item_glue;
	item_class->event = test_item_event;
	item_class->connect = test_item_connect;
	item_class->disconnect = test_item_disconnect;
	item_class->need_update = test_item_need_update;
	item_class->z_order = test_item_z_order;
}

static void
test_item_groupable_init (DiaCanvasGroupableIface *groupable)
{
	groupable->add = test_item_groupable_add;
	groupable->remove = test_item_groupable_remove;
	groupable->get_iter = test_item_groupable_get_iter;
	groupable->next = test_item_groupable_next;
	groupable->value = test_item_groupable_value;
	groupable->length = test_item_groupable_length;
	groupable->pos = test_item_groupable_pos;
}

static void
test_item_init (TestItem *test_item)
{
	test_item->children = NULL;
	test_item_clean (test_item);
}

static void
test_item_dispose (GObject *object)
{
	TestItem *test_item = TEST_ITEM (object);
	while (test_item->children)
		dia_canvas_groupable_remove (DIA_CANVAS_GROUPABLE (object),
					     test_item->children->data);

	G_OBJECT_CLASS (parent_class)->dispose (object);
}

static void
test_item_update (DiaCanvasItem *item, gdouble affine[6])
{
	if (parent_class->update)
		parent_class->update (item, affine);

	TEST_ITEM (item)->did_update = TRUE;
}

static gboolean
test_item_get_shape_iter (DiaCanvasItem *item, DiaCanvasIter *iter)
{
	if (parent_class->get_shape_iter)
		parent_class->get_shape_iter (item, iter);

	TEST_ITEM (item)->did_get_shape_iter = TRUE;
	if (TEST_ITEM (item)->shape)
		return TRUE;

	return FALSE;
}

static gboolean
test_item_shape_next (DiaCanvasItem *item, DiaCanvasIter *iter)
{
	if (parent_class->shape_next)
		parent_class->shape_next (item, iter);

	TEST_ITEM (item)->did_shape_next = TRUE;
	return FALSE;
}

static DiaShape*
test_item_shape_value (DiaCanvasItem *item, DiaCanvasIter *iter)
{
	if (parent_class->shape_value)
		parent_class->shape_value (item, iter);

	TEST_ITEM (item)->did_shape_value = TRUE;
	return TEST_ITEM (item)->shape;
}

static gdouble
test_item_point (DiaCanvasItem *item, gdouble x, gdouble y)
{
	if (parent_class->point)
		parent_class->point (item, x, y);

	TEST_ITEM (item)->did_point = TRUE;

	return  0.0;
}

static void
test_item_move (DiaCanvasItem *item, gdouble dx, gdouble dy, gboolean in)
{
	if (parent_class->move)
		parent_class->move (item, dx, dy, in);

	TEST_ITEM (item)->did_move = TRUE;
}

static void
test_item_handle_motion (DiaCanvasItem *item, DiaHandle *handle, gdouble *wx, gdouble *wy, DiaEventMask mask)
{
	if (parent_class->handle_motion)
		parent_class->handle_motion (item, handle, wx, wy, mask);

	TEST_ITEM (item)->did_handle_motion = TRUE;
}

static gdouble
test_item_glue (DiaCanvasItem *item, DiaHandle *handle, gdouble *wx, gdouble *wy)
{
	if (parent_class->glue)
		parent_class->glue (item, handle, wx, wy);

	TEST_ITEM (item)->did_glue = TRUE;
	return 0.0;
}

static gboolean
test_item_event (DiaCanvasItem *item, DiaEvent *event)
{
	if (parent_class->event)
		parent_class->event (item, event);

	TEST_ITEM (item)->did_event = TRUE;
	return TRUE;
}

static gboolean
test_item_connect (DiaCanvasItem *item, DiaHandle *handle)
{
	if (parent_class->connect)
		parent_class->connect (item, handle);

	TEST_ITEM (item)->did_connect = TRUE;
	return FALSE;
}

static gboolean
test_item_disconnect (DiaCanvasItem *item, DiaHandle *handle)
{
	if (parent_class->disconnect)
		parent_class->disconnect (item, handle);

	TEST_ITEM (item)->did_disconnect = TRUE;
	return FALSE;
}

static void
test_item_need_update (DiaCanvasItem *item)
{
	if (parent_class->need_update)
		parent_class->need_update (item);

	TEST_ITEM (item)->did_need_update = TRUE;
}

static void
test_item_z_order (DiaCanvasItem *item, gint positions)
{
	if (parent_class->z_order)
		parent_class->z_order (item, positions);

	TEST_ITEM (item)->did_z_order = TRUE;
}


/*
 * Groupable
 */

static gboolean
test_item_groupable_add (DiaCanvasGroupable *group, DiaCanvasItem *item)
{
	TEST_ITEM (group)->children = g_list_append (TEST_ITEM (group)->children, item);
	g_object_ref (item);
	dia_canvas_item_set_child_of (item, DIA_CANVAS_ITEM (group));

	TEST_ITEM (group)->did_groupable_add = TRUE;

	return TRUE;
}

static gboolean
test_item_groupable_remove (DiaCanvasGroupable *group, DiaCanvasItem *item)
{
	TEST_ITEM (group)->children = g_list_remove (TEST_ITEM (group)->children, item);
	g_object_unref (item);
	TEST_ITEM (group)->did_groupable_remove = TRUE;

	return TRUE;
}

static gboolean
test_item_groupable_get_iter (DiaCanvasGroupable *group, DiaCanvasIter *iter)
{
	iter->data[0] = TEST_ITEM (group)->children;

	TEST_ITEM (group)->did_groupable_get_iter = TRUE;

	return iter->data[0] ? TRUE : FALSE;
}

static gboolean
test_item_groupable_next (DiaCanvasGroupable *group, DiaCanvasIter *iter)
{
	if (iter->data[0])
		iter->data[0] = ((GList*) iter->data[0])->next;

	TEST_ITEM (group)->did_groupable_next = TRUE;

	return iter->data[0] ? TRUE : FALSE;
}

static DiaCanvasItem*
test_item_groupable_value (DiaCanvasGroupable *group, DiaCanvasIter *iter)
{
	TEST_ITEM (group)->did_groupable_value = TRUE;

	return iter->data[0] ? ((GList*) iter->data[0])->data : NULL;
}

static gint
test_item_groupable_length (DiaCanvasGroupable *group)
{
	TEST_ITEM (group)->did_groupable_length = TRUE;

	return g_list_length (TEST_ITEM (group)->children);
}

static gint
test_item_groupable_pos (DiaCanvasGroupable *group, DiaCanvasItem *item)
{
	TEST_ITEM (group)->did_groupable_pos = TRUE;

	return g_list_index (TEST_ITEM (group)->children, item);
}

