#pragma once

#include <string>
#include <map>
#include <vector>

#include "Mix/Tool/Win32/Core/Object.h"
#include "Mix/Tool/Win32/Core/File/OutputStream.h"

namespace Mix{ namespace Tool{ namespace Win32{ namespace Graphics{

	class Motion;
	class MotionCurve;
	class ObjectModel;

	class MotionController : public Mix::Tool::Win32::Object
	{
	public:
		//トランスフォーム構造体
		struct TRANSFORM
		{
			unsigned int nodeIndex;
			Mix::Tool::Win32::Graphics::MotionCurve* pCurve;

			TRANSFORM( unsigned int _nodeIndex, Mix::Tool::Win32::Graphics::MotionCurve* _pCurve )
			{
				nodeIndex = _nodeIndex;
				pCurve = _pCurve;
			}
		};

	private:
		enum MC_VALUE
		{
			MC_MOT_FILEPATH_MAX = 256,
		};

		//モーションコントローラーヘッダ構造体
		struct MC_DESC
		{
			wchar_t name[Mix::Tool::Win32::Graphics::MAX_NAME_SIZE];
			unsigned int priority;
			unsigned int motionNum;
		};

		typedef std::map<std::wstring, unsigned int> IndexMap;
		typedef std::vector<Mix::Tool::Win32::Graphics::Motion*> List;
		typedef std::vector<MotionController::TRANSFORM> TransformList;

	private:
		Mix::Tool::Win32::Graphics::ObjectModel* m_pObjectModel;

		bool m_bAssigned;

		std::wstring m_Name;
		unsigned int m_Priority;
		MotionController::IndexMap m_IndexMap;
		MotionController::List m_List;

		MotionController::TransformList m_TransformList;
		Mix::Tool::Win32::Graphics::Motion* m_pSelected;
		Mix::Tool::Win32::Graphics::MOTION_STATE m_State;
		float m_PreTime;
		float m_Time;

	private:
		MotionController( unsigned int nodeCount );
		MotionController( const wchar_t* pName );
		~MotionController( void );

		void SetObjectModel( Mix::Tool::Win32::Graphics::ObjectModel* pObjectModel );
		Mix::Tool::Win32::Graphics::ObjectModel* GetObjectModel( void ) const;

		void Attach( Mix::Tool::Win32::Graphics::Motion* pMotion );
		void Detach( Mix::Tool::Win32::Graphics::Motion* pMotion );

		bool CreateMotionName( Mix::Tool::Win32::Graphics::Motion* pMotion, const wchar_t* pRequestName, std::wstring& name );

		void CreateIndexMap( void );

		void SelectMotion( Mix::Tool::Win32::Graphics::Motion* pMotion );
		bool IsMotionSelected( void ) const;

	private:
		void PlayMotion( Mix::Tool::Win32::Graphics::Motion* pMotion );
		void PauseMotion( Mix::Tool::Win32::Graphics::Motion* pMotion );
		void StopMotion( Mix::Tool::Win32::Graphics::Motion* pMotion );
		Mix::Tool::Win32::Graphics::MOTION_STATE GetMotionState( const Mix::Tool::Win32::Graphics::Motion* pMotion ) const;
		void SetMotionTime( Mix::Tool::Win32::Graphics::Motion* pMotion, int time );
		int GetMotionTime( Mix::Tool::Win32::Graphics::Motion* pMotion );

		void UpdateRootTransform( void );

		bool WriteDefault( const wchar_t* pFilePath, Mix::Tool::Win32::File::OutputStream& output );
		bool SaveFile( void );

	protected:
		void OnUpdateRootTransform( std::vector<Mix::Tool::Win32::Graphics::RT_BLEND>& blendList );
		void OnUpdateBodyTransform( std::vector<Mix::Tool::Win32::Graphics::BT_BLEND>& blendList );
		void OnUpdateTime( float timeStep );

	public:
		bool IsAssigned( void ) const;

		void SetName( const wchar_t* pName );
		const wchar_t* GetName( void ) const;

		void SetPriority( unsigned int value );
		unsigned int GetPriority( void ) const;

		unsigned int GetCount( void ) const;
		Mix::Tool::Win32::Graphics::Motion* Get( unsigned int index ) const;
		Mix::Tool::Win32::Graphics::Motion* Add( const char* pName, float framesPerSec );
		Mix::Tool::Win32::Graphics::Motion* Add( const wchar_t* pName, float framesPerSec );
		void Add( const wchar_t* pFilePath );
		void Add( Mix::Tool::Win32::Graphics::Motion* pMotion );
		void Remove( Mix::Tool::Win32::Graphics::Motion* pMotion );

		void Destroy( void );

	public:
		virtual Mix::Tool::Win32::Object::TYPE GetType( void ) const;

		friend class Motion;
		friend class ObjectModel;
	};

}}}}
