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

#pragma once

#include "glmSDKAPI.h"
#include "glmSmartPointer.h"
#include "glmPODArray.h"

namespace glm
{
    class BehaviorGraph;
    class CloneFactory;
    class AbstractBehavior;

    // Class managing the evaluation of a bool callback in order to prevent multiple calls in a same update step
    class GLM_SDK_API AbstractTrigger : public ReferenceCounter
    {
    private:
        glm::PODArray<int32_t> _lastFrame; // last evaluated frame
        glm::PODArray<bool> _lastValue;    // Result of last evaluation

        friend class BoolTrigger;

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

        typedef SmartPointer<AbstractTrigger> SP;

        virtual ~AbstractTrigger();

        virtual void allocate(BehaviorGraph& behaviorGraph);
        virtual void resize(BehaviorGraph& behaviorGraph);
		virtual bool isShareable() = 0;	// can a trigger be shared amongst different behavior graphs (eg MotionTime can not be shared)

        bool call(int64_t index, AbstractBehavior* behavior, BehaviorGraph& behaviorGraph, bool isAttached=false);
        void reset(int64_t index, AbstractBehavior* behavior, BehaviorGraph& behaviorGraph);
		bool getLastValue(int64_t index);
		bool hasLastFrame(int64_t index) const;
		int getLastFrame(int64_t index) const;
		void setAttached(bool isAttached);
		BehaviorGraph* _behaviorGraph;		// behavior graph pointer to access current frame

        struct AndOrType
        {
            enum Value
            {
                AND = 0,
                OR
            };
        };

    protected:
        AbstractTrigger();

        virtual bool doCall(int64_t index, AbstractBehavior* behavior, BehaviorGraph& behaviorGraph, bool isAttached) = 0;
        inline virtual void doReset(int64_t /*index*/, AbstractBehavior* /*behavior*/, BehaviorGraph& /*behaviorGraph*/);
		bool _isAttached;				   // true if the corresponding trigger is attached

        // cloning
        friend class CloneFactory;
        virtual void cloneImpl(AbstractTrigger* clone, CloneFactory* factory) const;
        virtual AbstractTrigger* create() const = 0;
    };

    //-------------------------------------------------------------------------
    inline void AbstractTrigger::doReset(int64_t /*index*/, AbstractBehavior* /*behavior*/, BehaviorGraph& /*behaviorGraph*/)
    {
    }

} // namespace glm
