/**
 * @file Demultiplexer.h
 *
 */

#pragma once

#include "mpeg2/ts/Header.h"
#include "mpeg2/ts/PAT.h"
#include "mpeg2/ts/PMT.h"
#include "mpeg2/ts/SDT.h"
#include "mpeg2/ts/EIT.h"

#ifdef _WIN32
#include <windows.h>
#define MPEG2_MUTEX                 CRITICAL_SECTION
#define MPEG2_MUTEX_INIT            InitializeCriticalSection(&_lock)
#define MPEG2_MUTEX_DESTROY         DeleteCriticalSection(&_lock)
#define MPEG2_LOCK                  DeleteCriticalSection(&_lock)
#define MPEG2_UNLOCK                LeaveCriticalSection(&_lock)
#else
#include <pthread.h>
#define MPEG2_MUTEX                 pthread_mutex_t
#define MPEG2_MUTEX_INIT            pthread_mutex_init(&_lock, NULL)
#define MPEG2_MUTEX_DESTROY         pthread_mutex_destroy(&_lock)
#define MPEG2_LOCK                  pthread_mutex_lock(&_lock)
#define MPEG2_UNLOCK                pthread_mutex_unlock(&_lock)
#endif

namespace MPEG2
{
namespace TS
{

class Demultiplexer
{
public:
    enum
    {
        FLG_PAT     = 0x00000001,
        FLG_SDT     = 0x00000002,
        FLG_EIT     = 0x00000004,
    };
    class Listener
    {
    public:
        virtual void detect(SDT *sdt) = 0;
        virtual void detect(EIT *eit) = 0;
    };

private:
    MPEG2_MUTEX     _lock;
    uint32_t        _flag;
    Listener *      _listener;

    uint8_t _continuity_counter_sdt;
    SDT     _sdt;

    uint8_t _continuity_counter_0012;
    EIT     _eit_0012;

    uint8_t _continuity_counter_0026;
    EIT     _eit_0026;

    uint8_t _continuity_counter_0027;
    EIT     _eit_0027;

    void putSDT(Header *header, uint8_t *packet);
    void putEIT(Header *header, uint8_t *packet);


public:
    Demultiplexer();
    ~Demultiplexer();

    void setListener(Listener *listener);
    void setFlag(uint32_t flag, bool onoff);

    void put(uint8_t *buffer, uint32_t size);
};

} // TS
} // MPEG2
