//
// Created by Ht on 2020/5/8.
//

#ifndef TESTBIN_SOCKETCLIENT_H
#define TESTBIN_SOCKETCLIENT_H

#include <atomic>
#include <string>
#include <utility>
#include <qlibc/QObjectEventHolder.h>

#include "ChannelOperator.h"
#include "MgDataChannel.h"
#include "qlibc/httplib.h"

namespace jedge {

    static const char* DATA_CHANNEL_SOCK = "sock";
    static const char* vkey_sock_client_id_ = "client_id";
    static const char* vkey_sock_client_uri_ = "client_uri";

    static const char* sval_event_disconnect = "onDisconnect";

#define GetClientIDFromMessage(msg) \
    (msg).getString(vkey_sock_client_id_)

    using SocketClientOfflineHandler = JE_API std::function<bool(ChannelOperator & opr, const std::string& host, int port, SocketMode mode)>;

    class JE_API SocketClient :
            public MgDataChannel,
            public qlibc::QObjectEventHolder  {
    protected:
        socket_t sock_;
        std::shared_ptr<httplib::detail::SocketStream> sockst_;
        std::string host_;
        int port_ = 0;
#ifdef CYGWIN
        char sec_code_[16];
#endif
        time_t timeout_sec_ = 300;
        std::string interface_;

        bool active_ = false;
        bool quit_ = false;
        bool mb_print_income_ = false;

        std::recursive_mutex write_mutex_;

        std::mutex      quit_mutex_;
        std::condition_variable
                quit_wait_;

        SocketMode mode_ = typeUDP;

        SocketClientOfflineHandler* offline_handler_ = nullptr;     //掉线触发器

    public:
        explicit SocketClient(ChannelOperator& opr , std::string  moduleName);

        ~SocketClient() override {
            releaseEventHandlers();
            close();
            delete offline_handler_;
        }

        void close();

        //当前，同时只能启动其中一个链接
        bool start_tcp(const std::string &host, int port);
        //当前，同时只能启动其中一个链接
        bool start_udp(const std::string &host, int port);

        bool postRawMessage(qlibc::QData &message) override;

        SocketMode mode();

        void setOfflineHandler(const SocketClientOfflineHandler& handler) {
            if(offline_handler_==nullptr) offline_handler_ = new SocketClientOfflineHandler;
            *offline_handler_ = handler;
        }

        bool isActive(){
            return active_;
        }

    protected:
        void read_json_tcp();

        void read_json_rpc_from_udp();

        virtual bool handleSocketData(const char *buff, int len, SocketMode mode);

        bool postMessage(const char *buff, int len);

        bool postMessage(const std::string& buff);

        bool postUdpData(const char *host, int port, const char *buff, int len);

    public:
        void close_socket();

        bool postTcpData(const char *buff, int len);

        virtual void setPrintIncomingStr(bool print = true);

        bool isPrintIncomeingStr();

        bool isQuitting();
    };
}

#endif //TESTBIN_SOCKETCLIENT_H
