#ifndef MEDIA_STREAM_HANDLER_H_
#define MEDIA_STREAM_HANDLER_H_

#ifdef WIN32
#include <winsock2.h> // struct timeval
#else
#include <sys/time.h>
#endif
#include <string>
#include <map>

// Specific error codes                                                                                                                              
#define ERTCPTIMEOUT          10000
#define EENDOFSTREAM          10001
#define EMEDIAFORMATCHANGED   10002
#define EUNKNOWNSTREAMTYPE    10003
#define EENDOFCHUNK           10004
#define EENDOFARCHIVE         10005
#define EINTERNALERROR        10100

struct vn_player_recording_status_t;

namespace videonext { namespace media {

    enum STREAM_STATE  { IDLE,             /// initial state, or timeout occured if PLAY_* status was previous state                          
            	         PLAY_FROM_SERVER, /// playing stream from server 
                         PLAY_FROM_BUFFER, /// playing stream from cache
                         STOPPED,          /// player stopped
                         OPENING,          /// establishing connect
                         BUFFERING,        /// buffering stream
                         OPENED            /// stream successful opened
                       };

    enum STREAM_TYPE {AUDIO, VIDEO, DATA, UNKNOWN};

    enum PIXEL_FORMAT {PIX_NONE, PIX_YUV420P, PIX_RGB24, PIX_RGB32, PIX_BGR32};

    enum DECODER_TYPE {DECODER_NONE, DECODER_HW, DECODER_SW_MT, DECODER_SW};

    enum FRAME_BUFFERS_NUM {
        SINGLE_BUF = 1,
        DOUBLE_BUF,
        TRIPLE_BUF
    };

    struct ResultStatus
    {
       ResultStatus(
              int _errorCode = 0,
              const std::string &_errorString = std::string()) 
          : errorCode(_errorCode), errorString(_errorString)
       {}

       int errorCode;
       std::string errorString;
    };

    struct StreamInfo
    {
       STREAM_TYPE type;

       unsigned streamId;

       std::string RTPCodecStr; /// see [RFC3551]

       // make sense for audio streams only
       unsigned samplingFreq;
       unsigned bitsPerSample;
       unsigned numChannels;

       /**
        * Optional config data
        */
       unsigned char *configData;

       unsigned configDataSize;

       unsigned duration; // in milliseconds

       std::map<std::string, std::string> metadata;
    };

    struct CacheBoundaries
    {
        timeval begin;
        timeval end;
    };

    struct Frame
    {
       /**
        * Actually tells from what stream we have frame.
        * See: MediaStreamHandler::newStream
        */
       StreamInfo *streamInfo;

       /**
        * Pointer to picture planes (if video frame) or to audio samples.
        * Audio samples and "single" plain video frames (RGB) stored in data[0]
        */
       unsigned char *data[4];

       unsigned dataSize[4];

       /**
        * Frame width, 0 - if unknown
        */
       unsigned width;

       /**
        * Frame height, 0 - if unknown 
        */
       unsigned height;

       /**
        * Display aspect ratio
        */
       float dar; 

       /**
        * Time when frame was recorder from DVR.
        * Can be equal to PTS when receiving "live" media, and different in "archive" mode.
        */
       timeval *capturedTime;

       /**
        * Objects tracking data in binary format
        */
       std::string objectsData;
    };

    struct Report
    {
        Report()
            : streamInfo(0), jitter(0), bandwith(0), qfactor(0)
        {}
        StreamInfo *streamInfo;

        unsigned jitter;   /// in microseconds
        unsigned bandwith; /// bandwith in KBytes/s since last report
        unsigned qfactor; 
    };

    struct MediaStreamHandler
    {
        /**
         * Invokes for every new frame. Video and audio frames may be decoded here.
         * Tracked objects may be included in the frame.
         */
        virtual void newFrame(const Frame &, const CacheBoundaries &, int buf_num = 0) = 0;

        /**
         * Invokes when buffer's (cache's) boundaries have been changed         
         */
        virtual void bufferChanged(const CacheBoundaries &) = 0;  

        /**
         * Notifies client when player changes its state         
         */
        virtual void stateChanged(STREAM_STATE, const ResultStatus &) = 0;

        /**
         * New RTP stream was added         
         * @param StreamExtraInfo usefull to obtain additional stream params 
         */
        virtual void newStream(const StreamInfo &) = 0; 

        /**
         * Steam was removed. (RTCP BYE was received, etc..)                  
         */
        virtual void removeStream(const StreamInfo &) = 0; 

        /**
         * New RTP report
         */
        virtual void newReport(const Report &) = 0;

        /**
         * Create buffer to render image. Optional. If NULL is returned - buffer will be created by framework.
         * Buffer should be freed only after MediaProducer destroyed
         * 
         * @param width   Image width
         * @param height  Image height
         * @param dar     Display aspect ratio
         * @param buf_num Number of frame buffers created
         */
        virtual void* createImageBuffer(int width, int height, float dar, FRAME_BUFFERS_NUM& buf_num) = 0;

        virtual int  lockImageBuffer(int buf_num = 0) = 0;

        virtual void unlockImageBuffer(int buf_num = 0) = 0;

        virtual void recordingStatusChanged(const vn_player_recording_status_t &status) = 0;

        /**
         * Logging internal state
         */
        virtual void log(const char *msg) = 0;
    };

}};

#endif /*MEDIA_STREAM_HANDLER_H_*/
