/*
 *  Table.cpp
 */

#include "b25/aribstr.h"
#include "mpeg2/ts/Header.h"
#include "mpeg2/ts/Table.h"

namespace MPEG2
{
namespace TS
{

Table::Table()
{
    _pid = 0xFFFF;
    _length = 0;
}

Table::~Table()
{
}

//
// CRC
//
int Table::GetCrc32(
	unsigned char* data,				// [in]		CRC data
	int len)							// [in]		CRC data length
{
	int crc;
	int i, j;

	crc = 0xFFFFFFFF;
	for (i = 0; i < len; i++)
	{
		char x;
		x = data[i];

		for (j = 0; j < 8; j++)
		{
			int c;
			int bit;

			bit = (x >> (7 - j)) & 0x1;

			c = 0;
			if (crc & 0x80000000)
			{
				c = 1;
			}

			crc = crc << 1;

			if (c ^ bit)
			{
				crc ^= 0x04C11DB7;
			}

			crc &= 0xFFFFFFFF;
		}
	}

	return crc;
}

bool Table::decode(Header *header, uint8_t *packet)
{
    bool result = false;

    if (header->_adaptation_field_control != 0x02)
    {
        uint8_t offset = 0x04;
        if (header->_adaptation_field_control == 0x03)
        {
            offset = offset + packet[0x04];
        }

        if (header->_payload_unit_start)
        {
            if (_length != 0)
            {
                if (packet[offset] != 0)
                {
                    memcpy(&_section[_length], &packet[offset + 1], packet[offset]);
                    _length += packet[offset];
                }
                result = decode_section();
                _length = 0;
            }

            offset += (1 + packet[offset]);
        }

        memcpy(&_section[_length], &packet[offset], PACKET_SIZE - offset);
        _length += (PACKET_SIZE - offset);
    }

    return result;
}

void Table::reset()
{
    _pid = 0xFFFF;
    _length = 0;
    memset(_section, 0x00, sizeof(_section));
}

static uint16_t parseServiceDescriptor(uint8_t *buf, ServiceDescriptor *service)
{
    service->_descriptor_tag = buf[0];
    service->_descriptor_length = buf[1];
    service->_service_type = buf[2];
    service->_service_provider_name_length = buf[3];
    if (service->_service_provider_name_length > 0)
    {
        memcpy(service->_service_provider_name, &buf[4], service->_service_provider_name_length);
    }
    service->_service_name_length = buf[4 + service->_service_provider_name_length];
    if (service->_service_name_length > 0)
    {
        memcpy(service->_service_name, &buf[5 + service->_service_provider_name_length], service->_service_name_length);
    }
    return service->_descriptor_length + 2;
}

static uint16_t parseShortEventDescriptor(uint8_t *buf, ShortEventDescriptor *short_event)
{
    short_event->_descriptor_tag = buf[0];
    short_event->_descriptor_length = buf[1];
    memcpy(short_event->_ISO_639_language_code, &buf[2], 3);
    short_event->_event_name_length = buf[5];
    if (short_event->_event_name_length > 0)
    {
        memcpy(short_event->_event_name, &buf[6], short_event->_event_name_length);
    }
    short_event->_text_length = buf[6 + short_event->_event_name_length];
    if (short_event->_text_length > 0)
    {
        memcpy(short_event->_text, &buf[7 + short_event->_event_name_length], short_event->_text_length);
    }
    return short_event->_descriptor_length + 2;
}

static uint16_t parseExtendedEventDescriptor(uint8_t *buf, ExtendedEventDescriptor *extended)
{
    extended->_descriptor_tag = buf[0x00];
    extended->_descriptor_length = buf[0x01];
    extended->_descriptor_number = (buf[0x02] & 0xF0) >> 4;
    extended->_last_descriptor_number = buf[0x02] & 0x0F;
    memcpy(&extended->_ISO_639_language_code[0], &buf[0x03], 3);
    extended->_length_of_items = buf[0x06];
    extended->_item_count = 0;
    if ((extended->_length_of_items + 6) <= extended->_descriptor_length)
    {
        extended->_text_length = buf[extended->_length_of_items + 7];
        if ((extended->_text_length + extended->_length_of_items + 6) == extended->_descriptor_length)
        {
            memcpy(&extended->_text[0], &buf[extended->_length_of_items + 7], extended->_text_length);

            int item_remain = extended->_length_of_items;
            int item_offset = 0x07;
            while (item_remain >= 2)
            {
                extended->_items[extended->_item_count]._item_description_length = buf[item_offset++];
                if (extended->_items[extended->_item_count]._item_description_length > 0)
                {
                    memcpy(&extended->_items[extended->_item_count]._item_description[0], &buf[item_offset],
                           extended->_items[extended->_item_count]._item_description_length);
                    item_offset += extended->_items[extended->_item_count]._item_description_length;
                }
                item_remain -= (1 + extended->_items[extended->_item_count]._item_description_length);
                if (item_remain < 1)
                {
                    printf("%s item desc len error.\n", __FUNCTION__);
                    break;
                }
                
                extended->_items[extended->_item_count]._item_length = buf[item_offset++];
                if (extended->_items[extended->_item_count]._item_length > 0)
                {
                    memcpy(&extended->_items[extended->_item_count]._item[0], &buf[item_offset],
                           extended->_items[extended->_item_count]._item_length);
                    item_offset += extended->_items[extended->_item_count]._item_length;
                }
                item_remain -= (1 + extended->_items[extended->_item_count]._item_length);
                if ((item_remain < 0) || (item_remain == 1))
                {
                    printf("%s item len error. %d\n", __FUNCTION__, item_remain);
                    break;
                }

                ++extended->_item_count;
            }
        }
    }

    return extended->_descriptor_length + 2;
}

static uint16_t parseComponentDescriptor(uint8_t *buf, ComponentDescriptor *component)
{
    component->_descriptor_tag = buf[0];
    component->_descriptor_length = buf[1];

    return component->_descriptor_length + 2;
}

static uint16_t parseContentDescriptor(uint8_t *buf, ContentDescriptor *content)
{
    content->_descriptor_tag = buf[0];
    content->_descriptor_length = buf[1];
    for (int i = 0; i < (content->_descriptor_length / 2); ++i)
    {
        content->_contents[i]._content_nibble_level_1 = (buf[i * 2 + 0x02] & 0xF0) >> 4;
        content->_contents[i]._content_nibble_level_2 = buf[i * 2 + 0x02] & 0x0F;
        content->_contents[i]._user_nibble_1 = (buf[i * 2 + 0x03] & 0xF0) >> 4;
        content->_contents[i]._user_nibble_2 = buf[i * 2 + 0x03] & 0x0F;
    }
    return content->_descriptor_length + 2;
}

static uint16_t parseDigitalCopyControlDescriptor(uint8_t *buf, DigitalCopyControlDescriptor *digital_copy_control)
{
    digital_copy_control->_descriptor_tag = buf[0];
    digital_copy_control->_descriptor_length = buf[1];

    return digital_copy_control->_descriptor_length + 2;
}

static uint16_t parseAudioComponentDescriptor(uint8_t *buf, AudioComponentDescriptor *audio_component)
{
    audio_component->_descriptor_tag = buf[0];
    audio_component->_descriptor_length = buf[1];
    audio_component->_stream_content = buf[2] & 0x0F;
    audio_component->_component_type = buf[3];
    audio_component->_component_tag = buf[4];
    audio_component->_stream_type = buf[5];
    audio_component->_simulcast_group_tag = buf[6];
    audio_component->_ES_multi_lingual_flag = buf[7] >> 7;
    audio_component->_main_component_flag = (buf[7] >> 6) & 0x01;
    audio_component->_quality_indicator = (buf[7] >> 4) & 0x03;
    audio_component->_sampling_rate = (buf[7] >> 1) & 0x07;
    memcpy(audio_component->_ISO_639_language_code, &buf[8], 3);
    if (audio_component->_ES_multi_lingual_flag == 1)
    {
        memcpy(audio_component->_ISO_639_language_code_2, &buf[11], 3);
    }
    uint8_t cpylen = audio_component->_descriptor_length - (9 + audio_component->_ES_multi_lingual_flag * 3);
    memcpy(audio_component->_text_char, &buf[11 + audio_component->_ES_multi_lingual_flag * 3], cpylen);
    return audio_component->_descriptor_length + 2;
}

static uint16_t parseSeriesDescriptor(uint8_t *buf, SeriesDescriptor *series)
{
    series->_descriptor_tag = buf[0];
    series->_descriptor_length = buf[1];

    return series->_descriptor_length + 2;
}

uint16_t Table::parseDescriptor(uint8_t *buf, uint16_t length, Descriptor *descriptor)
{
    uint16_t result = 0;

    descriptor->_other._descriptor_tag    = buf[0x00];
    descriptor->_other._descriptor_length = buf[0x01];

    // length check
    if ((descriptor->_other._descriptor_length + 2) <= length)
    {
        switch (descriptor->_other._descriptor_tag)
        {
        case TAG_SERVICE_DESCRIPTOR:
            result = parseServiceDescriptor(buf, &descriptor->_service);
            break;

        case TAG_SHORT_EVENT_DESCRIPTOR:
            result = parseShortEventDescriptor(buf, &descriptor->_short_event);
            break;

        case TAG_EXTENDED_EVENT_DESCRIPTOR:
            result = parseExtendedEventDescriptor(buf, &descriptor->_extended_event);
            break;

        case TAG_COMPONENT_DESCRIPTOR:
            result = parseComponentDescriptor(buf, &descriptor->_component);
            break;

        case TAG_CONTENT_DESCRIPTOR:
            result = parseContentDescriptor(buf, &descriptor->_content);
            break;

        case TAG_DIGITAL_COPY_CONTROL_DESCRIPTOR:
            result = parseDigitalCopyControlDescriptor(buf, &descriptor->_digital_copy_control);
            break;

        case TAG_AUDIO_COMPONENT_DESCRIPTOR:
            result = parseAudioComponentDescriptor(buf, &descriptor->_audio_component);
            break;

        case TAG_SERIES_DESCRIPTOR:
            result = parseSeriesDescriptor(buf, &descriptor->_series);
            break;

        default:
            memcpy(&descriptor->_other._descriptor[0], &buf[0x02], descriptor->_other._descriptor_length);
            result = descriptor->_other._descriptor_length + 2;
            break;
        }
    }
    else
    {
        printf("%s() length = %d\n", __FUNCTION__, length);
        printf("%s() descriptor_tag = %d\n", __FUNCTION__, descriptor->_other._descriptor_tag);
        printf("%s() descriptor_length error. %d\n", __FUNCTION__, descriptor->_other._descriptor_length);
        result = 0;
//        abort();
    }
    return result;
}

} // TS
} // MPEG2
