/* -----------------------------------------------------------------------------
	GSFramework
	Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */


#ifndef	__NUI_SCENE__
#define	__NUI_SCENE__


		#include "ui/ui_item.h"
		#include "ui/ui_cursor.h"
		#include "ui/ui_message.h"
		#include "ui/ui_event_handler.h"
		#include "ui/ui_window_skin.h"
		#include "ui/ui_scene_event_interface.h"
		#include "scene3d/scene_io_flag.h"
		#include "motion/scene_motion_container.h"
		#include "core/tool_mode.h"
		#include "core/clock.h"
		#include "core/ace.h"
		#include "color/color.h"


namespace GS {
	namespace GPU { class TriangleBatch; }
	namespace Render { class RasterFont; }
	namespace S2D {
		struct Group;
		struct Camera;
		class Window;
		class Widget;

/*!
	@short	Scene 2D
	@author	Emmanuel Julien (ejulien@nworks.fr)
*/
class	Scene : public SharedObject, public ACE::Unit
{
		uint			current_item_uid;

protected:

		SharedList <Item *> item_list;
		Item			*lock;

		Matrix3			screen_to_ui, ui_to_screen;

		SharedPtr <Camera> default_camera, current_camera;

		Widget			*RecurseWidgetBelowCursor(Window *, Widget *, int x, int y);
		void			ProcessCursorEnterLeaveWidget(Cursor *, Window *, Widget *);

		/// Execute an ACE command.
		bool			ExecCommand(ACE::Command *, float dt);

		Core::sClock	clock;

public:

		String			name;

		void			SetClock(Core::Clock * = 0);

/*!
	@name	Script system.
	@{
*/
		Script::sVM	vm;

		AutoPtr <ISceneEvent> scene_event;
		AutoPtr <Script::ScriptedObject> scripted_object;

		void			SetAsScriptGlobalScene(Script::IVM * = 0);
/*!
	@}
	@name	Item list.
	@{
*/
		const SharedList <Item *> &GetItemList() const { return item_list; }

		/// Get item 2d from name.
		Item			*ItemFromName(const char *name, Item *parent = 0) const;
		/// Get item 2d from unique identifier.
		Item			*ItemFromUid(uint) const;

		void			SetupItemComponents(Item *);

		void			AddItem(Item *, bool setup_components);
		bool			RemoveItem(Item *);

		void			DeleteAllItems();
/*!
	@}
	@name	Motion system.
	@{
*/
		Core::SceneMotionContainer motion;

		/*!
			@short	Start a motion on the scene items.
			@note	Request an animation source group if you need control on the
					started animation sources.
		*/
		void			SetMotion(const char *name, Automation::SourceGroup ** = 0, float blend = Units::Sec(0.1), Automation::Player::AddSourceMode = Automation::Player::SourceSet, float weight = 1);
///	@}

		Camera			*GetDefaultCamera() const { return default_camera; }

		Camera			*GetCurrentCamera() const { return current_camera; }
		void			SetCurrentCamera(Camera *camera = 0);

		/// Lock all UI events to a specific item.
		void			Lock(Item *i) { lock = i; }
		void			Unlock() { lock = 0; }

		void			UpdateCursor(Cursor *);

		/// Call event handler.
		bool			CallEventHandler(Cursor *, EventCode, EventTable *);
		void			CallEventHandler(Cursor *, Widget *, EventCode, bool can_propagate = true);

		void			DrawProfilerText(Renderer &, Render::RasterFont *font[2], float &x, float &y);

		sWindowSkin		window_skin;

		Matrix3			offset_matrix;			///< Global post-projection offset matrix.
		Color			global_fade_color;

		/// Normalized screen coordinates to scene coordinates in pixels.
		const Matrix3	&GetScreenToUIMatrix() const { return screen_to_ui; }
		/// Scene coordinates in pixels to normalized screen coordinates.
		const Matrix3	&GetUIToScreenMatrix() const { return ui_to_screen; }

		float			GetGlobalFadeEffect() const;
		void			SetGlobalFadeEffect(float opacity = 1);

		/// Evaluate scene.
		void			Update();

		void			SetRenderMatrices(Renderer &);

		void			Render(Renderer &, GPU::TriangleBatch * = 0);
		void			RenderGlobalFade(Renderer &);
		void			RenderSetup(Core::ResourceFactories *);

		void			Setup();
		void			Reset();
		void			Clear();

		bool			IsItemToBeSaved(Item *, const Group *, uint save_flag) const;
		NML::Tag		*LinkInfoAsMetaTag(Item *, const Group *, uint flag) const;

		bool			FromMetaFileStoreGroup(const char *, Group ** = 0, uint = SceneIOAll, ToolMode = NoTool, int load_level = 0);
		bool			FromMetaTagStoreGroup(const NML::Tag &, Group **group = 0, uint = SceneIOAll, ToolMode = NoTool, int load_level = 0);
		bool			FromMetaTag(const NML::Tag &tag, ToolMode tool = NoTool) { return FromMetaTagStoreGroup(tag, 0, SceneIOAll, tool); }

		NML::Tag		*AsMetaTag(const Group *, uint = SceneIOAll, ToolMode = NoTool) const;
		NML::Tag		*AsMetaTag() const { return AsMetaTag(0); }

		Scene(Script::IVM * = 0);
virtual	~Scene();
};

	} // S2D
} // GS


#endif	// __NUI_SCENE__
