#pragma once

#include "Mix/Geometry/Sphere.h"
#include "Mix/Scene/IActorModel.h"
#include "Mix/Private/Scene/Common/RendererObject.h"
#include "Mix/Private/Scene/Common/Model.h"
#include "Mix/Private/Scene/Common/OctreeObject.h"

#ifdef _DEBUG
	#include "Mix/Private/Container.h"
#endif //_DEBUG

namespace Mix{ namespace Scene{ namespace Common{

	class ActorNode;
	class ActorMesh;
	class MotionController;
	class MotionMixer;
	class ActorRevision;
	class ActorDynamicsDirector;
	class ActorDynamicsFigure;

#ifdef _DEBUG
	class ActorDynamicsCluster;
#endif //_DEBUG

	class ActorModel : public Mix::Scene::IActorModel, public Mix::Scene::Common::RendererObject, public Mix::Scene::Common::Model
	{
	public:
		typedef Mix::STL::Vector<Mix::Memory::SECTION_SCENE, ActorMesh*> MeshList;

	private:
		typedef Mix::STL::Vector<Mix::Memory::SECTION_SCENE, ActorNode*> NodeList;
		typedef Mix::STL::Map<Mix::Memory::SECTION_SCENE, Mix::StringW, UInt32> IndexMap;
		typedef Mix::STL::Vector<Mix::Memory::SECTION_SCENE, Mix::Scene::Common::ActorRevision*> RevisionList;

	public:
		static ActorModel* CreateInstance( const wchar_t* pName );

	private:
		Mix::StringW m_Name;

		Mix::Scene::IActorModel::CONFIG m_Config;

		ActorModel::NodeList m_NodeList;
		ActorModel::IndexMap m_NodeIndexMap;

		ActorModel::MeshList m_MeshList;

		Mix::Scene::Common::ActorDynamicsDirector* m_pDynamicsDirector;
		Mix::Scene::Common::ActorDynamicsFigure* m_pDynamicsFigure;

		Mix::Scene::Common::MotionMixer* m_pMotionMixer;

		Mix::Scene::IActorListener* m_pListener;

		UInt32* m_RevisionFlags;
		UInt32 m_RevisionCounter;
		ActorModel::RevisionList m_RevisionList;
		Mix::Scene::Common::ActorRevision* m_pRevision;

		Mix::Matrix4x4 m_PivotMat;
		Mix::Matrix4x4 m_InvPivotMat;
		Mix::Matrix4x4 m_WorldMat;
		Mix::Matrix4x4 m_RootMat; //m_PivotMat * m_WorldMat

		Mix::Quaternion m_AngularVelocity;
		Mix::Vector3 m_LinearVelocity;

		Mix::Geometry::Sphere m_Bounds;

		IActorModel::STATE m_State;
		Float32 m_FarRatio;

		Mix::Scene::Common::ActorModelObject* m_pOctObj;

		Int32 m_UserIndex;
		void* m_pUserPtr;

		Boolean m_bDraw;
		Boolean m_bLocalLighting;
		UInt32 m_TRPriority;
		Mix::Scene::WATER_CONTAINS_RESULT m_DefWCResult;

#ifdef _DEBUG
		Float32 m_DebugDrawAxisScaling;
		Float32 m_DebugDrawJointFrameMinSize;
		Float32 m_DebugDrawJointLimitScaling;
#endif //_DEBUG

	public:
		Boolean Initialize( UInt32 nodeNum );
		void Finalize( void );

		void SetDynamicsFigure( Mix::Scene::Common::ActorDynamicsFigure* pDynamicsFigure );
		Mix::Scene::Common::ActorDynamicsFigure* GetDynamicsFigurePtr( void );

		Mix::Scene::Common::ActorDynamicsDirector* GetDynamicsDirectorPtr( void );
		Mix::Scene::Common::MotionMixer* GetMotionMixerPtr( void );

		void SetPivotMatrix( const Mix::Matrix4x4& pivotMat );
		Mix::Matrix4x4* GetWorldMatrixPtr( void );

		void Attach( Mix::Scene::Common::ActorModelObject* pOctObj );
		void Detach( void );

		ActorNode** GetNodeList( void );
		Mix::Scene::Common::ActorNode* GetNodePtr( const wchar_t* pName );
		ActorNode* GetRootNodePtr( void );

		const ActorModel::MeshList& GetMeshList( void ) const;
		Mix::Scene::Common::ActorRevision* GetRevisionPtr( void ) const;

		void InternalRefresh( const Mix::Vector3& eyePos );

#ifdef _DEBUG
		void Debug_Draw( Mix::Graphics::Utility::IPerspectiveRenderer* pPerspectiveRenderer, UInt32 flags );
#endif //_DEBUG

	private:
		ActorModel( const wchar_t* pName );
		virtual ~ActorModel( void );

		void ResetRoot( void );
		void ResetNode( const Mix::Matrix4x4& parentWorldMatrix, ActorNode* pNode, Boolean bInitLocalMatrix, Boolean bUpdateWorldMatrix );

		void UpdateRoot( void );

		void RefreshRoot( void );
		void RefreshNode( const Mix::Matrix4x4& parentWorldMatrix, ActorNode* pNode );
		void RefreshMesh( void );

	public:
		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::Common::Model
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual void AttachDynamics( Mix::Dynamics::IWorld* pWorld, Mix::Dynamics::IObjectListener* pObjectListener );
		virtual void DetachDynamics( Mix::Dynamics::IWorld* pWorld );

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::IActorModel
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual const wchar_t* GetName( void ) const;

		virtual const Mix::Scene::IActorModel::CONFIG& GetConfig( void ) const;
		virtual void SetConfig( const Mix::Scene::IActorModel::CONFIG& config );

		virtual UInt32 GetNodeCount( void ) const;
		virtual UInt32 GetNodeIndex( const wchar_t* pName ) const;
		virtual Boolean GetNodeByIndex( UInt32 index, Mix::Scene::IActorNode** ppNode );
		virtual Boolean GetNodeByName( const wchar_t* pName, Mix::Scene::IActorNode** ppNode );

		virtual Boolean ExistsCollider( void ) const;
		virtual Boolean GetCollider( Mix::Scene::IActorCollider** ppCollider );

		virtual UInt32 GetSensorCount( void ) const;
		virtual Boolean GetSensor( UInt32 index, Mix::Scene::IActorSensor** ppSensor );

		virtual Boolean ExistsKinematicCharacter( void ) const;
		virtual Boolean GetKinematicCharacter( Mix::Scene::IActorKinematicCharacter** ppKinematicCharacter );

		virtual void GetDynamicsDirector( Mix::Scene::IActorDynamicsDirector** ppDynamicsDirector );

		virtual void GetMotionMixer( Mix::Scene::IMotionMixer** ppMotionMixer );

		virtual Boolean GetListener( Mix::Scene::IActorListener** ppListener );
		virtual void SetListener( Mix::Scene::IActorListener* pListener );

		virtual const Mix::Matrix4x4& GetWorldMatrix( void ) const;
		virtual void SetWorldMatrix( const Mix::Matrix4x4& mat );

		virtual void Reset( UInt32 flags );

		virtual void Update( void );
		virtual void Update( Float32 dt );

		virtual const Mix::Quaternion& GetAngularVelocity( void ) const;
		virtual const Mix::Vector3& GetLinearVelocity( void ) const;

		virtual void Refresh( void );

		virtual void Refresh1( void );
		virtual void Refresh2( void );

		virtual const Mix::Geometry::Sphere& GetBounds( void ) const;

		virtual const Mix::Scene::IActorModel::STATE& GetState( void ) const;

		virtual Boolean IsVisible( void ) const;
		virtual Boolean IsVisible( UInt32 id ) const;
		virtual Boolean IsValid( void ) const;
		virtual Boolean IsValid( UInt32 id ) const;
		virtual Boolean IsIgnored( void ) const;

		virtual Boolean Clone( Mix::Scene::IActorModel** ppActorModel, UInt32 flags );

		virtual Float32 Debug_GetDrawAxisScaling( void ) const;
		virtual void Debug_SetDrawAxisScaling( Float32 scaling );

		virtual Float32 Debug_GetDrawJointFrameMinSize( void ) const;
		virtual void Debug_SetDrawJointFrameMinSize( Float32 minSize );

		virtual Float32 Debug_GetDrawJointLimitScaling( void ) const;
		virtual void Debug_SetDrawJointLimitScaling( Float32 scaling );

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::IModel
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual UInt32 GetMaterialSlotCount( void ) const;
		virtual const wchar_t* GetMaterialSlotName( UInt32 slotIndex ) const;
		virtual UInt32 GetMaterialSlotIndex( const wchar_t* pSlotName );
		virtual Boolean GetMaterialByIndex( UInt32 slotIndex, Mix::Scene::IMaterial** ppMaterial );
		virtual Boolean GetMaterialByName( const wchar_t* pSlotName, Mix::Scene::IMaterial** ppMaterial );
		virtual Boolean SetMaterialByIndex( UInt32 slotIndex, Mix::Scene::IMaterial* pMaterial );
		virtual Boolean SetMaterialByName( const wchar_t* pSlotName, Mix::Scene::IMaterial* pMaterial );

		virtual Int32 GetUserIndex( void )  const;
		virtual void SetUserIndex( Int32 index );

		virtual void* GetUserPtr( void ) const;
		virtual void SetUserPtr( void* pData );

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::IEntity
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual Boolean IsDraw( void ) const;
		virtual void SetDraw( Boolean state );

		virtual Boolean IsLocalLighting( void ) const;
		virtual void SetLocalLighting( Boolean state );

		virtual UInt32 GetTransparencyPriority( void ) const;
		virtual void SetTransparencyPriority( UInt32 priority );

		virtual Mix::Scene::WATER_CONTAINS_RESULT GetDefaultWaterContainsResult( void ) const;
		virtual void SetDefaultWaterContainsResult( Mix::Scene::WATER_CONTAINS_RESULT result );

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::IRendererObject
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual Mix::Scene::IRendererObject::TYPE GetType( void ) const;
		virtual Boolean IsRendering( void ) const;

	private:
		static const wchar_t* FAILED_CLONE;
	};

}}}
