#pragma once

#include "Mix/Scene/IMotion.h"
#include "Mix/Private/Scene/Common/MotionTypes.h"

namespace Mix{ namespace File{
	class IReader;
}}

namespace Mix{ namespace Scene{ namespace Common{

	class MotionCurve;
	class RootMotionCurve;
	class MotionEntryProcesser;

	class Motion : public Mix::Scene::IMotion
	{
	private:
		enum MOT_VALUE
		{
			MOT_MAGIC_NUMBER = 0x5F544F4D,
			MOT_VERSION = 0x01000000,
		};

		struct MOT_FILE_HEADER
		{
			UInt32 magicNumber;
			UInt32 version;
		};

		struct MOT_DATA_HEADER
		{
			wchar_t name[32];
			Float32 framesPerSec;
			Float32 lastFrame;
			Float32 speed;
			Float32 blendRatio;
			Float32 loopStartFrame;
			Float32 loopEndFrame;
			UInt32 rtCurveNum;
			UInt32 btCurveNum;
		};

		struct ENTRY_SORT
		{
			bool operator () ( const Mix::Scene::MOTION_ENTRY_DESC& l, const Mix::Scene::MOTION_ENTRY_DESC& r )
			{
				return l.startFrame < r.startFrame;
			}
		};

		typedef Mix::STL::Vector<Mix::Memory::SECTION_SCENE, Mix::Scene::Common::MotionCurve*> CurveList;
		typedef Mix::STL::Vector<Mix::Memory::SECTION_SCENE, Mix::Scene::MOTION_ENTRY_DESC> EntryList;
		typedef Mix::STL::List<Mix::Memory::SECTION_SCENE, Mix::Scene::Common::MotionEntryProcesser*> EntryProcesserList;

	public:
		static Motion* CreateInstance( void );
		static Motion* CreateInstance( Mix::IO::IReader* pReader, Boolean bWithMagicNumber, const wchar_t* pNameLabel, const wchar_t* pName );

	private:
		Mix::StringW m_Name;

		Float32 m_FramesPerSec;

		Float32 m_LastFrame;

		Float32 m_LoopStartFrame;
		Float32 m_LoopEndFrame;

		Float32 m_Speed;
		Float32 m_BlendRatio;

		Mix::Scene::Common::RootMotionCurve* m_pRootCurve;
		Motion::CurveList m_BodyCurveList;

		Motion::EntryList m_EntryList;
		Motion::EntryProcesserList m_EntryProcesserList;

	private:
		Motion( void );
		virtual ~Motion( void );

	public:
		Mix::Scene::Common::RootMotionCurve* GetRootCurvePtr( void );

		Mix::Scene::Common::MotionCurve* GetBodyCurvePtr( UInt32 index );
		UInt32 GetBodyCurveCount( void ) const;

		Mix::Scene::Common::MotionEntryProcesser* AddEntryProcesser( void );
		void RemoveEntryProcesser( Mix::Scene::Common::MotionEntryProcesser* pEntryProcesser );

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

		virtual Float32 GetFramesPerSec( void ) const;

		virtual Float32 GetLastFrame( void ) const;

		virtual Float32 GetLoopStartFrame( void ) const;
		virtual Float32 GetLoopEndFrame( void ) const;

		virtual void SetSpeed( Float32 speed );
		virtual Float32 GetSpeed( void ) const;

		virtual void SetBlendRatio( Float32 ratio );
		virtual Float32 GetBlendRatio( void ) const;

		virtual void SetEntry( const Mix::Scene::MOTION_ENTRY_DESC* entries, UInt32 count );
		virtual const Mix::Scene::MOTION_ENTRY_DESC* GetEntryPtr( UInt32 index ) const;
		virtual UInt32 GetEntryCount( void ) const;

		virtual Boolean Clone( Mix::Scene::IMotion** ppMotion, Boolean bDuplicateEntries );

	public:
		static const wchar_t* FAILED_CREATE;
	};

}}}
