//
// Created by Ht on 2022/3/2.
//
/**
 *  系统触发器的主要作用：
 *      利用一个独立线程、建立和维系一个系统触发器，利用条件函数为真时进行触发。
 *          触发时执行分为单词触发、在一定时间范围内多次触发执行动作等。
 *
 *
 */

#ifndef INC_1_LIBDEVCPP_QTRIGGER_H
#define INC_1_LIBDEVCPP_QTRIGGER_H

#include <condition_variable>
#include <utility>
#include "QPObjectHolder.h"
#include <cross/SystemUtil.h>
#include <qlibc/httplib.h>
#include <qlibc/QTimerEngine.h>

namespace qlibc {

    static const char* SYS_TRIGGER_PREFIX = "_TR";

    using QTriggerCallback = std::function<void()>;
    using QRTriggerCallback = std::shared_ptr<QTriggerCallback>;
    using QTriggerKeyCallback = std::function<void(const std::string& key)>;
    using QRTriggerKeyCallback = std::shared_ptr<QTriggerKeyCallback>;
    using QTriggerCondition = std::function<bool()>;
    using QRTriggerCondition = std::shared_ptr<QTriggerCondition>;

    class JE_API Syncer {
    protected:
        std::mutex m_;
        std::condition_variable c_;
    public:
        void waitForSignal(const QTriggerCondition& cond) {
            SINGLE_LOCK(m_);
            c_.wait_for(LOCKER_NAME(m_), std::chrono::milliseconds(10), [&cond] { return cond();});
        }

        void waitForSignal(){
            SINGLE_LOCK(m_);
            c_.wait(LOCKER_NAME(m_));
        }

        void markSignal() {
            SINGLE_LOCK(m_);
            c_.notify_one();
        }
        void markSignalForAll() {
            SINGLE_LOCK(m_);
            c_.notify_all();
        }
    };


    /**
     * 触发器：
     *
     */
    class JE_API QTrigger {
    protected:
        QRTriggerCondition  cond_;      //条件函数
        QRTriggerCallback   cb_;        //默认执行器
        QRTriggerKeyCallback cbk_;      //带key执行器
        qlibc::QRTimer      ext_;       //执行timer

        QRTimerEngine       te_;        //timer引擎

        //触发时间检查
        long freq_;     //检查频率
        const long freq_src_; //设定值
        long delay_;   //延迟检查
        long dur_; //需要持续执行
        const long dur_src_; //需要持续执行
        long gap_; //执行间隔
        bool overlay_:1;
        bool exec_:1;

        std::recursive_mutex trgm_;
    public:
        explicit QTrigger(QRTimerEngine te, const QTriggerCondition& cond, const QTriggerCallback& cb,
                          long freq, long delay,  long dur = -1, long gap = 1, bool overlay = false);

        explicit QTrigger(QRTimerEngine te, const QTriggerCondition& cond, const QTriggerKeyCallback& cb,
                          long freq, long delay,  long dur = -1, long gap = 1, bool overlay = false);

        void checkAndInvoke(const std::string& key);

        void trig(const std::string& key = "");

        void cancel();
    };


    /**
     *  触发器管理器
     */
    class JE_API QTriggerEngine : public QSelfRefObject {
    protected:
        std::string           engine_name_;
        httplib::RThreadPool  thread_pool_;
        qlibc::QRTimerEngine  timer_engine_;
        QSharedObjectHolder<QTrigger> triggers_;
        long    min_check_;
        unsigned short  start_ms_ = 0;
        Syncer  syncer_;
        bool    unique_pool:1;
        bool    active_:1;
        bool    quit_:1;

    public:
        explicit QTriggerEngine(httplib::RThreadPool pool, qlibc::QRTimerEngine engine, unsigned int minCheckFreq = 30);

        explicit QTriggerEngine(unsigned int minCheckFreq = 30);

        virtual ~QTriggerEngine();;

        void checkTriggers();

        bool startTriggers();

        void stopTriggers();

        const std::string &objId() override;

        /**
          *       系统触发器：
          *         各时间参数如小于最小检查时间单位，将自动取整。
          *
          * @param k             键值
          * @param cond          条件计算函数
          * @param cb            条件满足后的执行函数
          * @param freq          条件检查频率（默认1S）
          * @param delay         延迟检查时间（默认无延迟）
          * @param dur           触发持续时间（默认1次，如果为持续一定时间、则需要设置这段时间的执行频率gap参数，
          *                          如果处于已执行状态未停止、则后续触发可覆盖上次触发）
          * @param gap           反复执行的间隔时间（每次检查后默认执行一次，即，gap=dur）
          * @param overlay       两次触发时、第二次触发时是否中止上次触发的进程，如果是多次触发。仅在dur/gap有效时有效
          */

        auto addTrigger(const std::string& key, const qlibc::QTriggerCondition& cond, const qlibc::QTriggerCallback& cb,
                                      long freq = 1000, long delay = 0, long dur = -1, long gap = -1, bool overlay = false) -> const std::string&;

        //同上，执行回调函数格式不同
        auto addTrigger(const std::string& key, const qlibc::QTriggerCondition& cond, const qlibc::QTriggerKeyCallback& cb,
                                      long freq = 1000, long delay = 0, long dur = -1, long gap = -1, bool overlay = false) -> const std::string&;

        void clearTrigger(const std::string& key);
    };

    using QRTriggerEngine = std::shared_ptr<QTriggerEngine>;

}

#endif //INC_1_LIBDEVCPP_QTRIGGER_H
