#ifndef VN_WS_MEDIA_STREAM_PRODUCER_IMPL_H_
#define VN_WS_MEDIA_STREAM_PRODUCER_IMPL_H_

#include <map>
#include <queue>
#include "json/json.h"
#include "libwebsockets.h"

#include "RTSPMediaStreamProducerImpl.h"

namespace videonext { namespace media {

/**
 * WebSocket media producer
 */
class WebSocketMediaStreamProducerImpl : public RTSPMediaStreamProducerImpl
{
public:
    WebSocketMediaStreamProducerImpl(MediaStreamHandler *mediaStreamHandler, const std::string &url,
                                     unsigned cacheSize, unsigned streamId,
                                     unsigned bufferLen /*in msec*/, float speed = 1.f);

    virtual ~WebSocketMediaStreamProducerImpl();

public:

    // Redefined virtual functions
    virtual void open();

    virtual void pause();

    virtual void setStepMode(bool value) {}

    virtual void setPlayDirection(int value) {}

    virtual void moveToTimestamp(time_t time) { jumpToTimestamp(time); }

    virtual void teardown() {stop();}

    virtual void jumpToTimestamp(int value, bool mark = true);

    virtual void setSpeed(float speed);

    virtual void muteAudio(bool mute);


protected:
    virtual void resume();
    void shutdown();

public:
    static int lws_protocol_callback(struct lws *wsi, enum lws_callback_reasons reason,
                                     void *user, void *in, size_t len);
    static void lws_log_callback(int level, const char *line);

private:
    int clientConnect(struct lws *wsi);
    int clientInit();
    int clientPlay();
    int clientPause();
    int clientJump();
    int clientSetSpeed();

    static void incomingDataHandler(WebSocketMediaStreamProducerImpl* src, int mask);
    int clientReceive(const char *in, size_t len);

private:
    virtual void noteLiveness() {}

private:
    static void lwsTask(void* );


private:
    Json::Value lastRequest_;
    std::queue<Json::Value> requests_;

    std::map<std::string, std::string> requestParams_;
    TaskToken lwsServiceTask_;
    struct lws_context *wsiContext_;

    time_t jumpToTimestamp_;

    int fd_;
    float speed_;
    struct timeval pts_;
    unsigned hevc_vconf_size_;
    unsigned char* hevc_vconf_;

    struct lws_protocols protocols_[2];

    FrameConsumer *sinks_[2];

    struct TimevalSort
    {
        bool operator()(const struct timeval& ltv, const struct timeval& rtv) const
        {
            return (ltv.tv_sec == rtv.tv_sec && ltv.tv_usec < rtv.tv_usec) ||
                    ltv.tv_sec < rtv.tv_sec;
        }
    };
    typedef std::map<const struct timeval, std::string, TimevalSort> OBJECTS_DATA_ASCENDING;
    OBJECTS_DATA_ASCENDING objectsData_;
    bool cloud_;
    bool audioMuted_;
};

}}


#endif /*VN_WS_MEDIA_STREAM_PRODUCER_IMPL_H_*/
