#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>
#include <condition_variable>

namespace ROSBridge {
namespace ComPrivate {

struct ThreadData;

class TopicPublisher
{
    typedef std::unique_ptr<std::thread> ThreadPtr;
    using CondVar = std::condition_variable;
public:

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

    ~TopicPublisher();

    //! @brief Starts the publisher.
    void start();

    //! @brief Resets the publisher.
    void reset();

    void publish(JsonDocUPtr docPtr){
        {
        std::lock_guard<std::mutex> lock(_queueMutex);
        _queue.push_back(std::move(docPtr));
        }
        _cv.notify_one();  // Wake publisher thread.
    }

    template<class T>
    void publish(const T &msg, const std::string &topic){
        JsonDocUPtr docPtr(_casePacker.pack(msg, topic));
        publish(std::move(docPtr));
    }

private:
    JsonQueue           _queue;
    std::mutex          _queueMutex;
    std::atomic<bool>   _running;
    CasePacker         &_casePacker;
    RosbridgeWsClient  &_rbc;
    CondVar             _cv;
    ThreadPtr           _pThread;
};


void transmittLoop(ThreadData data);


} // namespace CommunicatorDetail
} // namespace ROSBridge
