//
// Created by Ht on 2021/11/24.
//

#ifndef VDALUNIT2_QCLASSIFIEDQUEUE_H
#define VDALUNIT2_QCLASSIFIEDQUEUE_H

#include "jebase/config.h"
#include <qlibc/QData.hpp>
#include <qlibc/QPObjectHolder.h>
#include "SerialDevice.h"

#include <list>
#include <mutex>
#include <condition_variable>

namespace qlibc {

    static const char* vkey_classify_queue_default_key_ = "";
    static const int ival_default_safe_delay_ = 2;
    static const int ival_default_timeout_ = 20;

    using QDataPList = std::list<QData*>;
    using QDataPListVector = std::vector<QDataPList*>;
    using LevelMessageChecker = std::function<bool(QDataPListVector&,  unsigned char level, qlibc::QData*)>;
    using MessageReleaser = std::function<void(qlibc::QData*)>;

    class JE_API QClassifiedQueue {
    protected:
        bool quit_ = false;
        bool hi_pr_not_empty_ = false;

        unsigned char default_level_;
        unsigned char active_level_;
        unsigned char pending_level_;
        unsigned long wait_cnt_ = 0;    //500 count for common high to low level,  1000 for config to others
        unsigned long wait_gap_;  //20ms

        std::string   level_key_;

        qlibc::QPObjectHolder<unsigned char> key_order_;
        qlibc::QPObjectHolder<LevelMessageChecker>   checkers_;

        QDataPListVector         q_;
        std::vector<int>         to_;       //指令队列时间
        std::vector<int>         dl_;       //延迟

        MessageReleaser*         releaser_ = nullptr;

        std::mutex               m_;
        std::condition_variable  w_;
    protected:
        jedge::ChannelOperator&  operator_;
        std::mutex               wake_mutex_;
        std::mutex               mm_;
        std::condition_variable  wake_cond_;
        bool                     checking_ = true;
        jedge::SerialRootDevice               *root_;
        qlibc::QPObjectHolder<qlibc::QData>   confirmMessageMap_;
    public:
        explicit QClassifiedQueue(jedge::ChannelOperator& opr, const std::string &key_orders, std::string levelKey, unsigned long wait_gap = 100);
        virtual ~QClassifiedQueue() { delete releaser_; };

        unsigned char levelFromType(const std::string &key);

        qlibc::QData *retreiveMessage();
        void clearMessageQueue();
        void pushMessage(qlibc::QData *msg);

        void setLevelMessageChecker(const std::string& key,const LevelMessageChecker& checker);

        unsigned char lastLevel();

        unsigned char getActiveLevel();

        void resetActiveLevel();

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

        std::string makeMessageLog(const QData *msg);

        void setTimeout(const std::string &levelKey, int queue_timeout = ival_default_timeout_, int safe_delay = ival_default_safe_delay_);

        void setTimeouts(const qlibc::QData &timeoutDefs);

        void setMessageReleaser(const MessageReleaser& r);

    protected:

        unsigned char findNotEmptyLevel();

        bool checkQueuedMessages(unsigned char level, QData *msg);

        void makeMessageLog(std::string &msglog,const QData *msg);

        static void markTime(QData *msg);

        bool isMessageTimeout(unsigned char lv, QData *msg, int now);

        void clearTimeoutMessages();

        void releaseMessage(qlibc::QData *msg);

        static void makeTimeStr(char *tmark, time_t seconds);

    public:
        bool holdMessage(const std::string &device_id,QData &msg);
        bool checkAvailable();
        bool procCheck();
        bool pendMessage(QData *message);
        void setRoot(jedge::SerialRootDevice *r){
            root_ = r;
        }
        bool mergePendingQueue(QData *msg);
    };

}


#endif //VDALUNIT2_QCLASSIFIEDQUEUE_H
