/* test-canvas.c
 *
 * Unit tests for the DiaCanvas class.
 *
 * Arjan
 */

#include "unit-test.h"
#include <diacanvas/dia-canvas.h>
#include <diacanvas/dia-canvas-group.h>

static DiaCanvas *canvas;

void
test_dia_canvas_setup (void)
{
	canvas = dia_canvas_new ();
	TEST (canvas != NULL);
	TEST (DIA_IS_CANVAS (canvas));
}

void
test_dia_canvas_teardown (void)
{
	if (canvas)
		g_object_unref (canvas);
	canvas = NULL;
}


TEST_BEGIN (DiaCanvas, test_dia_canvas_setup, test_dia_canvas_teardown)

TEST_NEW (initial_state)
{
	TEST (canvas->root != NULL);
	TEST (DIA_IS_CANVAS_ITEM (canvas->root));
	TEST (DIA_IS_CANVAS_GROUP (canvas->root));

	TEST (canvas->extents.left == 0.0);
	TEST (canvas->extents.right == 0.0);
	TEST (canvas->extents.top == 0.0);
	TEST (canvas->extents.bottom == 0.0);
	TEST (canvas->static_extents == FALSE);
	TEST (canvas->snap_to_grid == FALSE);

	TEST (canvas->interval_x == 10.0);
	TEST (canvas->interval_y == 10.0);
	TEST (canvas->offset_x == 0.0);
	TEST (canvas->offset_y == 0.0);
	TEST (canvas->grid_color == DIA_COLOR (0,0,128));
	TEST (canvas->grid_bg == DIA_COLOR (255, 255, 255));

	TEST (canvas->solver != NULL)
	TEST (DIA_IS_SOLVER (canvas->solver));

	TEST (canvas->idle_id == 0);

	TEST (canvas->allow_undo == FALSE);
	TEST (canvas->in_undo == FALSE);
	TEST (canvas->stack_depth == 10);
	TEST (canvas->undo == NULL);
	TEST (canvas->redo == NULL);
}

TEST_NEW (set_property)
{
	DiaRectangle r = { 1.0, 2.0, 3.0, 4.0 };

	g_object_set (canvas, "snap_to_grid", TRUE, NULL);
	g_message ("snap_to_grid = %x", canvas->snap_to_grid);
	TEST (canvas->snap_to_grid);
	g_object_set (canvas, "snap_to_grid", FALSE, NULL);
	TEST (!canvas->snap_to_grid);

	g_object_set (canvas, "static_extents", TRUE, NULL);
	TEST (canvas->static_extents);
	g_object_set (canvas, "static_extents", FALSE, NULL);
	TEST (!canvas->static_extents);

	g_object_set (canvas, "extents", &r, NULL);
	TEST (canvas->extents.left == 1.0);
	TEST (canvas->extents.right == 3.0);
	TEST (canvas->extents.top == 2.0);
	TEST (canvas->extents.bottom == 4.0);

	TEST (canvas->interval_x == 10.0);
	g_object_set (canvas, "grid_int_x", 5.0, NULL);
	TEST (canvas->interval_x == 5.0);

	TEST (canvas->interval_y == 10.0);
	g_object_set (canvas, "grid_int_y", 5.0, NULL);
	TEST (canvas->interval_y == 5.0);

	TEST (canvas->offset_x == 0.0);
	g_object_set (canvas, "grid_ofs_x", 5.0, NULL);
	TEST (canvas->offset_x == 5.0);

	TEST (canvas->offset_y == 0.0);
	g_object_set (canvas, "grid_ofs_y", 5.0, NULL);
	TEST (canvas->offset_y == 5.0);

	TEST (canvas->grid_color == DIA_COLOR (0,0,128));
	g_object_set (canvas, "grid_color", DIA_COLOR (255, 0, 255), NULL);
	TEST (canvas->grid_color == DIA_COLOR (255, 0, 255));

	TEST (canvas->grid_bg == DIA_COLOR (255, 255, 255));
	g_object_set (canvas, "grid_bg", DIA_COLOR (255, 0, 255), NULL);
	TEST (canvas->grid_bg == DIA_COLOR (255, 0, 255));

	TEST (!canvas->allow_undo);
	g_object_set (canvas, "allow_undo", TRUE, NULL);
	TEST (canvas->allow_undo);
	g_object_set (canvas, "allow_undo", FALSE, NULL);
	TEST (!canvas->allow_undo);
}

TEST_NEW (set_property_notifiers)
{
	gboolean n = 0;
	DiaRectangle r = { 1.0, 2.0, 3.0, 4.0 };

	int n_specs = 0, i;
	GParamSpec **specs = g_object_class_list_properties(G_OBJECT_GET_CLASS(canvas), &n_specs);
	TEST(n_specs != 0);
	for (i = 0; i < n_specs; i++) {
		g_message ("spec %d: %s [%d]", i, specs[i]->name, specs[i]->flags);
	}

	TEST_PROPERTY_NOTIFY (canvas, "snap-to-grid", n);
	TEST_PROPERTY_NOTIFY (canvas, "static-extents", n);
	TEST_PROPERTY_NOTIFY (canvas, "extents", n);
	TEST_PROPERTY_NOTIFY (canvas, "grid-int-x", n);
	TEST_PROPERTY_NOTIFY (canvas, "grid-int-y", n);
	TEST_PROPERTY_NOTIFY (canvas, "grid-ofs-x", n);
	TEST_PROPERTY_NOTIFY (canvas, "grid-ofs-y", n);
	TEST_PROPERTY_NOTIFY (canvas, "grid-color", n);
	TEST_PROPERTY_NOTIFY (canvas, "grid-bg", n);
	TEST_PROPERTY_NOTIFY (canvas, "allow-undo", n);

	g_object_set (canvas, "extents", &r, NULL);
	TEST (n == TRUE);

	n = FALSE;
	g_object_set (canvas, "snap-to-grid", TRUE, NULL);
	TEST (n == TRUE);

	n = FALSE;
	g_object_set (canvas, "static-extents", TRUE, NULL);
	TEST (n == TRUE);

	n = FALSE;
	g_object_set (canvas, "grid_int_x", 5.0, NULL);
	TEST (n == TRUE);

	n = FALSE;
	g_object_set (canvas, "grid_int_y", 5.0, NULL);
	TEST (n == TRUE);

	n = FALSE;
	g_object_set (canvas, "grid_ofs_y", 5.0, NULL);
	TEST (n == TRUE);

	n = FALSE;
	g_object_set (canvas, "grid_ofs_y", 5.0, NULL);
	TEST (n == TRUE);

	n = FALSE;
	g_object_set (canvas, "grid_color", 0, NULL);
	TEST (n == TRUE);

	n = FALSE;
	g_object_set (canvas, "grid_bg", 0, NULL);
	TEST (n == TRUE);

	n = FALSE;
	g_object_set (canvas, "allow_undo", TRUE, NULL);
	TEST (n == TRUE);
}

TEST_NEW (request_update)
{
	TEST (canvas->idle_id == 0);
	dia_canvas_request_update (canvas);
	TEST (canvas->idle_id != 0);

	TEST_EMPTY_QUEUE();
	TEST (canvas->idle_id == 0);
}

TEST_NEW (update_now)
{
	TEST (canvas->idle_id == 0);
	dia_canvas_request_update (canvas);
	TEST (canvas->idle_id != 0);

	dia_canvas_update_now (canvas);
	TEST (canvas->idle_id == 0);
}

TEST_NEW (resolve_now)
{
}

TEST_NEW (set_extents)
{
	DiaRectangle r = { 1.0, 2.0, 3.0, 4.0 };

	dia_canvas_set_extents (canvas, &r);
	TEST (canvas->extents.left == 1.0);
	TEST (canvas->extents.top == 2.0);
	TEST (canvas->extents.right == 3.0);
	TEST (canvas->extents.bottom == 4.0);

	r.left = 5.0;
	r.right = 6.0;
	r.top = 7.0;
	r.bottom = 8.0;

	dia_canvas_set_extents (canvas, &r);
	TEST (canvas->extents.left == 5.0);
	TEST (canvas->extents.right == 6.0);
	TEST (canvas->extents.top == 7.0);
	TEST (canvas->extents.bottom == 8.0);
}

TEST_NEW (set_static_extents)
{
	DiaRectangle r = { 1.0, 2.0, 3.0, 4.0 };

	TEST (!canvas->static_extents);
	dia_canvas_set_static_extents (canvas, TRUE);
	TEST (canvas->static_extents);
	
	dia_canvas_set_extents (canvas, &r);
	TEST (canvas->extents.left == 1.0);
	TEST (canvas->extents.right == 3.0);
	TEST (canvas->extents.top == 2.0);
	TEST (canvas->extents.bottom == 4.0);

	dia_canvas_request_update (canvas);
	dia_canvas_update_now (canvas);
	TEST (canvas->extents.left == 1.0);
	TEST (canvas->extents.right == 3.0);
	TEST (canvas->extents.top == 2.0);
	TEST (canvas->extents.bottom == 4.0);

	dia_canvas_set_static_extents (canvas, FALSE);
	TEST (canvas->static_extents == FALSE);

	dia_canvas_request_update (canvas);
	dia_canvas_update_now (canvas);
	TEST (canvas->extents.left == 0.0);
	TEST (canvas->extents.right == 0.0);
	TEST (canvas->extents.top == 0.0);
	TEST (canvas->extents.bottom == 0.0);
}

TEST_NEW ((set_)snap_to_grid)
{
	DiaPoint p = { 2.0, 7.0 };

	dia_canvas_snap_to_grid (canvas, &p.x, &p.y);
	TESTFL (p.x, 2.0);
	TESTFL (p.y, 7.0);

	dia_canvas_set_snap_to_grid (canvas, TRUE);
	dia_canvas_snap_to_grid (canvas, &p.x, &p.y);
	TESTFL (p.x, 0.0);
	TESTFL (p.y, 10.0);

	g_object_set (canvas, "grid_ofs_x", 2.0, "grid_ofs_y", 3.0, NULL);
	dia_canvas_snap_to_grid (canvas, &p.x, &p.y);
	TESTFL (p.x, 2.0);
	TESTFL (p.y, 13.0);
}

TEST_NEW (glue_handle)
{
	g_message ("Test this using the demo app.");
}

TEST_NEW (find_objects_in_rectangle)
{
	DiaRectangle r = { -10000.0, -10000.0, 10000.0, 10000.0 };
	GList *objs;
	DiaCanvasItem *group;

	objs = dia_canvas_find_objects_in_rectangle (canvas, &r);

	TEST (g_list_length (objs) == 0);

	group = dia_canvas_group_create_item (DIA_CANVAS_GROUP (canvas->root),
					      DIA_TYPE_CANVAS_GROUP, NULL);

	objs = dia_canvas_find_objects_in_rectangle (canvas, &r);
	TEST (g_list_length (objs) == 1);
	TEST (objs->data == (gpointer) group);

	g_list_free (objs);
}

TEST_NEW (dia_canvas_add/remove_constraint)
{
	DiaVariable *v;
	DiaConstraint *c;
	
	v = dia_variable_new ();
	c = dia_constraint_new ();
	dia_constraint_add (c, v, 1.0);

	TEST (canvas->solver->constraints == NULL);
	dia_canvas_add_constraint (canvas, c);
	TEST (g_list_length (canvas->solver->constraints) == 1);

	dia_canvas_remove_constraint (canvas, c);
	TEST (canvas->solver->constraints == NULL);

	g_object_unref (v);
	g_object_unref (c);
}

TEST_NEW (undo/redo)
{
	g_message ("Test undo/redo functionality through the demo app.");
}

#define DEPTH 10
TEST_NEW (ref_counting)
{
	DiaCanvasItem *item;
	DiaCanvasGroup *group;
	gboolean notifier[DEPTH];
	gint i;

	group = DIA_CANVAS_GROUP (canvas->root);
	for (i = 0; i < DEPTH; i++) {
		item = dia_canvas_group_create_item (group, DIA_TYPE_CANVAS_GROUP, NULL);
		notifier[i] = FALSE;
		TEST_WEAK_REF (item, notifier[i]);
		group = DIA_CANVAS_GROUP (item);
	}

	g_object_unref (canvas);
	canvas = NULL;

	for (i = 0; i < DEPTH; i++) {
		TEST (notifier[i] == TRUE);
	}
}
#undef DEPTH

TEST_NEW (canvas_destruction)
{
	DiaCanvasItem *item;
	gint idle_id;
	gboolean notifier[3] = {0, 0, 0};

	item = dia_canvas_group_create_item (DIA_CANVAS_GROUP (canvas->root),
					     DIA_TYPE_CANVAS_GROUP, NULL);
	TEST (canvas->idle_id != 0);
	TEST (item->parent == canvas->root);
	TEST (G_OBJECT (item)->ref_count == 1);
	g_object_ref (item);
	TEST (G_OBJECT (item)->ref_count == 2);
	TEST_WEAK_REF (canvas, notifier[0]);
	TEST_WEAK_REF (canvas->root, notifier[1]);
	TEST_WEAK_REF (item, notifier[2]);

	idle_id = canvas->idle_id;

	g_object_unref (canvas);
	canvas = NULL;
	TEST (G_OBJECT(item)->ref_count == 1);
	TEST (notifier[0] == TRUE);
	TEST (notifier[1] == TRUE);
	TEST (notifier[2] == FALSE);
	TEST (item->canvas == NULL);
	TEST (item->parent == NULL);
	/* idle_id should have been removed. */
	TEST (!g_source_remove (idle_id));

	g_object_unref (item);
	TEST (notifier[2] == TRUE);
}

TEST_END ();
