#pragma once

#include "ros_bridge/include/TypeFactory.h"
#include "ros_bridge/include/CasePacker.h"
#include "ros_bridge/include/ComPrivateInclude.h"
#include "ros_bridge/include/RosBridgeClient.h"

#include <thread>
#include <deque>
#include <atomic>
#include <mutex>
#include <set>

namespace ROSBridge {
namespace ComPrivate {

class TopicPublisher
{
    typedef std::unique_ptr<std::thread> ThreadPtr;
public:

    TopicPublisher() = delete;
    TopicPublisher(CasePacker *casePacker,
                   RosbridgeWsClient *rbc);

    ~TopicPublisher();

    void start();
    void stop();
    template<class T>
    void publish(const T &msg, const std::string &topic){
        JsonDocUPtr docPtr(_casePacker->pack(msg, topic));
        publish(std::move(docPtr));
    }
    void publish(JsonDocUPtr docPtr){
        std::lock_guard<std::mutex> lock(_queueMutex);
        _queue.push_back(std::move(docPtr));
    }

private:
    JsonQueue           _queue;
    std::mutex          _queueMutex;
    std::atomic<bool>   _stopFlag;
    CasePacker         *_casePacker;
    ThreadPtr           _pThread;
    RosbridgeWsClient  *_rbc;
    HashSet            _advertisedTopicsHashList; // Not thread save! This container
                                                  // is manipulated by transmittLoop only!
};


void transmittLoop(const ROSBridge::CasePacker &casePacker,
                   RosbridgeWsClient &rbc,
                   ROSBridge::ComPrivate::JsonQueue &queue,
                   std::mutex &queueMutex,
                   HashSet &advertisedTopicsHashList,
                   const std::atomic<bool> &stopFlag);


} // namespace CommunicatorDetail
} // namespace ROSBridge
