#pragma once

#include "fbxsdk.h"

#include <list>
#include <vector>
#include <map>

#include "Mix/Tool/Win32/Core/Graphics/FBX.h"
#include "Mix/Tool/Win32/Core/Graphics/Model.h"

#include "Mix/Tool/Win32/Core/Graphics/MAMTypes.h"

namespace Mix{ namespace Tool{ namespace Win32{ namespace Dynamics{
	class RigidBody;
}}}}

namespace Mix{ namespace Tool{ namespace Win32{ namespace Dynamics{ namespace Design{
	class Basic;
	class Actor;
	class Part;
}}}}}

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

	class Material;
	class MotionController;
	class Node;
	class ObjectMesh;

	class ObjectModel : public Mix::Tool::Win32::Graphics::Model
	{
	public:
		static const wchar_t* UNASSIGNED_TEXT;
		static const wchar_t* DEF_MOTION_CTRL_NAME;

	public:
		//1秒間あたりのフレーム数
		enum TIME_MODE
		{
			TIME_MODE_FRAMES_30,	//30フレーム
			TIME_MODE_FRAMES_60,	//60フレーム
		};

		//インポート設定構造体
		struct IMPORT_CONFIG
		{
			const wchar_t* pFilePath;	//!< ファイルパス

			Mix::Tool::Win32::Graphics::Model::IMPORT_OPTION_TYPE opt;	//!< オプション

			float scaling;				//!< スケール
			D3DXVECTOR3 rotation;		//!< 回転
			D3DXVECTOR3 translation;	//!< 移動

			bool bSmooting;				//!< スムージングを有効にする場合は true
			float smootingAngle;		//!< スムージング角度( DEG )

			TIME_MODE motionTimeMode;	//!< モーションの一秒間のフレーム数

			Mix::Tool::Win32::Graphics::MESH_BUILD_TYPE meshBuildType;	//!< メッシュのビルドタイプ

			IMPORT_CONFIG( void )
			{
				pFilePath = NULL;

				opt = Mix::Tool::Win32::Graphics::Model::IO_FBX_MAYA;

				scaling = 1.0f;
				rotation = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
				translation = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );

				bSmooting = false;
				smootingAngle = 45.0f;

				motionTimeMode = ObjectModel::TIME_MODE_FRAMES_60;

				meshBuildType = Mix::Tool::Win32::Graphics::MESH_BUILD_OPTIMIZE;
			}
		};

	private:
		//モーションコントローラーのソート構造体
		struct MOTION_CTRL_SORT
		{
			bool operator()( const Mix::Tool::Win32::Graphics::MotionController* l, const Mix::Tool::Win32::Graphics::MotionController* r );
		};

		typedef std::map<std::wstring, int> NodeIndexMap;
		typedef std::vector<Mix::Tool::Win32::Graphics::Node*> NodeList;
		typedef std::vector<Mix::Tool::Win32::Graphics::ObjectMesh*> MeshList;
		typedef std::vector<Mix::Tool::Win32::Graphics::BASE_SHAPE> BaseShapeList;
		typedef std::vector<Mix::Tool::Win32::Graphics::MotionController*> MotionControllerList;
		typedef std::vector<Mix::Tool::Win32::Graphics::RT_BLEND> RTBlendList;
		typedef std::vector<Mix::Tool::Win32::Graphics::BT_BLEND> BTBlendList;

	private:
		std::wstring m_Name;

		std::wstring m_MotionDirectoryPath;

		D3DXVECTOR3 m_Scaling;
		D3DXQUATERNION m_Rotation;
		D3DXVECTOR3 m_Translation;

		D3DXMATRIX m_PivotMat;
		D3DXMATRIX m_InvPivotMat;

		ObjectModel::NodeList m_NodeList;
		ObjectModel::NodeIndexMap m_NodeIndexMap;

		ObjectModel::MeshList m_MeshList;

		ObjectModel::MotionControllerList m_MotionCtrlList;
		Mix::Tool::Win32::Graphics::MotionController* m_pUnassignedMotionCtrl;

		Mix::Tool::Win32::Graphics::Node* m_pSelectedNode;
		ObjectMesh* m_pSelectedMesh;

		ObjectModel::RTBlendList m_RTBlendList;
		ObjectModel::BTBlendList m_BTBlendList;

		unsigned int m_RTFlags;
		int m_RTNodeIndex;
		MOTION_RT_AXIS m_RTRAxis;
		MOTION_RT_HORIZONAL m_RTTHoriz;
		MOTION_RT_VERTICAL m_RTTVert;
		MOTION_RT_AXIS m_RTTAxis;

		ObjectModel::BaseShapeList m_BaseShapeList;
		Mix::Tool::Win32::Dynamics::Design::Actor* m_pDynamicsActorDesigner;

	private:
		bool FBX_LoadNode( FBX& fbx, FbxNode* pFbxNode, Mix::Tool::Win32::Graphics::Node* pParentNode, const ObjectModel::IMPORT_CONFIG& cfg );
		bool FBX_LoadMesh( FBX& fbx, FbxNode* pFbxNode, Mix::Tool::Win32::Graphics::Node* pNode, const ObjectModel::IMPORT_CONFIG& cfg );

		bool Optimize( const ObjectModel::IMPORT_CONFIG& cfg, bool bInvertZ );
		void CollectActorBaseShape( const D3DXMATRIX& mat, Mix::Tool::Win32::Graphics::Node* pNode );
		bool BuildDynamicsPartTree( Mix::Tool::Win32::Dynamics::Design::Part* pParentPartDesigner, Mix::Tool::Win32::Graphics::Node* pNode );
		Mix::Tool::Win32::Graphics::Node* FindNode( const wchar_t* pName );
		bool CreateMotionControllerName( Mix::Tool::Win32::Graphics::MotionController* pMotionCtrl, const wchar_t* pRequestName, std::wstring& name );

		D3DXMATRIX ComputeRootMatrix( void );

		static bool SaveModel_CollectDynamics(
			Mix::Tool::Win32::Graphics::ObjectModel* pModel,
			std::vector<Mix::Tool::Win32::Graphics::MAM_SHAPE_1_0_0_0>& colliderShapeList,
			std::vector<Mix::Tool::Win32::Graphics::MAM_SHAPE_1_0_0_0>& sensorShapeList,
			std::vector<Mix::Tool::Win32::Graphics::MAM_COLLIDER_1_0_0_0>& colliderList,
			std::map<const Mix::Tool::Win32::Dynamics::RigidBody*, int>& colliderMap,
			std::vector<Mix::Tool::Win32::Graphics::MAM_SENSOR_1_0_0_0>& sensorList,
			std::vector<Mix::Tool::Win32::Graphics::MAM_JOINT_1_0_0_0>& jointList );

		static bool SaveModel_CollectDynamics(
			Mix::Tool::Win32::Graphics::Node* pNode,
			std::vector<Mix::Tool::Win32::Graphics::MAM_SHAPE_1_0_0_0>& colliderShapeList,
			std::vector<Mix::Tool::Win32::Graphics::MAM_SHAPE_1_0_0_0>& sensorShapeList,
			std::vector<Mix::Tool::Win32::Graphics::MAM_COLLIDER_1_0_0_0>& colliderList,
			std::map<const Mix::Tool::Win32::Dynamics::RigidBody*, int>& colliderMap,
			std::vector<Mix::Tool::Win32::Graphics::MAM_SENSOR_1_0_0_0>& sensorList,
			std::vector<Mix::Tool::Win32::Graphics::MAM_JOINT_1_0_0_0>& jointList );

		static bool SaveModel_CollectDynamics_Basic( 
			const wchar_t* pNodeName,
			Mix::Tool::Win32::Dynamics::Design::Basic* pBasic,
			std::vector<Mix::Tool::Win32::Graphics::MAM_SHAPE_1_0_0_0>& colliderShapeList,
			std::vector<Mix::Tool::Win32::Graphics::MAM_SHAPE_1_0_0_0>& sensorShapeList,
			std::vector<Mix::Tool::Win32::Graphics::MAM_COLLIDER_1_0_0_0>& colliderList,
			std::map<const Mix::Tool::Win32::Dynamics::RigidBody*, int>& colliderMap,
			std::vector<Mix::Tool::Win32::Graphics::MAM_SENSOR_1_0_0_0>& sensorList );

		static bool SaveModel_CollectDynamics_Shapes(
			const wchar_t* pNodeName,
			const wchar_t* pRigidBodyType,
			const wchar_t* pRigidBodyName,
			const void* pSrc,
			std::vector<Mix::Tool::Win32::Graphics::MAM_SHAPE_1_0_0_0>& shapeList );

		static bool SaveModel_CollectDynamics_Part(
			const wchar_t* pNodeName,
			Mix::Tool::Win32::Dynamics::Design::Part* pPart,
			std::map<const Mix::Tool::Win32::Dynamics::RigidBody*, int>& colliderMap,
			std::vector<Mix::Tool::Win32::Graphics::MAM_JOINT_1_0_0_0>& jointList );

		static void LogBaseShape( const wchar_t* pTitle, const Mix::Tool::Win32::Graphics::BASE_SHAPE* pBaseShape );

	private:
		const Mix::Tool::Win32::Graphics::Node* GetRootTransformConstant( D3DXMATRIX& baseMat, D3DXMATRIX& castMat, D3DXQUATERNION& invDefWorldRot, D3DXVECTOR3& defWorldPos );
		void GetRootTransformConstant( const Mix::Tool::Win32::Graphics::Node* pNode, D3DXMATRIX& baseMat );
/*
		const Mix::Tool::Win32::Graphics::Node* GetRootTransformConstant( D3DXQUATERNION& baseRotation, D3DXMATRIX& baseTranslation ) const;
		void GetRootTransformConstant( const Mix::Tool::Win32::Graphics::Node* pNode, D3DXQUATERNION& baseRotation, D3DXMATRIX& baseTranslation ) const;
*/
		Mix::Tool::Win32::Graphics::Node* GetRootTransformNodePtr( void ) const;
/*
		void ApplyPivot( D3DXQUATERNION& rotation );
		void ApplyPivot( D3DXMATRIX& mat );
*/
	public:
		ObjectModel( void );
		virtual ~ObjectModel( void );

		//インポート
		bool Import( const ObjectModel::IMPORT_CONFIG& cfg );
		bool ImportFinalize( void );

		//メッシュ
		unsigned int GetMeshCount( void ) const;
		Mix::Tool::Win32::Graphics::ObjectMesh* GetMesh( unsigned int index ) const;

		//ノード
		Mix::Tool::Win32::Graphics::Node* GetNode( const wchar_t* pName );
		int GetNodeIndexByName( const wchar_t* pName ) const;

		//モーションコントローラー
		unsigned int GetMotionControllerCount( void ) const;
		Mix::Tool::Win32::Graphics::MotionController* GetMotionControllerByIndex( unsigned int index );
		Mix::Tool::Win32::Graphics::MotionController* GetUnassignedMotionController( void );
		Mix::Tool::Win32::Graphics::MotionController* AddMotionController( void );
		void RemoveMotionController( Mix::Tool::Win32::Graphics::MotionController* pMotionController );

		//ルートトランスフォーム
		void SetRootTransformActive( unsigned int flags );
		unsigned int GetRootTransformActive( void ) const;
		void SetRootTransformNodeIndex( int nodeIndex );
		int GetRootTransformNodeIndex( void ) const;
		const wchar_t* GetRootTransformNodeName( void ) const;
		void SetRootRotationAxis( MOTION_RT_AXIS axis );
		const MOTION_RT_AXIS& GetRootRotationAxis( void ) const;
		void SetRootTranslationHorizonal( MOTION_RT_HORIZONAL horiz );
		MOTION_RT_HORIZONAL GetRootTranslationHorizonal( void ) const;
		void SetRootTranslationVertical( MOTION_RT_VERTICAL vert );
		MOTION_RT_VERTICAL GetRootTranslationVertical( void ) const;
		void SetRootTranslationAxis( MOTION_RT_AXIS axis );
		const MOTION_RT_AXIS& GetRootTranslationAxis( void ) const;
		void UpdateRootTransform( void );

		//姿勢のリセット
		void ResetPose( void );
		//ジャンプ( アクターにキネマティックキャラクターが設定されている場合のみ )
		void Jump( void );

		//モーションの保存(ファイル)
		bool SaveMotions( void );

		//ベースシェイプ
		int GetBaseShapeCount( void ) const;
		Mix::Tool::Win32::Graphics::BASE_SHAPE* GetBaseShapePtr( int index );

		//ダイナミクス : ユニバーサルデザイナー
		Mix::Tool::Win32::Dynamics::Design::Actor* GetDynamicsActorDesignerPtr( void );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// Model
	////////////////////////////////////////////////////////////////////////////////////////////////////

	public:
		virtual const wchar_t* GetName( void ) const;
		virtual Mix::Tool::Win32::Graphics::Node* GetRootNode( void );
		virtual void SelectedMeshByKey( unsigned int key );
		virtual void SelectedNode( Mix::Tool::Win32::Graphics::Node* pNode );
		virtual bool SaveModel( void );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// DrawObject
	////////////////////////////////////////////////////////////////////////////////////////////////////

	private:
		virtual void OnUpdate( void );
		virtual void OnRefresh( void );
		virtual void OnDraw( DrawObject::DRAW_EVENT_ARGS& args );
		virtual void OnRefreshMesh( unsigned int materialSlotIndex );

	////////////////////////////////////////////////////////////////////////////////////////////////////

	public:
		MIX_OBJECT_TYPE( Mix::Tool::Win32::Object::GRAPHICS__OBJECT_MODEL, Mix::Tool::Win32::Graphics::Model );

		friend class Manager;
		friend class OptimizeMesh;
		friend class ObjectMesh;
		friend class Motion;
		friend class MotionController;
	};

}}}}
