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

#pragma once

#include "glmSDKAPI.h"

#include "glmRagdollEntityComponent_PhysX.h" //base class IForceCallback is in this file
#include "glmAbstractDynamicsBehavior.h"

namespace glm
{
    class RagdollEntityComponent_PhysX;

    /**
     * \brief A ForceCallback that always return the same static value
     */
    class GLM_SDK_API StaticForceCallback : public IForceCallback
    {
    public:
        Vector3 _force;

    public:
        GLM_CLASS_STAT_ID( glm::MemoryStatIds::Simulation)

        StaticForceCallback(const Vector3& globalForce = Vector3::getNullVector());
        virtual ~StaticForceCallback();
        inline Vector3 getForceAt(EntityType& entityType, ForceBehavior* forceBehavior, int64_t entityIndex);
    };

    class GLM_SDK_API ForceBehavior : public AbstractDynamicsBehavior
    {
        friend class RagdollEntityComponent_PhysX;

    public:
        int _forceMode;       //ForceMode::Value
        float _boneForceMode; // -1. == force-(force*mass) / 0. == uniform force on all bones / 1. == force*mass on all bones;
        float _boneForceMultiplierMin;
        float _boneForceMultiplierMax;
        ForceParameters _behaviorForce;

    protected:
        bool _ownForceCallback;
        IForceCallback* _forceCallback; /// force that is applied while the behavior is running

    public:
        GLM_CLASS_STAT_ID( glm::MemoryStatIds::Simulation)

        ForceBehavior();
        virtual ~ForceBehavior();

        /**
       * \brief set the force callback to use
       * \param force force to use at start time or at call time 
       * \param ownCallback true if the callback shall be deleted by the behavior
       */
        void setForceCallback(IForceCallback* force, bool ownCallback);
        inline IForceCallback* touchForceCallback();

        // type checking - value derived from this type
        virtual bool isThisType(const AbstractBehavior* value) const override;

    protected:
        // cloning
        friend class CloneFactory;
        inline virtual ForceBehavior* create() const override;

        virtual void doInit(BehaviorGraph& graph) override;
        virtual void doStart(int64_t index, BehaviorGraph& graph) override;
        virtual void onRequestStop(int64_t index, BehaviorGraph& graph) override;
    };

    //-------------------------------------------------------------------------
    inline Vector3 StaticForceCallback::getForceAt(EntityType& /*entityType*/, ForceBehavior* /*forceBehavior*/, int64_t /*entityIndex*/)
    {
        return _force;
    }

    //-------------------------------------------------------------------------
    inline IForceCallback* ForceBehavior::touchForceCallback()
    {
        return _forceCallback;
    }

    //-------------------------------------------------------------------------
    inline ForceBehavior* ForceBehavior::create() const
    {
        ForceBehavior* myNewForceBehavior = GLM_NEW(ForceBehavior, myNewForceBehavior, getClassMemoryStatId());
        return myNewForceBehavior;
    }
} // namespace glm
