/*
 * JSDX Framework
 *
 * Copyright(c) 2012 Fred Chien <fred@mandice.com>
 *
 */

#include <v8.h>
#include <node.h>
#include <ev.h>
#include <stdlib.h>
#include <clutter/clutter.h>
#include <clutter/x11/clutter-x11.h>

#include "jsdx_toolkit.hpp"

#include "actor.hpp"
#include "container.hpp"
#include "group.hpp"
#include "stage.hpp"
#include "rectangle.hpp"
#include "text.hpp"
#include "texture.hpp"
#include "state.hpp"
#include "media.hpp"
#include "application.hpp"
#include "window.hpp"

#if ENABLE_CLUTTER_GST
#include "gst/gst.hpp"
#include "gst/video-texture.hpp"
#endif

#if ENABLE_WIDGET
#include "widgets/widget.hpp"
//#include "widgets/FlickView.hpp"
#endif

namespace JSDXToolkit {
 
	using namespace node;
	using namespace v8;

	static Handle<Value> ClutterInit(const Arguments& args)
	{
		HandleScope scope;

		return scope.Close(Integer::New(clutter_init(NULL, NULL)));
	}

	static Handle<Value> ClutterMain(const Arguments& args)
	{
		HandleScope scope;

		return Undefined();
	}

	static Handle<Value> SetUseARGBVisual(const Arguments& args)
	{
		if (args[0]->IsBoolean()) {
			clutter_x11_set_use_argb_visual(args[0]->ToBoolean()->Value());
		}

		return Undefined();
	}

	static Handle<Value> ClutterMainQuit(const Arguments& args)
	{
		return Undefined();
	}
	 
	extern "C" {
		static void init(Handle<Object> target)
		{
			HandleScope scope;

			/* Error conditions for initializing*/
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "INIT_SUCCESS", CLUTTER_INIT_SUCCESS);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "INIT_UNKNOWN", CLUTTER_INIT_ERROR_UNKNOWN);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "INIT_THREADS", CLUTTER_INIT_ERROR_THREADS);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "INIT_BACKEND", CLUTTER_INIT_ERROR_BACKEND);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "INIT_INTERNAL", CLUTTER_INIT_ERROR_INTERNAL);

			/* ClutterGravity */
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "GRAVITY_NONE", CLUTTER_GRAVITY_NONE);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "GRAVITY_NORTH", CLUTTER_GRAVITY_NORTH);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "GRAVITY_NORTH_EAST", CLUTTER_GRAVITY_NORTH_EAST);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "GRAVITY_EAST", CLUTTER_GRAVITY_EAST);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "GRAVITY_SOUTH_EAST", CLUTTER_GRAVITY_SOUTH_EAST);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "GRAVITY_SOUTH", CLUTTER_GRAVITY_SOUTH);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "GRAVITY_SOUTH_WEST", CLUTTER_GRAVITY_SOUTH_WEST);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "GRAVITY_CENTER", CLUTTER_GRAVITY_CENTER);

			/* ClutterRotateAxis */
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "X_AXIS", CLUTTER_X_AXIS);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "Y_AXIS", CLUTTER_Y_AXIS);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "Z_AXIS", CLUTTER_Z_AXIS);

			/* ClutterRotateDirection */
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "ROTATE_CW", CLUTTER_ROTATE_CW);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "ROTATE_CCW", CLUTTER_ROTATE_CCW);

			/* ClutterAlpha */
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "CUSTOM_MODE", CLUTTER_CUSTOM_MODE);

			/* linear */
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "LINEAR", CLUTTER_LINEAR);

			/* quadratic */
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_IN_QUAD", CLUTTER_EASE_IN_QUAD);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_OUT_QUAD", CLUTTER_EASE_OUT_QUAD);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_IN_OUT_QUAD", CLUTTER_EASE_IN_OUT_QUAD);

			/* cubic */
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_IN_CUBIC", CLUTTER_EASE_IN_CUBIC);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_OUT_CUBIC", CLUTTER_EASE_OUT_CUBIC);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_IN_OUT_CUBIC", CLUTTER_EASE_IN_OUT_CUBIC);

			/* quartic */
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_IN_QUART", CLUTTER_EASE_IN_QUART);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_OUT_QUART", CLUTTER_EASE_OUT_QUART);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_IN_OUT_QUART", CLUTTER_EASE_IN_OUT_QUART);

			/* quintic */
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_IN_QUINT", CLUTTER_EASE_IN_QUINT);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_OUT_QUINT", CLUTTER_EASE_OUT_QUINT);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_IN_OUT_QUINT", CLUTTER_EASE_IN_OUT_QUINT);

			/* sinusoidal */
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_IN_SINE", CLUTTER_EASE_IN_SINE);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_OUT_SINE", CLUTTER_EASE_OUT_SINE);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_IN_OUT_SINE", CLUTTER_EASE_IN_OUT_SINE);

			/* exponential */
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_IN_EXPO", CLUTTER_EASE_IN_EXPO);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_OUT_EXPO", CLUTTER_EASE_OUT_EXPO);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_IN_OUT_EXPO", CLUTTER_EASE_IN_OUT_EXPO);

			/* circular */
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_IN_CIRC", CLUTTER_EASE_IN_CIRC);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_OUT_CIRC", CLUTTER_EASE_OUT_CIRC);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_IN_OUT_CIRC", CLUTTER_EASE_IN_OUT_CIRC);

			/* elastic */
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_IN_ELASTIC", CLUTTER_EASE_IN_ELASTIC);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_OUT_ELASTIC", CLUTTER_EASE_OUT_ELASTIC);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_IN_OUT_ELASTIC", CLUTTER_EASE_IN_OUT_ELASTIC);

			/* overshooting cubic */
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_IN_BACK", CLUTTER_EASE_IN_BACK);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_OUT_BACK", CLUTTER_EASE_OUT_BACK);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_IN_OUT_BACK", CLUTTER_EASE_IN_OUT_BACK);

			/* exponentially decaying parabolic */
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_IN_BOUNCE", CLUTTER_EASE_IN_BOUNCE);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_OUT_BOUNCE", CLUTTER_EASE_OUT_BOUNCE);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EASE_IN_OUT_BOUNCE", CLUTTER_EASE_IN_OUT_BOUNCE);

			/* Effect */
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EFFECT_CUSTOM", JSDX_TOOLKIT_EFFECT_CUSTOM);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EFFECT_BLUR", JSDX_TOOLKIT_EFFECT_BLUR);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EFFECT_COLORIZE", JSDX_TOOLKIT_EFFECT_COLORIZE);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EFFECT_DESATURATE", JSDX_TOOLKIT_EFFECT_DESATURATE);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EFFECT_PAGE_TURN", JSDX_TOOLKIT_EFFECT_PAGE_TURN);

			/* own events */
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EVENT_DESTROY", JSDX_TOOLKIT_EVENT_DESTROY);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EVENT_SHOW", JSDX_TOOLKIT_EVENT_SHOW);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EVENT_HIDE", JSDX_TOOLKIT_EVENT_HIDE);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EVENT_PRESS", JSDX_TOOLKIT_EVENT_PRESS);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EVENT_RELEASE", JSDX_TOOLKIT_EVENT_RELEASE);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EVENT_KEY_PRESS", JSDX_TOOLKIT_EVENT_KEY_PRESS);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EVENT_KEY_RELEASE", JSDX_TOOLKIT_EVENT_KEY_RELEASE);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EVENT_CLICK", JSDX_TOOLKIT_EVENT_CLICK);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EVENT_LONG_PRESS", JSDX_TOOLKIT_EVENT_LONG_PRESS);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EVENT_ENTER", JSDX_TOOLKIT_EVENT_ENTER);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EVENT_LEAVE", JSDX_TOOLKIT_EVENT_LEAVE);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EVENT_MOTION", JSDX_TOOLKIT_EVENT_MOTION);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EVENT_DRAG", JSDX_TOOLKIT_EVENT_DRAG);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "EVENT_SCROLL", JSDX_TOOLKIT_EVENT_SCROLL);

			/* Scroll direction */
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "SCROLL_DIRECTION_UP", JSDX_TOOLKIT_SCROLL_UP);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "SCROLL_DIRECTION_DOWN", JSDX_TOOLKIT_SCROLL_DOWN);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "SCROLL_DIRECTION_LEFT", JSDX_TOOLKIT_SCROLL_LEFT);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "SCROLL_DIRECTION_RIGHT", JSDX_TOOLKIT_SCROLL_RIGHT);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "SCROLL_DIRECTION_SMOOTH", JSDX_TOOLKIT_SCROLL_SMOOTH);

			/* Action state */
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "ACTION_STATE_LONG_PRESS_QUERY", CLUTTER_LONG_PRESS_QUERY);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "ACTION_STATE_LONG_PRESS_ACTIVATE", CLUTTER_LONG_PRESS_ACTIVATE);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "ACTION_STATE_LONG_PRESS_CANCEL", CLUTTER_LONG_PRESS_CANCEL);

			/* Animation */
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "ANIMATION_PLAY", JSDX_TOOLKIT_ANIMATION_PLAY);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "ANIMATION_PAUSE", JSDX_TOOLKIT_ANIMATION_PAUSE);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "ANIMATION_STOP", JSDX_TOOLKIT_ANIMATION_STOP);

			/* Window Type */
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "WINDOW_TYPE_NORMAL", JSDX_WINDOW_TYPE_NORMAL);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "WINDOW_TYPE_DESKTOP", JSDX_WINDOW_TYPE_DESKTOP);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "WINDOW_TYPE_DOCK", JSDX_WINDOW_TYPE_DOCK);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "WINDOW_TYPE_TOOLBAR", JSDX_WINDOW_TYPE_TOOLBAR);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "WINDOW_TYPE_MENU", JSDX_WINDOW_TYPE_MENU);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "WINDOW_TYPE_UTILITY", JSDX_WINDOW_TYPE_UTILITY);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "WINDOW_TYPE_SPLASH", JSDX_WINDOW_TYPE_SPLASH);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "WINDOW_TYPE_DIALOG", JSDX_WINDOW_TYPE_DIALOG);
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "WINDOW_TYPE_POPUP_MENU", JSDX_WINDOW_TYPE_POPUP_MENU);

			/* Texture Type */
			JSDX_TOOLKIT_DEFINE_CONSTANT(target, "TEXTURE_X11", JSDX_TOOLKIT_TEXTURE_X11);

			NODE_SET_METHOD(target, "init", ClutterInit);
			NODE_SET_METHOD(target, "_main", ClutterMain);
			NODE_SET_METHOD(target, "_quit", ClutterMainQuit);
			NODE_SET_METHOD(target, "useARGB", SetUseARGBVisual);

			/* Application */
			Application::Initialize(target);
			JSDXWindow::Initialize(target);

			Actor::Initialize(target);
			Container::Initialize(target);
			Group::Initialize(target);
			Stage::Initialize(target);
			Rectangle::Initialize(target);
			Text::Initialize(target);
			Texture::Initialize(target);
			State::Initialize(target);

#if ENABLE_CLUTTER_GST
			Gst::Initialize(target);
			GstVideoTexture::Initialize(target);
#endif

#if ENABLE_WIDGET
			Widget::Initialize(target);
//			FlickView::Initialize(target);
#endif
		}

		NODE_MODULE(jsdx_toolkit, init);
	}

}
