#include <clutter/clutter.h>
#include <stdio.h>
#include <stdlib.h>

static ClutterActor *main_stage, *rect, *p[5];

static void
init_handles ()
{
  gint              i;
  ClutterVertex    v[4];
  ClutterVertex    v1, v2;
  ClutterColor blue = { 0, 0, 0xff, 0xff };

  clutter_actor_get_vertices (rect, v);
  for (i = 0; i < 4; ++i)
    {
      p[i] = clutter_rectangle_new_with_color (&blue);
      clutter_actor_set_size (p[i], 5, 5);
      clutter_actor_set_position (p[i], 0, 0);
      clutter_group_add (CLUTTER_GROUP (main_stage), p[i]);

      clutter_actor_set_position (p[i],
				  CLUTTER_FIXED_INT (v[i].x) -
				  clutter_actor_get_width (p[i])/2,
				  CLUTTER_FIXED_INT (v[i].y) -
				  clutter_actor_get_height (p[i])/2);

      clutter_actor_raise_top (p[i]);

      clutter_actor_show (p[i]);
    }

  v1.x = CLUTTER_INT_TO_FIXED (clutter_actor_get_width (rect)/2);
  v1.y = CLUTTER_INT_TO_FIXED (clutter_actor_get_height (rect)/2);
  v1.z = 0;
  
  clutter_actor_apply_transform_to_point (rect, &v1, &v2);
  p[4] = clutter_rectangle_new_with_color (&blue);
  clutter_actor_set_size (p[4], 5, 5);
  clutter_actor_set_position (p[4], 0, 0);
  clutter_group_add (CLUTTER_GROUP (main_stage), p[4]);
  clutter_actor_set_position (p[4],
			      CLUTTER_FIXED_INT (v2.x) -
			      clutter_actor_get_width (p[4])/2,
			      CLUTTER_FIXED_INT (v2.y) -
			      clutter_actor_get_height (p[4])/2);

  clutter_actor_raise_top (p[4]);
  
  clutter_actor_show (p[4]);
}

static void
place_handles ()
{
  gint              i;
  ClutterVertex    v[4];
  ClutterVertex    v1, v2;

  clutter_actor_get_vertices (rect, v);
  for (i = 0; i < 4; ++i)
    {
      clutter_actor_set_position (p[i],
				  CLUTTER_FIXED_INT (v[i].x) -
				  clutter_actor_get_width (p[i])/2,
				  CLUTTER_FIXED_INT (v[i].y) -
				  clutter_actor_get_height (p[i])/2);
    }

  v1.x = CLUTTER_INT_TO_FIXED (clutter_actor_get_width (rect)/2);
  v1.y = CLUTTER_INT_TO_FIXED (clutter_actor_get_height (rect)/2);
  v1.z = 0;
  
  clutter_actor_apply_transform_to_point (rect, &v1, &v2);
  clutter_actor_set_position (p[4],
			      CLUTTER_FIXED_INT (v2.x) -
			      clutter_actor_get_width (p[4])/2,
			      CLUTTER_FIXED_INT (v2.y) -
			      clutter_actor_get_height (p[4])/2);
}

#define M(m,row,col)  (m)[col*4+row]

static gint
find_handle_index (ClutterActor * a)
{
    gint i;
    for (i = 0; i < sizeof(p)/sizeof(p[0]); ++i)
	if (p[i] == a)
	    return i;

    return -1;
}


void 
on_event (ClutterStage *stage,
	  ClutterEvent *event,
	  gpointer      user_data)
{
  static ClutterActor * dragging = NULL;
  
  switch (event->type)
    {
    case CLUTTER_BUTTON_PRESS:
      {
	gint x, y;
	ClutterActor * actor;

        clutter_event_get_coords (event, &x, &y);

	actor = clutter_stage_get_actor_at_pos (stage, x, y);
	
        if (actor != CLUTTER_ACTOR (stage))
	  {
	    if (actor != rect)
	      dragging = actor;
	  }
      }
      break;

    case CLUTTER_MOTION:
      {
	if (dragging)
	  {
	    gint x, y;
	    gint i;
	    ClutterActorBox box1, box2;
	    ClutterFixed xp, yp;
	    
	    i = find_handle_index (dragging);

	    if (i < 0)
	      break;
	    
	    clutter_event_get_coords (event, &x, &y);
	    
	    clutter_actor_query_coords (dragging, &box1);
	    clutter_actor_query_coords (rect, &box2);

	    xp = CLUTTER_INT_TO_FIXED (x-3) - box1.x1;
	    yp = CLUTTER_INT_TO_FIXED (y-3) - box1.y1;
	    
	    if (i == 4)
	      {
		g_debug ("moving box by %f, %f",
			 CLUTTER_FIXED_TO_FLOAT (xp),
			 CLUTTER_FIXED_TO_FLOAT (yp));
			 
		clutter_actor_move_by (rect,
				       CLUTTER_FIXED_INT(xp),
				       CLUTTER_FIXED_INT(yp));
	      }
	    else
	      {
		g_debug ("adjusting box by %f, %f, handle %d",
			 CLUTTER_FIXED_TO_FLOAT (xp),
			 CLUTTER_FIXED_TO_FLOAT (yp),
			 i);
		switch (i)
		  {
		  case 0:
		    box2.x1 += xp;
		    box2.y1 += yp;
		    break;
		  case 1:
		    box2.x2 += xp;
		    box2.y1 += yp;
		    break;
		  case 2:
		    box2.x1 += xp;
		    box2.y2 += yp;
		    break;
		  case 3:
		    box2.x2 += xp;
		    box2.y2 += yp;
		    break;
		  }

		clutter_actor_request_coords (rect, &box2);
	      }
	    
 	    place_handles ();
	  }
      }
      break;
      
    case CLUTTER_BUTTON_RELEASE:
      {
	dragging = NULL;
      }
      break;
      
    default:
      break;
    }
}


int
main (int argc, char *argv[])
{
  ClutterActor *label;
  
  ClutterColor      stage_color = { 0x0, 0x0, 0x0, 0xff }, 
	            white       = { 0xff, 0xff, 0xff, 0xff };

  clutter_init (&argc, &argv);

  main_stage = clutter_stage_get_default ();

  clutter_stage_set_color (CLUTTER_STAGE (main_stage), &stage_color);
  clutter_actor_set_size (main_stage, 640, 480);

  rect = clutter_rectangle_new_with_color (&white);
  clutter_actor_set_size (rect, 320, 240);
  clutter_actor_set_position (rect, 180, 120);
  clutter_actor_set_rotation (rect, CLUTTER_Y_AXIS, 60, 0, 0, 0);
  clutter_group_add (CLUTTER_GROUP (main_stage), rect);

  label = clutter_label_new_with_text ("Mono 8pt", "Drag the blue rectangles");
  clutter_label_set_color (CLUTTER_LABEL (label), &white);
  
  clutter_actor_set_position (label, 10, 10);
  clutter_group_add (CLUTTER_GROUP (main_stage), label);
  
  clutter_actor_show_all (main_stage);
  
  g_signal_connect (main_stage, "event", G_CALLBACK (on_event), NULL);

  init_handles ();
  
  clutter_main();

  return EXIT_SUCCESS;
}