/*
 * DiaClock
 *
 * This is LGPL'ed code.
 */

#include "dia-clock.h"
#include <diacanvas/dia-shape.h>
#include <diacanvas/dia-canvas-i18n.h>
#include <libart_lgpl/art_affine.h>
#include <stdlib.h>
#include <math.h>

static void dia_clock_class_init	(DiaClockClass *klass);
static void dia_clock_init		(DiaClock *item);
static void dia_clock_set_property	(GObject *object,
					 guint property_id,
					 const GValue *value,
					 GParamSpec *pspec);
static void dia_clock_get_property	(GObject *object,
					 guint property_id,
					 GValue *value,
					 GParamSpec *pspec);
static void dia_clock_dispose		(GObject *object);
static void dia_clock_update		(DiaCanvasItem *item,
					 gdouble affine[6]);
static gboolean dia_clock_event		(DiaCanvasItem *item,
					 DiaEvent *event);
static gboolean dia_clock_get_shape_iter (DiaCanvasItem *item,
					  DiaCanvasIter *iter);
static gboolean dia_clock_shape_next	(DiaCanvasItem *item,
					 DiaCanvasIter *iter);
static DiaShape* dia_clock_shape_value	(DiaCanvasItem *item,
					 DiaCanvasIter *iter);
static gdouble dia_clock_glue (DiaCanvasItem *item, DiaHandle *handle,
			       gdouble *x, gdouble *y);
static gboolean dia_clock_connect (DiaCanvasItem *item, DiaHandle *handle);

static DiaCanvasElementClass *parent_class = NULL;

gboolean
clock_update (gpointer data)
{
	DiaClock *clock = data;
	time_t t;
	struct tm *lt;
	glong sec;

	time (&t);
	lt = localtime (&t);
	sec = ((lt->tm_hour * 60) + lt->tm_min) * 60 + lt->tm_sec;

	if (sec != clock->sec) {
		clock->sec = sec;
		dia_canvas_item_request_update (DIA_CANVAS_ITEM (clock));
	}

	return TRUE; /* keep the timeout function. */
}

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

	if (!object_type) {
		static const GTypeInfo object_info = {
			sizeof (DiaClockClass),
			(GBaseInitFunc) NULL,
			(GBaseFinalizeFunc) NULL,
			(GClassInitFunc) dia_clock_class_init,
			(GClassFinalizeFunc) NULL,
			(gconstpointer) NULL, /* class_data */
			sizeof (DiaClock),
			(guint16) 0, /* n_preallocs */
			(GInstanceInitFunc) dia_clock_init,
		};

		object_type = g_type_register_static (DIA_TYPE_CANVAS_ELEMENT,
						      "DiaClock",
						      &object_info, 0);
	}

	return object_type;
}


static void
dia_clock_class_init (DiaClockClass *klass)
{
	GObjectClass *object_class;
	DiaCanvasItemClass *item_class;
	
	object_class = (GObjectClass*) klass;
	item_class = DIA_CANVAS_ITEM_CLASS (klass);
	
	parent_class = g_type_class_peek_parent (klass);

	object_class->dispose = dia_clock_dispose;
	object_class->get_property = dia_clock_get_property;
	object_class->set_property = dia_clock_set_property;
	
	item_class->update = dia_clock_update;
	item_class->event = dia_clock_event;
	item_class->get_shape_iter = dia_clock_get_shape_iter;
	item_class->shape_next = dia_clock_shape_next;
	item_class->shape_value = dia_clock_shape_value;
	item_class->glue = dia_clock_glue;
	item_class->connect = dia_clock_connect;
}


static void
dia_clock_init (DiaClock *item)
{
	item->sec = 0;
	item->timer = g_timeout_add (200, clock_update, item);

	item->circle = dia_shape_new (DIA_SHAPE_ELLIPSE);
	item->hours = dia_shape_new (DIA_SHAPE_PATH);
	item->minutes = dia_shape_new (DIA_SHAPE_PATH);
	item->seconds = dia_shape_new (DIA_SHAPE_PATH);
}


static void
dia_clock_set_property (GObject *object, guint property_id,
			     const GValue *value, GParamSpec *pspec)
{
	switch (property_id) {
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}

static void
dia_clock_get_property (GObject *object, guint property_id,
			     GValue *value, GParamSpec *pspec)
{
	switch (property_id) {
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}

static void
dia_clock_dispose (GObject *object)
{
	DiaClock *clock = (DiaClock*) object;

	g_message (__FUNCTION__);
	if (clock->timer) {
		g_source_remove (clock->timer);
		clock->timer = 0;
	}

	if (clock->circle) {
		dia_shape_free (clock->circle);
		clock->circle = NULL;
		dia_shape_free (clock->hours);
		clock->hours = NULL;
		dia_shape_free (clock->minutes);
		clock->minutes = NULL;
		dia_shape_free (clock->seconds);
		clock->seconds = NULL;
	}
	G_OBJECT_CLASS (parent_class)->dispose (object);
}


static void
dia_clock_update (DiaCanvasItem *item, gdouble affine[6])
{
	DiaClock *clock = (DiaClock*) item;
	DiaShape *circle, *hours, *minutes, *seconds;
	DiaPoint center, p;
	gdouble t, r;

        if (DIA_CANVAS_ITEM_CLASS (parent_class)->update)
		DIA_CANVAS_ITEM_CLASS (parent_class)->update (item, affine);
	
	circle = clock->circle;
	hours = clock->hours;
	minutes = clock->minutes;
	seconds = clock->seconds;

	center.x = clock->item.width / 2;
	center.y = clock->item.height / 2;
	r = MIN (clock->item.width, clock->item.height) / 2;

	dia_shape_ellipse (circle, &center, r + r, r + r);
	dia_shape_set_color (circle, DIA_COLOR(20,20,20));
	dia_shape_ellipse_set_fill (circle, DIA_FILL_SOLID);
	dia_shape_ellipse_set_fill_color (circle, DIA_COLOR_A (40, 0, 0, 60));
	dia_shape_ellipse_set_line_width (circle, 2.0);

	t = clock->sec * M_PI / 21600.0; /* 3600 * 6 */
	p.x = sin (t) * r * 0.7 + center.x;
	p.y = -cos (t) * r * 0.7 + center.y;
	dia_shape_line (hours, &center, &p);
	dia_shape_path_set_line_width (hours, 4.0);
	dia_shape_request_update (hours);
	
	t = clock->sec * M_PI / 1800.0;
	p.x = sin (t) * r * 0.85 + center.x;
	p.y = -cos (t) * r * 0.85 + center.y;
	dia_shape_line (minutes, &center, &p);
	dia_shape_path_set_line_width (minutes, 2.0);
	dia_shape_request_update (minutes);
	
	t = clock->sec * M_PI / 30.0;
	p.x = sin (t) * r * 0.9 + center.x;
	p.y = -cos (t) * r * 0.9 + center.y;
	dia_shape_line (seconds, &center, &p);
	dia_shape_path_set_line_width (seconds, 1.0);
	dia_shape_set_color (seconds, DIA_COLOR (200, 50,50));
	dia_shape_request_update (seconds);
}

static gboolean
dia_clock_event (DiaCanvasItem *item, DiaEvent *event)
{
	gboolean retval = FALSE;

        if (DIA_CANVAS_ITEM_CLASS (parent_class)->event)
		retval = DIA_CANVAS_ITEM_CLASS (parent_class)->event (item, event);
	
	switch (event->type) {
	case DIA_EVENT_FOCUS_IN:
		g_message("*** FOCUS IN ***");
		retval = TRUE;
		break;
	case DIA_EVENT_FOCUS_OUT:
		g_message("*** FOCUS OUT ***");
		retval = TRUE;
		break;
	default:
		break;
	}
	return retval;
}

static gboolean
dia_clock_get_shape_iter (DiaCanvasItem *item, DiaCanvasIter *iter)
{
	iter->data[0] = DIA_CLOCK (item)->circle;
		return TRUE;
}

static gboolean
dia_clock_shape_next (DiaCanvasItem *item, DiaCanvasIter *iter)
{
	DiaClock *c = (DiaClock*) item;

	if (iter->data[0] == c->circle)
		iter->data[0] = c->hours;
	else if (iter->data[0] == c->hours)
		iter->data[0] = c->minutes;
	else if (iter->data[0] == c->minutes)
		iter->data[0] = c->seconds;
	else
		iter->data[0] = NULL;

	return (iter->data[0] != NULL ? TRUE : FALSE);
}

static DiaShape*
dia_clock_shape_value (DiaCanvasItem *item, DiaCanvasIter *iter)
{
	return iter->data[0];
}

static gdouble
dia_clock_glue (DiaCanvasItem *item, DiaHandle *handle, gdouble *x, gdouble *y)
{
	return G_MAXDOUBLE;
}

static gboolean
dia_clock_connect (DiaCanvasItem *item, DiaHandle *handle)
{
	return FALSE;
}


