/**
 * @file EIT.cpp
 *
 */

#include "b25/aribstr.h"
#include "mpeg2/ts/EIT.h"

namespace MPEG2
{
namespace TS
{

EIT::EIT()
{
    reset();
}

EIT::EIT(EIT &eit)
{
    _table_id                    = eit._table_id;
    _section_syntax_indicator    = eit._section_syntax_indicator;
    _section_length              = eit._section_length;
    _service_id                  = eit._service_id;
    _version_number              = eit._version_number;
    _current_next_indicator      = eit._current_next_indicator;
    _section_number              = eit._section_number;
    _last_section_number         = eit._last_section_number;
    _transport_stream_id         = eit._transport_stream_id;
    _original_network_id         = eit._original_network_id;
    _segment_last_section_number = eit._segment_last_section_number;
    _last_table_id               = eit._last_table_id;
    _event_offset                = eit._event_offset;
    _length                      = eit._length;
    memcpy(_event_data, eit._event_data, sizeof(_event_data));
}

EIT::~EIT()
{
    reset();
}

bool EIT::decode_section()
{
    bool result = false;

    _table_id = _section[0x00];
    if ((TABLE_ID_SELF <= _table_id) && (_table_id <= TABLE_ID_OTHER_SCHEDULE_END))
    {
        _section_syntax_indicator    = (_section[0x01] & 0x80) >> 7;
        _section_length              = ((_section[0x01] << 8) + _section[0x02]) & 0x0FFF;
        _service_id                  = (_section[0x03] << 8) + _section[0x04];
        _version_number              = (_section[0x05] & 0x3E) >> 1;
        _current_next_indicator      = _section[0x05] & 0x01;
        _section_number              = _section[0x06];
        _last_section_number         = _section[0x07];
        _transport_stream_id         = (_section[0x08] << 8) + _section[0x09];
        _original_network_id         = (_section[0x0a] << 8) + _section[0x0b];
        _segment_last_section_number = _section[0x0c];
        _last_table_id               = _section[0x0d];

        if (GetCrc32(_section, _section_length + 3) == 0)
        {
            memcpy(_event_data, &_section[0x0e], _section_length - 3 - 11);
            _event_offset = 0;
            result = true;
        }
    }

    return result;
}

void EIT::reset()
{
    _table_id = 0;
    _section_length = 0;
    _event_offset = 0xFFFF;
}

EIT::Event *EIT::nextEvent()
{
    if ((_event_offset >= 0x00) && (_event_offset + 0x0c < _section_length - 0x0e))
    {
        _event._event_id = (_event_data[_event_offset] << 8) + _event_data[_event_offset + 0x01];

        // start_time
        uint16_t mjd = (_event_data[_event_offset + 0x02] << 8) + _event_data[_event_offset + 0x03];
        _event._st_year  = (uint16_t)((mjd - 15078.2) / 365.25);
        _event._st_month = (uint8_t)((mjd - 14956.1 - (uint16_t)(_event._st_year * 365.25)) / 30.6001);
        _event._st_day   = mjd - 14956 - (uint16_t)(_event._st_year * 365.25) - (uint8_t)(_event._st_month * 30.6001);
        if ((_event._st_month == 14) || (_event._st_month == 15))
        {
            _event._st_year += 1901;
            _event._st_month -= 13;
        }
        else
        {
            _event._st_year += 1900;
            _event._st_month -= 1;
        }
        _event._st_hour = ((_event_data[_event_offset + 0x04] & 0xF0) >> 4) * 10 + (_event_data[_event_offset + 0x04] & 0x0F);
        _event._st_min  = ((_event_data[_event_offset + 0x05] & 0xF0) >> 4) * 10 + (_event_data[_event_offset + 0x05] & 0x0F);
        _event._st_sec  = ((_event_data[_event_offset + 0x06] & 0xF0) >> 4) * 10 + (_event_data[_event_offset + 0x06] & 0x0F);

        // duration
        _event._dur_hour = ((_event_data[_event_offset + 0x07] & 0xF0) >> 4) * 10 + (_event_data[_event_offset + 0x07] & 0x0F);
        _event._dur_min  = ((_event_data[_event_offset + 0x08] & 0xF0) >> 4) * 10 + (_event_data[_event_offset + 0x08] & 0x0F);
        _event._dur_sec  = ((_event_data[_event_offset + 0x09] & 0xF0) >> 4) * 10 + (_event_data[_event_offset + 0x09] & 0x0F);

        _event._running_status = (_event_data[_event_offset + 0x0a] & 0xE0) >> 5;
        _event._free_CA_mode = (_event_data[_event_offset + 0x0a] & 0x10) >> 4;
        _event._descriptors_loop_length = ((_event_data[_event_offset + 0x0a] & 0x0F) << 8) + _event_data[_event_offset + 0x0b];

        if (_event_offset + 0x0c + _event._descriptors_loop_length <= _section_length)
        {
            _event._descriptor_ptr = &_event_data[_event_offset + 0x0c];
            _event._descriptor_offset = 0;
            _event_offset += (0x0c + _event._descriptors_loop_length);

            return &_event;
        }
    }

    _event._event_id = 0;
    _event._descriptors_loop_length = 0;
    return NULL;
}

Descriptor *EIT::Event::nextDescriptor()
{
    if (_descriptors_loop_length >= 2)
    {
        uint16_t len = Table::parseDescriptor(&_descriptor_ptr[_descriptor_offset], _descriptors_loop_length, &_descriptor);
        if (len != 0)
        {
            _descriptor_offset += len;
            _descriptors_loop_length -= len;
            return &_descriptor;
        }
    }
    return NULL;
}

} // TS
} // MPEG2
