//
// Created by Ht on 2022/10/2.
//

#ifndef INC_1_LIBDEVCPP_QGACONTROLLERUTIL_H
#define INC_1_LIBDEVCPP_QGACONTROLLERUTIL_H

#include <qlibc/qlibc.h>
#include <exlib/QJAServer.h>

namespace jedge {

    class JE_API QGaDataActionBase {
    public:
        virtual void parseParam(Json::Value& ret, const std::string& src, const qlibc::QData* msg) = 0;

        virtual bool runActionStopIfFail(qlibc::QData *req, qlibc::QData *resp) = 0;

        virtual bool runThisAction(qlibc::QData *req, qlibc::QData *resp) = 0;

        virtual bool checkCondition(qlibc::QData *req, qlibc::QData *resp) = 0;

        virtual const std::string& getPathKey() = 0;
    };

    class QGaDataActionController;

    using QGaControllerHandler = std::function<bool(QGaDataActionController* ctrl, qlibc::QData* req, qlibc::QData* resp)>;

    class JE_API QGaDataActionController : public qlibc::QData {
    protected:
        const QGaControllerHandler* handler_;

    public:
        QJAMgServer& ctx_;
        QGaDataActionBase& base_;
        qlibc::QRTimer timer;
        qlibc::QData *newReq = nullptr, *newResp = nullptr;

        std::recursive_mutex m_;
        std::mutex wm_;
        std::condition_variable w_;
        bool quit_ = false;

        explicit QGaDataActionController(QJAMgServer& ctx, QGaDataActionBase& base, const QGaControllerHandler& execBody) : handler_(new QGaControllerHandler(execBody)), ctx_(ctx), base_(base) {
        }

        bool runDataAction (qlibc::QData* req, qlibc::QData* resp) {
            return (handler_!= nullptr) && (*handler_)(this, req, resp);
        }

        void stopControl() {
            RECURSIVE_LOCK(m_);
            quit_ = true;
            if(timer!= nullptr) {
                ctx_.timerEngine().stopTimer(timer);
                timer = nullptr;
            }

            if(newReq!= nullptr) {
                ctx_.releaseMessage(newReq);
            }

            if(newResp!= nullptr) {
                ctx_.releaseMessage(newResp);
            }
            SINGLE_LOCK(wm_);
            w_.notify_all();
        }

        void initDataWith(QData *req, QData *resp) {
            RECURSIVE_LOCK(m_);
            if(newReq!= nullptr)
                newReq->clear();
            else
                newReq = ctx_.getBlankMessage();
            if(req!= nullptr)
                newReq->copyData(*req);
            if(newResp!= nullptr)
                newResp->clear();
            else
                newResp = ctx_.getBlankMessage();
            if(resp!= nullptr)
                newResp->copyData(*resp);
        }
    };
    using QGaDataActionControllerR = std::shared_ptr<QGaDataActionController>;

    using QGaDataActionControllerCreator = std::function<QGaDataActionController*(
            QJAMgServer& ctx, QGaDataActionBase &action, const std::string& ctrlKey, QStringList& params, const qlibc::QData* msg)>;

    class JE_API QGaControllerUtil {
    protected:
        qlibc::QPObjectHolder<QGaDataActionControllerCreator> creators_;
        explicit QGaControllerUtil();

    public:

        static QGaControllerUtil& instance();

        //添加一个controller的创建对象
        void addDataActionController(const std::string& ctrlKey, const QGaDataActionControllerCreator& creator);

        //创建一个controller
        QGaDataActionController* createController(QJAMgServer& ctx, QGaDataActionBase &action, const std::string& controller, const qlibc::QData* msg);
    };

#define DAControllerLamda(_c,_r,_s) (QGaDataActionController* (_c), qlibc::QData* (_r), qlibc::QData* (_s))->bool
#define DAControllerCreator(_ctx,_ac,_ck,_pm,_mg) (QJAMgServer& (_ctx), QGaDataActionBase &(_ac), const std::string& (_ck), QStringList& (_pm), const qlibc::QData* (_mg))->QGaDataActionController*

#define GaoActionControllerCreatorName(_t) createFor##_t
#define GaoActionRunnerName(_t) _t##Runner

#define bindGAOActionController(_t) \
       QGaControllerUtil::instance().addDataActionController(#_t, [this]DAControllerCreator(ctx,ac,ck,pm,mg) {\
            return GaoActionControllerCreatorName(_t)(ctx,ac,ck,pm,mg); \
       })
#define implGAOActionControllerCreator(_t,_ctx,_ac,_ck,_pm,_mg) \
        GaoActionControllerCreatorName(_t)(QJAMgServer &(_ctx), QGaDataActionBase &(_ac), const string &(_ck), QStringList &(_pm), const qlibc::QData* (_mg))

#define implGAOActionRunner(_t,_c,_r,_p) \
        GaoActionRunnerName(_t)(QGaDataActionController *(_c), qlibc::QData *(_r), qlibc::QData *(_p))

#define CreateControllerWithRunner(_t,_ctx,_ac) \
        new QGaDataActionController((_ctx), (_ac),\
            [](QGaDataActionController *_ctrl, qlibc::QData *_req, qlibc::QData *_resp) -> bool { \
            return GaoActionRunnerName(_t)(_ctrl, _req, _resp); \
        })
}

#endif //INC_1_LIBDEVCPP_QGACONTROLLERUTIL_H
