/***
 *	This file is part of Clutter-Gesture.
 *
 *	Portions Copyright 2009 (c) Intel Corp.
 *	Author: Long Bu		(long.bu@intel.com)
 *
 *	This file is modified based on test-events of Clutter/tests
 * 	Copyright (C) 2006 OpenedHand
 *
 *	Clutter-Gesture is free software; you can redistribute it and/or modify
 *	it under the terms of the GNU Lesser General Public License as published
 *	by the Free Software Foundation; either version 2.1 of the License,
 *	or (at your option) any later version.
 *
 *	Clutter-Gesture is distributed in the hope that it will be useful, but
 *	WITHOUT ANY WARRANTY; without even the implied warranty of
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 *	General Public License for more details.
 *
 *	You should have received a copy of the GNU Lesser General Public License
 *	along with ClutterGesture; if not, write to the Free Software
 *	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 *	USA.
 ***/
#include <gmodule.h>
#include <clutter/clutter.h>
#include <clutter/x11/clutter-x11.h>
#include <string.h>
#include "clutter-gesture.h"

gboolean IsFullScreen = FALSE, IsMotion = TRUE;

#if 0
static void
stage_state_cb (ClutterStage    *stage,
		gpointer         data)
{
  gchar *detail = (gchar*)data;

  printf("[stage signal] %s\n", detail);
}

static gboolean
blue_button_cb (ClutterActor    *actor,
		ClutterEvent    *event,
		gpointer         data)
{
  g_print ("blue_button_cb is called\n");

  return FALSE;
}
static gboolean
red_button_cb (ClutterActor    *actor,
		ClutterEvent    *event,
		gpointer         data)
{

  if (IsMotion)
    IsMotion = FALSE;
  else
    IsMotion = TRUE;

  clutter_set_motion_events_enabled (IsMotion);

  g_print ("*** Per actor motion events %s ***\n",
           IsMotion ? "enabled" : "disabled");

  return FALSE;
}
#endif
#if 0
static gboolean
capture_cb (ClutterActor *actor,
	    ClutterEvent *event,
	    gpointer      data)
{
  g_print ("* captured event for type '%s' *\n",
           G_OBJECT_TYPE_NAME (actor));

  return FALSE;
}
#endif
/*
static void
key_focus_in_cb (ClutterActor    *actor,
		 gpointer         data)
{
  ClutterActor *focus_box = CLUTTER_ACTOR(data);  

  if (actor == clutter_stage_get_default ())
    clutter_actor_hide (focus_box);
  else
    {
      clutter_actor_set_position (focus_box,
				  clutter_actor_get_x (actor) - 5,
				  clutter_actor_get_y (actor) - 5);

      clutter_actor_set_size (focus_box,
			      clutter_actor_get_width (actor) + 10,
			      clutter_actor_get_height (actor) + 10);
      clutter_actor_show (focus_box);
    }
}
*/

static void
fill_keybuf (char *keybuf, ClutterKeyEvent *event)
{
  char utf8[6];
  int len;

  /* printable character, if any (ß, ∑) */
  len = g_unichar_to_utf8 (event->unicode_value, utf8);
  utf8[len] = '\0';
  sprintf(keybuf, "'%s' ", utf8);

  /* key combination (<Mod1>s, <Shift><Mod1>S, <Ctrl><Mod1>Delete) */
  len = g_unichar_to_utf8 (clutter_keysym_to_unicode (event->keyval),
                           utf8);
  utf8[len] = '\0';

  if (event->modifier_state & CLUTTER_SHIFT_MASK)
    strcat (keybuf, "<Shift>");
  if (event->modifier_state & CLUTTER_LOCK_MASK)
    strcat (keybuf, "<Lock>");
  if (event->modifier_state & CLUTTER_CONTROL_MASK)
    strcat (keybuf, "<Control>");
  if (event->modifier_state & CLUTTER_MOD1_MASK)
    strcat (keybuf, "<Mod1>");
  if (event->modifier_state & CLUTTER_MOD2_MASK)
    strcat (keybuf, "<Mod2>");
  if (event->modifier_state & CLUTTER_MOD3_MASK)
    strcat (keybuf, "<Mod3>");
  if (event->modifier_state & CLUTTER_MOD4_MASK)
    strcat (keybuf, "<Mod4>");
  if (event->modifier_state & CLUTTER_MOD5_MASK)
    strcat (keybuf, "<Mod5>");
  strcat (keybuf, utf8);
}

static gboolean
gesture_cb (ClutterGesture    *gesture,
	  ClutterGestureEvent    *event,
	  gpointer         data)
{
	const char *gesture_name[] = {"dummy", 
		"SLIDE", "HOLD", "PINCH", "WINDOW", "ANY"};

	const char *slide_dir_name [] = {
		"dummy", 
		 "SLIDE_UP", "SLIDE_DOWN", "SLIDE_LEFT", "SLIDE_RIGHT"};


	printf("gesture_cb: event pointer %p\n", event);
	if (event) {
		printf("gesture_cb: event %s\n", gesture_name[event->type]);
		switch (event->type) {
			case GESTURE_SLIDE: 
				{
					ClutterGestureSlideEvent *slide = (ClutterGestureSlideEvent *)event;
					printf("slide direction :%s\n", slide_dir_name[slide->direction]);
					break;
				}
                        case GESTURE_HOLD:
                                {
                                        printf("GESTURE_HOLD is received\n");
                                        break;
                                }

                        case GESTURE_PINCH:
                                {
                                  printf("GESTURE_PINCH event is received\n");
                                  break;
                                }
                        case GESTURE_ROTATE:
                                {
                                  printf("GESTURE_ROTATE event is received\n");
                                  break;
                                }
			default:
				break;

		}
	}
	return TRUE;

}

static gboolean
input_cb (ClutterActor    *actor,
	  ClutterEvent    *event,
	  gpointer         data)
{
  ClutterStage *stage = CLUTTER_STAGE (clutter_stage_get_default ());
//  gchar keybuf[128], *source = (gchar*)data;
  gchar keybuf[128];
  gfloat x, y;

  switch (event->type)
    {
    case CLUTTER_KEY_PRESS:
      fill_keybuf (keybuf, &event->key);
//      printf ("[%s] KEY PRESS %s", source, keybuf);
      break;
    case CLUTTER_KEY_RELEASE:
      fill_keybuf (keybuf, &event->key);
//      printf ("[%s] KEY RELEASE %s", source, keybuf);
      break;
    case CLUTTER_MOTION:
//      g_print ("[%s] MOTION", source);
      break;
    case CLUTTER_ENTER:
//      g_print ("[%s] ENTER", source);
      break;
    case CLUTTER_LEAVE:
//      g_print ("[%s] LEAVE", source);
      break;
    case CLUTTER_BUTTON_PRESS:
//      g_print ("[%s] BUTTON PRESS (click count:%i)", 
//	       source, event->button.click_count);
      clutter_event_get_coords(event, &x, &y);
//      g_print("x, y is %d, %d\n", x, y);
      break;
    case CLUTTER_BUTTON_RELEASE:
//      g_print ("[%s] BUTTON RELEASE (click count:%i)", 
//	       source, event->button.click_count);

      if (clutter_event_get_source (event) == CLUTTER_ACTOR (stage))
        clutter_stage_set_key_focus (stage, NULL);
      else if (clutter_event_get_source (event) == actor
	       && clutter_actor_get_parent (actor) == CLUTTER_ACTOR (stage))
	clutter_stage_set_key_focus (stage, actor);
      break;
    case CLUTTER_SCROLL:
//      g_print ("[%s] BUTTON SCROLL (click count:%i)",
//	       source, event->button.click_count);
      break;
    case CLUTTER_STAGE_STATE:
//      g_print ("[%s] STAGE STATE", source);
      break;
    case CLUTTER_DESTROY_NOTIFY:
//      g_print ("[%s] DESTROY NOTIFY", source);
      break;
    case CLUTTER_CLIENT_MESSAGE:
//      g_print ("[%s] CLIENT MESSAGE", source);
      break;
    case CLUTTER_DELETE:
//      g_print ("[%s] DELETE", source);
      break;
    case CLUTTER_NOTHING:
      return FALSE;
    }

  if (clutter_event_get_source (event) == actor)
    {
      ;
    }
//    g_print (" *source*");
  
//  g_print ("\n");

  return FALSE;
}

int
main (int argc, char *argv[])
{
  ClutterActor    *stage, *actor, *actor1, *group;
  ClutterColor    rcol = { 0xff, 0, 0, 0xff}, 
                  bcol = { 0, 0, 0xff, 0xff },
		  gcol = { 0, 0xff, 0, 0xff };
		  /* ycol = { 0xff, 0xff, 0, 0xff }; */
		  /*ncol = { 0, 0, 0, 0xff }; */
  ClutterGesture *gesture = NULL;

  g_type_init();

  clutter_x11_enable_xinput();

  clutter_init (&argc, &argv);

//  clutter_set_motion_events_frequency(120);

  stage = clutter_stage_get_default ();
  clutter_stage_set_throttle_motion_events(CLUTTER_STAGE(stage), FALSE);
  clutter_set_default_frame_rate(60);
//  g_signal_connect (stage, "event", G_CALLBACK (input_cb), "stage");
#if 0
  g_signal_connect (stage, "fullscreen", 
		    G_CALLBACK (stage_state_cb), "fullscreen");
  g_signal_connect (stage, "unfullscreen", 
		    G_CALLBACK (stage_state_cb), "unfullscreen");
  g_signal_connect (stage, "activate", 
		    G_CALLBACK (stage_state_cb), "activate");
  g_signal_connect (stage, "deactivate", 
		    G_CALLBACK (stage_state_cb), "deactivate");
#endif
  group = clutter_group_new ();
  clutter_container_add (CLUTTER_CONTAINER (stage), group, NULL);
//  clutter_actor_set_position (group, 100, 350);
//  g_signal_connect (stage, "captured-event", G_CALLBACK (capture_cb), NULL);

//  focus_box = clutter_rectangle_new_with_color (&ncol);
//  clutter_container_add (CLUTTER_CONTAINER(stage), focus_box, NULL);
    actor = clutter_rectangle_new_with_color (&rcol);
  clutter_actor_set_size (actor, 200, 200);
  clutter_actor_set_position (actor, 100, 100);

  clutter_actor_set_reactive (actor, TRUE);

  clutter_container_add (CLUTTER_CONTAINER (group), actor, NULL);

  g_signal_connect (actor, "event", G_CALLBACK (input_cb), "red box");
  /* g_signal_connect (actor, "focus-in", G_CALLBACK (key_focus_in_cb), 
		    focus_box);	*/

    clutter_stage_set_key_focus (CLUTTER_STAGE (stage), actor);

  /* g_signal_connect (actor, "focus-in", G_CALLBACK (key_focus_in_cb), 
		    focus_box);	*/

  actor1 = clutter_rectangle_new_with_color (&gcol);
  clutter_actor_set_size (actor1, 50, 50);
  clutter_actor_set_position (actor1, 300, 300);
  //clutter_actor_set_depth (actor1, 10);

  clutter_actor_set_reactive (actor1, TRUE);

  clutter_container_add (CLUTTER_CONTAINER (group), actor1, NULL);
  clutter_actor_set_reactive (group, TRUE);

//  g_signal_connect (group, "event", G_CALLBACK (input_cb), "group");

  clutter_actor_show(actor1);

  actor = clutter_rectangle_new_with_color (&bcol);
  clutter_actor_set_size (actor, 50, 50);
  clutter_actor_set_position (actor, 400, 400);

  clutter_actor_set_reactive (actor, TRUE);

  clutter_container_add (CLUTTER_CONTAINER(stage), actor, NULL);

  g_signal_connect (actor, "event", G_CALLBACK (input_cb), "blue box");
  /* g_signal_connect (actor, "focus-in", G_CALLBACK (key_focus_in_cb), 
		    focus_box);	*/
#if 0
  /* non reactive */
  actor = clutter_rectangle_new_with_color (&ncol);
  clutter_actor_set_size (actor, 400, 50);
  clutter_actor_set_position (actor, 100, 250);

  clutter_container_add (CLUTTER_CONTAINER(stage), actor, NULL);

  g_signal_connect (actor, "event", G_CALLBACK (input_cb), "blue box");
  /* g_signal_connect (actor, "focus-in", G_CALLBACK (key_focus_in_cb), 
		    focus_box);
  g_signal_connect (stage, "focus-in", G_CALLBACK (key_focus_in_cb), 
		    focus_box);
	*/
  /* non reactive group, with reactive child */
  actor = clutter_rectangle_new_with_color (&ycol);
  clutter_actor_set_size (actor, 100, 100);
  clutter_actor_set_reactive (actor, TRUE);

  g_signal_connect (actor, "event", G_CALLBACK (input_cb), "yellow box");
#endif
  /* note group not reactive */
  clutter_actor_show_all (group);
  clutter_actor_show_all (CLUTTER_ACTOR (stage));

  gesture = clutter_gesture_new(CLUTTER_ACTOR(stage));
  clutter_gesture_set_gesture_mask(gesture, group, GESTURE_MASK_SLIDE | GESTURE_MASK_HOLD);
  g_signal_connect (gesture, "gesture-slide-event", G_CALLBACK (gesture_cb), (gpointer)0x11223344);
  g_signal_connect (gesture, "gesture-hold-event", G_CALLBACK (gesture_cb), (gpointer)0x11223344);

  clutter_main();

  return 0;
}
