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

#pragma once

#include "glmAbstractBehavior.h"
#include "glmAbstractTrigger.h"
#include "glmICallBack.h"

namespace glm
{
    class GLM_SDK_API AbstractUserBehavior : public AbstractBehavior
    {
    public:
        glm::Array<ICallBack::SP> _initialStateCallBacks;
        glm::Array<ICallBack::SP> _finalStateCallBacks;

    private:
        AbstractTrigger::SP _startingCondition;
        glm::Array<AbstractTrigger::SP> _stoppingConditions;

    public:
        GLM_ABSTRACTCLASS_STAT_ID( glm::MemoryStatIds::Simulation)

        virtual ~AbstractUserBehavior();

        unsigned int addNext(AbstractBehavior* next, const AbstractTrigger::SP& condition);
        virtual unsigned int addNext(AbstractBehavior* next);
        virtual void removeNext(unsigned int next);
        virtual void clearNexts();

        inline const AbstractTrigger::SP& getStartingCondition() const;
        void setStartingCondition(const AbstractTrigger::SP& condition);
        inline const glm::Array<AbstractTrigger::SP>& getStoppingConditions() const;
        void setStoppingCondition(const AbstractTrigger::SP& condition, unsigned int next);

        virtual void allocate(BehaviorGraph& graph) override;
        virtual void deallocate() override;
        virtual void resize(BehaviorGraph& graph) override;
        virtual void init(BehaviorGraph& graph) override;
        virtual void finish(BehaviorGraph& graph) override;
        virtual void init(int64_t index, BehaviorGraph& graph) override;
        virtual void finish(int64_t index, BehaviorGraph& graph) override;
        virtual void update(int64_t index, BehaviorGraph& graph, Time dt) override;
        virtual void requestStart(int64_t index, BehaviorGraph& graph) override;
        virtual void requestStop(int64_t index, BehaviorGraph& graph, unsigned int next = _nextInvalidId) override;

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

    protected:
        // cloning
        friend class CloneFactory;
        virtual void cloneImpl(AbstractBehavior* clone, CloneFactory* factory) const override;
        inline virtual AbstractUserBehavior* create() const override;

        AbstractUserBehavior();

        inline virtual void doAllocate(BehaviorGraph& /*graph*/);

        inline virtual void doDeallocate();

        inline virtual void doResize(BehaviorGraph& /*graph*/);

        inline virtual void doInit(BehaviorGraph& /*graph*/);

        inline virtual void doFinish(BehaviorGraph& /*graph*/);

        inline virtual void doInit(int64_t /*index*/, BehaviorGraph& /*graph*/);

        inline virtual void doFinish(int64_t /*index*/, BehaviorGraph& /*graph*/);

        inline virtual void doStart(int64_t /*index*/, BehaviorGraph& /*graph*/);

        virtual void doUpdate(int64_t /*index*/, BehaviorGraph& /*graph*/, Time /*dt*/);

        inline virtual ResultStatus::Value doStop(int64_t /*index*/, BehaviorGraph& /*graph*/, Time /*dt*/);

        inline virtual void onRequestStart(int64_t /*index*/, BehaviorGraph& /*graph*/);

        inline virtual void onRequestStop(int64_t /*index*/, BehaviorGraph& /*graph*/);
    };
    //-------------------------------------------------------------------------
    inline void AbstractUserBehavior::doAllocate(BehaviorGraph& /*graph*/)
    {
    }

    //-------------------------------------------------------------------------
    inline void AbstractUserBehavior::doDeallocate()
    {
    }

    //-------------------------------------------------------------------------
    inline void AbstractUserBehavior::doResize(BehaviorGraph& /*graph*/)
    {
    }

    //-------------------------------------------------------------------------
    inline void AbstractUserBehavior::doInit(BehaviorGraph& /*graph*/)
    {
    }

    //-------------------------------------------------------------------------
    inline void AbstractUserBehavior::doFinish(BehaviorGraph& /*graph*/)
    {
    }

    //-------------------------------------------------------------------------
    inline void AbstractUserBehavior::doInit(int64_t /*index*/, BehaviorGraph& /*graph*/)
    {
    }

    //-------------------------------------------------------------------------
    inline void AbstractUserBehavior::doFinish(int64_t /*index*/, BehaviorGraph& /*graph*/)
    {
    }

    //-------------------------------------------------------------------------
    inline void AbstractUserBehavior::doStart(int64_t /*index*/, BehaviorGraph& /*graph*/)
    {
    }

    //-------------------------------------------------------------------------
    inline void AbstractUserBehavior::doUpdate(int64_t /*index*/, BehaviorGraph& /*graph*/, Time /*dt*/)
    {
    }

    //-------------------------------------------------------------------------
    inline AbstractBehavior::ResultStatus::Value AbstractUserBehavior::doStop(int64_t /*index*/, BehaviorGraph& /*graph*/, Time /*dt*/)
    {
        return ResultStatus::SUCCESS;
    }

    //-------------------------------------------------------------------------
    inline void AbstractUserBehavior::onRequestStart(int64_t /*index*/, BehaviorGraph& /*graph*/)
    {
    }

    //-------------------------------------------------------------------------
    inline void AbstractUserBehavior::onRequestStop(int64_t /*index*/, BehaviorGraph& /*graph*/)
    {
    }

    //-------------------------------------------------------------------------
    inline const AbstractTrigger::SP& AbstractUserBehavior::getStartingCondition() const
    {
        return _startingCondition;
    }

    //-------------------------------------------------------------------------
    inline const glm::Array<AbstractTrigger::SP>& AbstractUserBehavior::getStoppingConditions() const
    {
        return _stoppingConditions;
    }

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