#pragma once

#include <library/cpp/threading/atomic/bool.h>

#include <util/datetime/base.h>
#include <util/generic/ptr.h>
#include <library/cpp/deprecated/atomic/atomic.h>
#include <util/system/event.h>
#include <util/thread/factory.h>

namespace NFusion {

    class IThreadLoop : public IThreadFactory::IThreadAble
    {
    public:
        IThreadLoop(const TString& threadName);
        virtual ~IThreadLoop();

        void Start();
        void Stop();
        void Pause();
        void Resume();

        bool Stopped() const {
            return StopFlag;
        }

    protected:
        using TTimeToSleep = TDuration;

    protected:
        virtual void OnBeforeStart() = 0;
        virtual void OnAfterStart() = 0;
        virtual void OnBeforeStop() = 0;
        virtual void OnAfterStop() = 0;
        virtual void OnPause() = 0;
        virtual void OnResume() = 0;

        virtual TTimeToSleep DoIteration() = 0;
        virtual TTimeToSleep OnException() = 0;

    protected:
        // threadpool selector (for custom CPU scheduling)
        virtual IThreadFactory* GetThreadPool();

    private:
        // IThreadFactory::IThreadAble
        virtual void DoExecute() final;

    private:
        TString ThreadName;
        TManualEvent ResumeEvent;               // signal this event to resume a paused thread
        TAutoEvent WakeupEvent;                 // signal this event to awake a thread that sleeps between iterations
        NAtomic::TBool StopFlag;
        THolder<IThreadFactory::IThread> Thread;
    };
}
