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

#pragma once

#include <glmSDKAPI.h>
#include <glmAbstractUserBehavior.h>

namespace glm
{
    // Behavior which allow to change & play different geometry files
    class GLM_SDK_API BehaviorGeometry : public AbstractUserBehavior
    {
    public:
        typedef SmartPointer<BehaviorGeometry> SP;

        class GLM_SDK_API BehaviorGeometryData
        {

        public:
            GLM_CLASS_STAT_ID( glm::MemoryStatIds::PrevizAndRender)

            BehaviorGeometryData();
            ~BehaviorGeometryData();

            // Internal Data Members
            int _geometryAnimFrameStep;      //!< Number of 1/10th frame to apply at each update
            float _geometryAnimStartPercent; //!< Start percent
            int _currentFrame;               //!< Current fbx frame * 10
        };

        int _geometryId;
        short _geometryAnimFrameStepMode; /// Geometry frame step mode (0: pp / 1: random / 2: auto)
        float _geometryAnimFrameSpeed;    /// Speed (in m/s) of the source geometry (for auto speed adapt)
        int _geometryAnimStartFrame;      /// Start frame * 10
        int _geometryAnimStopFrame;       /// Stop frame * 10
        bool _loopGeometryAnim;           /// True if the behavior loops
        bool _blendBehavior;              /// True if the behavior is blended with other behaviors
        int _samplingRate;                /// samplingRate in tenth of frame. 1 = each tenth of frame, 10 = round to nearest full frame
        Time _sceneDt;                    /// Behavior scene dt (mainly used in case of timewarping)

        static const char* _geoIDKBEntryName;
        static const char* _geoInfoKBEntryName;
        static const char* _geoBlendModeKBEntryName;

        static int64_t _geoIdHashKey;
        static int64_t _geoInfoHashKey;
        static int64_t _geoBlendModeHashKey;

    private:
        glm::Array<BehaviorGeometryData> _behaviorGeometryData;

        // KBEntry arrays have a life time == entity life time if KBEntry is not removed explicitely.
        // This pointers are swapped at same time as entity array, by KBContext
        PODArray<int>* _geoIds;
        Array<Vector3>* _geoFrameInfos;
        PODArray<int>* _geoBlendModes;

    public:
        GLM_CLASS_STAT_ID( glm::MemoryStatIds::PrevizAndRender)

        BehaviorGeometry();
        virtual ~BehaviorGeometry();

        static void initStatic();

        inline const glm::Array<BehaviorGeometryData>& getBehaviorGeometryData() const;
        void setGeometryAnimStartPercent(int64_t index, float startpercent);
        inline void setGeometryAnimFrameStep(int64_t index, float frameStep);
        void setGeometryAnimFrameInfos(int startFrame, int stopFrame);

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

    protected:
        // cloning
        friend class CloneFactory;
        inline virtual BehaviorGeometry* 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 doInit(int64_t index, BehaviorGraph& graph) override;
        virtual void doFinish(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;
    };

    //-------------------------------------------------------------------------
    inline BehaviorGeometry* BehaviorGeometry::create() const
    {
        BehaviorGeometry* myNewBehaviorGeometry = GLM_NEW(BehaviorGeometry, myNewBehaviorGeometry, getClassMemoryStatId());
        return myNewBehaviorGeometry;
    }

    //-------------------------------------------------------------------------
    inline const glm::Array<BehaviorGeometry::BehaviorGeometryData>& BehaviorGeometry::getBehaviorGeometryData() const
    {
        return _behaviorGeometryData;
    }

    //-------------------------------------------------------------------------
    inline void BehaviorGeometry::setGeometryAnimFrameStep(int64_t index, float frameStep)
    {
        _behaviorGeometryData[index]._geometryAnimFrameStep = (int)floorf(frameStep * 10);
    }

} // namespace glm
