#pragma once

#include "Mix/Geometry/Sphere.h"
#include "Mix/Scene/IActorNode.h"
#include "Mix/Private/Scene/Common/RendererObject.h"

namespace Mix{ namespace Scene{ namespace Common{

	class ActorRevision;
	class ActorModel;
	class ActorMesh;
	class ActorConstraint;
	class ActorDynamicsPart;

	class ActorNode : public Mix::Scene::IActorNode, public Mix::Scene::Common::RendererObject
	{
	public:
		static ActorNode* CreateInstance( Mix::Scene::IActorModel* pOwner );

	public:
		typedef Mix::STL::Map<Mix::Memory::SECTION_SCENE, Mix::StringW, ActorConstraint*> ConstraintMap;

	private:
		typedef Mix::STL::Vector<Mix::Memory::SECTION_SCENE, ActorNode*> ChildPtrList;

	private:
		Mix::Scene::IActorModel* m_pOwner;

		Mix::StringW m_Name;

		Mix::Scene::Common::ActorMesh* m_pMesh;
		Mix::Scene::Common::ActorDynamicsPart* m_pDynamicsPart;
		Mix::Scene::Common::ActorRevision* m_pRevision;

		Mix::Matrix4x4 m_GeometricMat;
		Mix::Matrix4x4 m_InvGeometricMat;
		Mix::Matrix4x4 m_DefLocalMat;
		Mix::Matrix4x4 m_LocalMat;
		Mix::Matrix4x4 m_WorldMat;

		ActorNode::ConstraintMap m_ConstraintMap;

		Int32 m_ParentIndex;
		ActorNode* m_pParent;
		ActorNode::ChildPtrList m_ChildPtrList;

		Int32 m_UserIndex;
		void* m_pUserPtr;

	private:
		ActorNode( Mix::Scene::IActorModel* pOwner );
		virtual ~ActorNode( void );

		void UpdateConstraint( void );

	public:
		void SetName( const wchar_t* pName );

		void SetGeometricMatrix( const Mix::Matrix4x4& mat );
		const Mix::Matrix4x4& GetGeometricMatrix( void ) const;

		void SetDefLocalMatrix( const Mix::Matrix4x4& mat );
		const Mix::Matrix4x4& GetDefLocalMatrix( void ) const;
		Float32* GetDefLocalMatrixPtrF( void );
		Mix::Matrix4x4* GetLocalMatrixPtr( void );
		const Mix::Matrix4x4* GetWorldMatrixPtr( void ) const;

		Mix::Scene::Common::ActorMesh* GetMeshPtr( void );
		void SetMesh( Mix::Scene::Common::ActorMesh* pMesh );

		Mix::Scene::Common::ActorDynamicsPart* GetDynamicsPartPtr( void );
		void SetDynamicsPart( Mix::Scene::Common::ActorDynamicsPart* pDynamicsPart );

		Mix::Scene::Common::ActorRevision* GetRevisionPtr( void ) const;
		void SetRevisionPtr( Mix::Scene::Common::ActorRevision* pRevision );

		void SetParent( Int32 parentIndex, ActorNode* pParent );

		void ReserveChilds( UInt32 count );
		UInt32 GetChildCount( void ) const;
		ActorNode* GetChildPtr( UInt32 index ) const;
		ActorNode* const* GetChilds( void ) const;

		void Reset( const Mix::Matrix4x4& parentWorldMat );
		void Refresh( const Mix::Matrix4x4& parentWorldMat );

		const ActorNode::ConstraintMap& GetConstraintMap( void ) const;

		void Dispose( void );

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

	public:
		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::IActorNode
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual Boolean GetOwner( Mix::Scene::IActorModel** ppOwner );
		virtual Mix::Scene::IActorModel* GetOwnerPtr( void ) const;

		virtual Int32 GetParentIndex( void ) const;

		virtual const wchar_t* GetName( void ) const;

		virtual Boolean IsDraw( void ) const;
		virtual void SetDraw( Boolean state, UInt32 depth );

		virtual void ResetLocalMatrix( void );

		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 GetConstraint( const wchar_t* pName, Mix::Scene::IActorConstraint** ppConstraint );
		virtual Boolean AddConstraint( const wchar_t* pName, Mix::Scene::IActorConstraint** ppConstraint );
		virtual void RemoveConstraint( Mix::Scene::IActorConstraint* pConstraint );

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

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

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::INode
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual const Mix::Matrix4x4& GetLocalMatrix( void ) const;
		virtual void SetLocalMatrix( const Mix::Matrix4x4& mat );

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

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

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

	private:
		static const wchar_t* FAILED_ADD_CONSTRAINT;
	};

}}}
