#pragma once

#include <map>

#include "Mix/Scene/IMotionController.h"

#include "Mix/Private/Container.h"
#include "Mix/Private/Queue.h"
#include "Mix/Private/Scene/Common/MotionTypes.h"

namespace Mix{ namespace Scene{ namespace Common{

	class ActorModel;
	class MotionMixer;
	class MotionCurve;
	class Motion;
	class MotionState;
	class MotionDeformer;
	class MotionEntryProcesser;

	class MotionController : public Mix::Scene::IMotionController
	{
	private:
		enum PRIVATE_CONSTANT
		{
			COMANND_DEF_CAPACITY = 4,
			COMANND_RESIZE_STEP = 2,

			MOTION_PREVIOUS	= 0,
			MOTION_CURRENT	= 1,
			MOTION_MAX		= 2,
		};

		//アクション
		enum ACTION
		{
			ACTION_QUEUEING	= 0,	//キューイングを行う
			ACTION_FADEIN	= 1,	//フェードイン( トランジション )
			ACTION_FADEOUT	= 2,	//フェードアウト( トランジション )
		};

		//モーションステート
		enum MOTION_STATE
		{
			MS_PLAY		= 0,	//再生
			MS_PLAYING	= 1,	//再生中
			MS_STOP		= 2,	//停止
		};

		//モーション構造体
		struct MOTION
		{
			Mix::Scene::MOTION_HANDLE handle;
			Mix::Scene::Common::Motion* pInterface;
			Mix::Scene::Common::MotionState* pState;
			Mix::Scene::Common::MotionDeformer* pDeformer;
			Mix::Scene::Common::MotionEntryProcesser* pEntryProcesser;
			Mix::Scene::IMotionListener* pListener;
			MOTION_STATE state;
			Float32 preFrame;

			MOTION( Mix::Scene::MOTION_HANDLE _handle,
					Mix::Scene::Common::Motion* _pInterface,
					Mix::Scene::Common::MotionState* _pState,
					Mix::Scene::Common::MotionEntryProcesser* _pEntryProcesser )
			{
				handle = _handle;
				pInterface = _pInterface;
				pState = _pState;
				pDeformer = NULL;
				pEntryProcesser = _pEntryProcesser;
				pListener = NULL;
				state = MotionController::MS_STOP;
				preFrame = -1.0f;
			}
		};

		typedef std::map<Mix::StringW, Mix::Scene::MOTION_HANDLE> HandleMap;
		typedef std::map<Mix::Scene::MOTION_HANDLE, MotionController::MOTION> MotionMap;

	private:
		Mix::Scene::Common::ActorModel* m_pModel;
		Mix::Scene::Common::MotionMixer* m_pMixer;

		Mix::StringW m_Name;

		UInt32 m_Priority;

		MotionController::HandleMap m_HandleMap;
		MotionController::MotionMap m_MotionMap;

		MotionController::ACTION m_Action;

		Mix::QueueT<Mix::Memory::SECTION_SCENE, Mix::Scene::MOTION_COMMAND> m_CommandQueue;

		MotionController::MOTION* m_MotionTable[MotionController::MOTION_MAX];

		Float32 m_TransitionFramesInv;
		Float32 m_TransitionFrame;
		Float32 m_TransitionRatio;

	public:
		static MotionController* CreateInstance(	Mix::Scene::Common::ActorModel* pModel,
													Mix::Scene::Common::MotionMixer* pMixer,
													const wchar_t* pName,
													UInt32 priority );

	private:
		MotionController(	Mix::Scene::Common::ActorModel* pModel,
							Mix::Scene::Common::MotionMixer* pMixer,
							const wchar_t* pName,
							UInt32 priority );

		virtual ~MotionController( void );

		Mix::Scene::MOTION_HANDLE ProcAdd( Mix::Scene::Common::Motion* pMotion );

	public:
		void OnRootTransform( Mix::ContainerT<Mix::Scene::Common::MOTION_ROOT_BLEND, Mix::Memory::SECTION_SCENE>& list );
		void OnBodyTransform( Mix::ContainerT<Mix::Scene::Common::MOTION_BODY_BLEND, Mix::Memory::SECTION_SCENE>& list );
		void OnUpdate( Float32 dt );
		void OnReset( void );

		void Stop( MotionController::MOTION* pMotion );

		Boolean AddMotion( Mix::Scene::Common::Motion* pMotion );
		Boolean CloneMotion( MotionController* pDstController, Boolean bShared, Boolean bDuplicateEntries );

		UInt32 GetCondition( const Mix::Scene::MOTION_HANDLE& handle ) const;

		Boolean Finalize( void );
		void Dispose( void );

	public:
		virtual const wchar_t* GetName( void ) const;

		virtual UInt32 GetPriority( void ) const;

		virtual UInt32 GetHandleCount( void ) const;
		virtual Mix::Scene::MOTION_HANDLE GetHandleByIndex( UInt32 index ) const;
		virtual Mix::Scene::MOTION_HANDLE GetHandleByName( const wchar_t* pName ) const;
		virtual Mix::Scene::MOTION_HANDLE Add( Mix::Scene::IMotion* pMotion );
		virtual Boolean Remove( const Mix::Scene::MOTION_HANDLE& handle );
		virtual Boolean Get( const Mix::Scene::MOTION_HANDLE& handle, Mix::Scene::IMotion** ppMotion );

		virtual Boolean GetState( const Mix::Scene::MOTION_HANDLE& handle, Mix::Scene::IMotionState** ppMotionState );

		virtual void SetListener( Mix::Scene::IMotionListener* pListener );
		virtual Boolean SetListener( const Mix::Scene::MOTION_HANDLE& handle, Mix::Scene::IMotionListener* pListener );

		virtual void SendCommand( Mix::Scene::MOTION_COMMAND_EXECUTE_TYPE exeType, const Mix::Scene::MOTION_COMMAND& com );
		virtual UInt32 GetCommandCount( void ) const;

	private:
		static const wchar_t* FAILED_CREATE;
	};

}}}
