/***************************************************************************
*                                                                          *
*  Copyright (C) Golaem S.A.  All Rights Reserved.                         *
*                                                                          *
***************************************************************************/

#pragma once

#include "glmSDKAPI.h"
#include "glmPhysicsDefinitions_PhysX.h"
#include "glmCollisionFilter.h"
#include "glmRagdollEntityComponent_PhysX.h"

#include "glmPhysX.h"	//needed for inheritance to physx::PxControllerFilterCallback

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4275)
#endif

namespace glm
{
	class GLM_SDK_API CharacterControllerQueryFilterCallback : public physx::PxQueryFilterCallback
	{
	public:
		GLM_CLASS_STAT_ID(glm::MemAllocStatId::Simulation)

		CharacterControllerQueryFilterCallback(const RagdollEntityComponent_PhysX * ragdollEntity, const CollisionFilter* collisionFilter);
		virtual ~CharacterControllerQueryFilterCallback() {}

		/**
		This filter callback is executed before the exact intersection test if PxQueryFlag::ePREFILTER flag was set.
		*/
		virtual physx::PxQueryHitType::Enum preFilter(const physx::PxFilterData& filterData, const physx::PxShape* shape, const physx::PxRigidActor* actor, physx::PxHitFlags& queryFlags);

		/**
		\brief This filter callback is executed if the exact intersection test returned true and PxQueryFlag::ePOSTFILTER flag was set.
		*/
		virtual physx::PxQueryHitType::Enum postFilter(const physx::PxFilterData& filterData, const physx::PxQueryHit& hit);

		const RagdollEntityComponent_PhysX * _ragdollEntity; // used to remove collisions with the controller and the ragdoll
		const CollisionFilter* _collisionFilter; // collision filter information
	};
	
	/**
	* \brief CharacterController vs CharacterController collision filter
	*/
	class GLM_SDK_API CharacterControllerFilterCallback : public physx::PxControllerFilterCallback
	{
	public:
		GLM_CLASS_STAT_ID(glm::MemAllocStatId::Simulation)

		CharacterControllerFilterCallback(bool collide = true)
			: _collide(collide)
		{}
		virtual ~CharacterControllerFilterCallback(){}

		bool _collide;
		virtual bool filter(const physx::PxController& /*a*/, const physx::PxController& /*b*/)
		{
			return _collide;
		}
	};

	/**
	* \brief abstract interface realization for the motion entity
	*/
	class GLM_SDK_API CharacterController_PhysX
	{
	public:
		GLM_ABSTRACTCLASS_STAT_ID(glm::MemoryStatIds::Simulation);

		CharacterController_PhysX(physx::PxControllerDesc* descriptor, const CollisionFilter* collisionFilter, PhysicsContext_PhysX& physicsContext, SimuEntityHandle& entityHandle);
		~CharacterController_PhysX();

		//************************************************************
		//! @name Compute
		//************************************************************
		//@{
		/**
		* \brief init
		*/
		bool init();

		/**
		* \brief compute and update the transform of the rigid
		*/
		void update(const Time dt);

		/**
		* \brief clean
		*/
		void clean();
		//@}

		//************************************************************
		//! @name Accessors
		//************************************************************
		//@{
		/**
		* \brief getRagdollComponent
		*/
		const RagdollEntityComponent_PhysX * getRagdollComponent() const
		{
			return _ragdollEntity;
		}

		/**
		* \brief getGravitationalAcceleration
		*/
		glm::Vector3 getGravitationalAcceleration() const
		{
			return _gravityAccu;
		}
		//@}

	protected:
		physx::PxControllerDesc* _descriptor;
		PhysicsContext_PhysX* _thePhysicsContext;
		SimuEntityHandle _entityHandle;
		const RagdollEntityComponent_PhysX * _ragdollEntity; // used to remove collisions with the controller and the ragdoll
		const CollisionFilter* _collisionFilter;

		physx::PxController* _controller;
		physx::PxControllerFilters* _filter;
		glm::Vector3 _gravityAccu;
		bool _firstUpdate;
		int _rigidBodyInfoIndex;

	public:
		glm::Vector3 _positionOffset;
		float _scale;
		bool _collideWithCC;
	};
}

#ifdef _MSC_VER
#pragma warning(pop)
#endif
