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

#pragma once

#include "glmSDKAPI.h"
#include "glmMotionDefinitions.h"
#include "glmAbstractMotionBehavior.h"
#include "glmAimAtBN.h"

namespace glm
{
    class AimAtBN;

    // LookAt Modes
    struct AimAtType
    {
    public:
        enum Value
        {
            NONE = 0,
            FIXED_TARGET_POSITION,
            FIXED_TARGET_ORIENTATION,
            LATERAL_CONTROL,
            RANDOM_LOCATIONS_CONTROL,
            END
        };
    };

    // AimAt on a character
    class GLM_SDK_API AimAtBehavior : public AbstractMotionBehavior
    {
    public:
        class AimAtBehaviorData
        {
        public:
            float _currentLateralAngle;
            bool _targetReached;
            glm::Time _targetReachedTime;
            glm::Time _durationOnTarget;
            AimAtRequest* _aimAtRequest;
            float _coeff;
            Time _currentTime;
            bool _requestSet;

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

            AimAtBehaviorData();
            ~AimAtBehaviorData();
        };

        float _speed;
        Ramp _speedRamp;
        Vector3 _aimingAxis;
        IKTarget::SP _target;
        Angle _maxAngularYaw;
        Angle _maxAngularPitch;
        int _aimAtType;
        glm::Angle _lateralConeAngle; /// sides
        glm::Angle _verticalMinAngle; /// up and down
        glm::Angle _verticalMaxAngle;

        glm::Angle _alignementAttitudeOffset;

    private:
        // cache
        int _cachedBoneIndex;
        glm::PODArray<float> _cacheAdaptationWeights;

        AimAtBN* _aimAtBlendNode;

        glm::Array<AimAtBehaviorData> _aimAtData;

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

        AimAtBehavior();
        virtual ~AimAtBehavior();

        void setAimingBone(int boneIndex, glm::PODArray<float>& adaptationWeights);

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

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

        virtual void doAllocate(BehaviorGraph& graph) override;
        virtual void doDeallocate() override;
        virtual void doResize(BehaviorGraph& graph) override;
        virtual void doInit(BehaviorGraph& graph) override;
        virtual void doFinish(BehaviorGraph& graph) override;
        virtual void doInit(int64_t index, BehaviorGraph& graph) override;
        virtual void doFinish(int64_t index, BehaviorGraph& graph) override;
        virtual void doStart(int64_t index, BehaviorGraph& graph) override;
        virtual void doUpdate(int64_t index, BehaviorGraph& graph, Time dt) override;
        virtual AbstractBehavior::ResultStatus::Value doStop(int64_t index, BehaviorGraph& graph, Time dt) override;

    private:
        void computeAimAt(int64_t index, BehaviorGraph& graph);
        void clearAimingBoneCache();
    };

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