#pragma once

#include "ros_bridge/rapidjson/include/rapidjson/document.h"
#include "ros_bridge/include/CasePacker.h"
#include "ros_bridge/include/TypeFactory.h"
#include "ros_bridge/include/JsonFactory.h"
#include "ros_bridge/include/TopicPublisher.h"
#include "ros_bridge/include/TopicSubscriber.h"

#include <memory>
#include <tuple>

#include "boost/lockfree/queue.hpp"

namespace ROSBridge {
class ROSBridge
{
public:    
    typedef MessageTag Tag;
    typedef rapidjson::Document JsonDoc;
    typedef std::unique_ptr<JsonDoc> JsonDocUPtr;

    explicit ROSBridge();

    template<class T>
    void publish(T &msg, const std::string &topic){
        _topicPublisher.publish(msg, topic);
    }
    void publish(JsonDocUPtr doc);

    void subscribe(const char *topic, const std::function<void(JsonDocUPtr)> &callBack);

    const CasePacker *casePacker() const;

    //! @brief Start ROS bridge.
    void start();
    //! @brief Stops ROS bridge.
    void reset();
    //! @return Returns true if connected to the rosbridge_server, false either.
    //! @note This function can block up to 100ms. However normal execution time is smaller.
    bool connected();

private:
    TypeFactory             _typeFactory;
    JsonFactory             _jsonFactory;
    CasePacker              _casePacker;
    RosbridgeWsClient       _rbc;
    std::mutex              _rbcMutex;
    ComPrivate::TopicPublisher     _topicPublisher;
    ComPrivate::TopicSubscriber    _topicSubscriber;

};
}
