//
// Created by Ht on 2021/2/6.
//

#ifndef LIBDEVCPP_QCMDNSCLIENT_H
#define LIBDEVCPP_QCMDNSCLIENT_H

#include <cmdnsc/cmdns.h>
#include <jebase/config.h>
#include <string>
#include <qlibc/QTimerEngine.h>
#include <qlibc/QPObjectHolder.h>

namespace jedge {

    static const char* vkey_subnet_config_ = "subnet";
    static const char* vkey_cmdns_host_ = "cmdns_addr";
    static const char* vkey_cmdns_port_ = "cmdns_port";
    static const char* vkey_cmdns_priority_ = "priority";

    using QCMDnsServiceHandler = std::function<void(CMdnsServiceQueried services[], int svc_cnt, const char* ip, int port)>;

    class JE_API QCMDnsClient {
    protected:
        httplib::ThreadPool &pool_;
        qlibc::QTimerEngine  &timers_;
        CMDns* cmDns = nullptr;
        qlibc::QSharedObjectHolder<QCMDnsServiceHandler>    service_found_hanlders_;
        qlibc::QSharedObjectHolder<qlibc::QRTimer>          stop_timers_;
        qlibc::QPObjectHolder<CMDnsServiceQuery>            queries_;       //不做动态内存管理，queries的存储管理在cmdns中
        std::recursive_mutex  opr_mutex_;
        bool   quitting_ = false;

    public:
        explicit QCMDnsClient(httplib::ThreadPool& pool, qlibc::QTimerEngine& engine);

        virtual ~QCMDnsClient();

        /**
         *  查询服务、持续多少秒，查询到最新的版本。
         * @param handler       命中后的回调函数
         * @param type          tcp/udp
         * @param key           mgbus/gaffic, etc.
         * @param subnet        查询的子网，如#0
         * @param ttl           单次查询间隔秒数
         * @param qtype         查询类型： t-只返回优先级最高的服务端口， a-返回所有服务端口， k-只返回符合选择关键字的服务版本
         * @param dureSecs      查询持续时间，默认为60S。
         * @return
         */

        bool queryForHost(const QCMDnsServiceHandler& handler, const std::string& type, const std::string& key, const std::string &subnet = "", int ttl = 10 * 1000, const std::string& qtype = "a" , int dureMilliSecs = 5000);

        /**
         *  手动停止查询
         * @param key   停止的key
         */
        void stopHostQuery(const std::string &key);

        /**
         *
         * @param handler       命中后的回调函数
         * @param type          tcp/udp
         * @param key           mgbus/gaffic, etc.
         * @param subnet        查询的子网，如#0,
         * @param ttl           单次查询间隔秒数
         * @return
         */
        const std::string*
        watchForHost(const QCMDnsServiceHandler& handler, const std::string& type, const std::string& key,
                     const std::string &subnet = sval_default_cmdns_subnet_open_, int ttl = 60 * 1000);

        /**
         *  停止监听指定服务
         * @param key   指定服务的key
         */
        void stopWatch(const std::string& key);

        /**
          *
          * @param type          tcp/udp
          * @param key           msg/gaffic, etc.
          * @param port          服务端口
          * @param comment       服务备注
          * @param priority      优先级、1000
          * @param ttl           服务通知生存周期，默认180S
          * @return
          */
        CMDnsServicePublish * publishService(const std::string& type, const std::string& key,int port, const std::string &subnet = "", const std::string& comment = "", int priority = ival_default_cmdns_priority, int ttl = ival_default_cmdns_ttl);

        void withDrawServicePublish(CMDnsServicePublish *publish);

        virtual void onServiceFound(const CMdnsServiceQueried services[], int svc_cnt, const char* ip, int port);

        void clearCMDnsStacks();

        void setupMulticastAddress(const std::string &addr, int port);

    };

}


#endif //LIBDEVCPP_QCMDNSCLIENT_H
