#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <errno.h>
#include <getopt.h>
#include <stdarg.h>
#include <time.h>
#include <inttypes.h>
#include <assert.h>
#include <pthread.h>
#include <time.h>

#include "hx_debug.h"
#include "qw_util.h"
#include "AZBoxTVSDK_DEF.h"
#include "AZBoxTVSDK.h"

#include "parse_psi.h"
#include "parse_si.h"

struct tuner_list_st *tuner_list;

static int 
get_bit(uint8_t *bitfield, int bit)
{
	return (bitfield[bit/8] >> (bit % 8)) & 1;
}

//set bit value in bitfield
static void 
set_bit(uint8_t *bitfield, int bit)
{
	bitfield[bit/8] |= 1 << (bit % 8);
}



/**********************************************************
 * Descriptor identification and location - EN 300 468 p26
 */

/**********************************************************
 * data type for TABLE
 * PAT : service_st
 * CAT : service_st
 * PMT : service_st
 * SDT : service_st
 * NIT : multiplex_st
 * BAT : nultiplex_st
 * EIT : psi_table_st
 * TOT 
 */

///////////////////////////////////    si  /////////////////////////////////////////////
			//for ISDBT

static void 
parse_iso639_language_descriptor(const unsigned char *buf, struct service_st *s)
{
	unsigned char len = buf [1];
	buf += 2;

	if (len > 3) {
		verbose(TVSDK_DBG_ID,"\tLANG=%.3s type:%d\n", buf, buf[3]);
		
		if (s != NULL) 
			memcpy(s->audio_info[s->audio_num].lang, buf, 3);

		/* seems like the audio_type is wrong all over the place */
		//if (buf[3] == 0) -> normal
		if (buf[3] == 1)
			s->audio_info[s->audio_num].lang[3] = '!'; /* clean effects (no language) */
		else if (buf[3] == 2)
			s->audio_info[s->audio_num].lang[3] = '?'; /* for the hearing impaired */
		else if (buf[3] == 3)
			s->audio_info[s->audio_num].lang[3] = '+'; /* visually impaired commentary */
	}
}


static void 
parse_si_descriptors(enum table_type t, unsigned char descriptor_tag , const unsigned char *buf, void *data)
{
	switch(descriptor_tag) {

		case 0x40:
			verbose(TVSDK_DBG_ID,"network name descriptor\n");
			if (t == NIT) { 
			}
			break;

		case 0x41:
			verbose(TVSDK_DBG_ID,"service list descriptor\n");
			//if ((t == NIT) || (t == BAT)) 
			if (t == BAT) {
			}
			break;

		case 0x42:
			verbose(TVSDK_DBG_ID,"stuffing descriptor\n");
			if ((t == NIT) || (t == BAT) || (t == SDT) || (t == EIT)) { }
			break;

		case 0x43:
			verbose(TVSDK_DBG_ID,"satellite delivery descriptor\n");
			if (t == NIT) { 
			}
			break;

		case 0x44:
			fprintf(stderr, "\n\n\ncable delivery descriptor\n\n\n");
			if (t == NIT) { 
			}
			break;

		case 0x45:
			//verbose(TVSDK_DBG_ID,"VBI data descriptor\n");
			//if (t == PMT) { }
			break;

		case 0x46:
			//verbose(TVSDK_DBG_ID,"VBI teletext descriptor\n");
			//if (t == PMT) { }
			break;

		case 0x47:
			verbose(TVSDK_DBG_ID,"Bouquet name descriptor\n");
			if ((t == BAT) || (t == SDT) ) { 
			}
			break;

		case 0x48:
			verbose(TVSDK_DBG_ID,"service descriptor\n");
			if ((t == SDT)) { 
			}
			break;

		case 0x49:
			verbose(TVSDK_DBG_ID,"country availablity descriptor\n");
			if ((t == BAT) || (t == SDT)) { 
			}
			break;

		case 0x4a:
			verbose(TVSDK_DBG_ID,"linkage descriptor\n");
		//	if ((t == NIT) || (t == BAT) || (t == SDT) || (t == EIT))  
			if (t == EIT) {
				parse_linkage_descriptor (buf, data);
			}
			break;

		case 0x4b:
			verbose(TVSDK_DBG_ID,"NVOD reference descriptor\n");
			//if (t == SDT) { }
			break;

		case 0x4c:
			verbose(TVSDK_DBG_ID,"time shifted service descriptor\n");
			//if (t == SDT) { }
			break;

		case 0x4d:
			verbose(TVSDK_DBG_ID,"short event descriptor\n");
			if (t == EIT) { 
				parse_short_event_descriptor (buf, data);
			}
			break;

		case 0x4e:
			verbose(TVSDK_DBG_ID,"extended event descriptor\n");
			if (t == EIT) {
				parse_extended_event_descriptor (buf, data);
			}
			break;

		case 0x4f:
			verbose(TVSDK_DBG_ID,"time shifted event descriptor\n");
			if (t == EIT) { }
			break;

		case 0x50:
			verbose(TVSDK_DBG_ID,"component_descriptor\n");
			if (t == EIT) { 
				parse_component_descriptor(buf, data);
			}
			break;

		case 0x51:
			verbose(TVSDK_DBG_ID,"mosaic descriptor\n");
			break;

		case 0x52:
			verbose(TVSDK_DBG_ID,"stream identifier descriptor\n");
			break;

		case 0x53:
			verbose(TVSDK_DBG_ID,"CA identifier descriptor\n");
			break;

		case 0x54:
			verbose(TVSDK_DBG_ID,"content descriptor\n");
			if ((t == EIT)) {
				parse_content_descriptor (buf, data);
			}
			break;

		case 0x55:
			verbose(TVSDK_DBG_ID,"parental rating descriptor\n");
			if (t == EIT) { 
				parse_parental_rating_descriptor (buf, data);
			}
			break;

		case 0x56:
			verbose(TVSDK_DBG_ID,"teletext descriptor\n");
			break;

		case 0x57:
			verbose(TVSDK_DBG_ID,"telephone descriptor\n");
			break;

		case 0x58:
			verbose(TVSDK_DBG_ID,"local time offset descriptor\n");
			break;

		case 0x59:
			verbose(TVSDK_DBG_ID,"subtitling descriptor\n");
			break;

		case 0x5a:
			verbose(TVSDK_DBG_ID,"terrestrial delivery system_descriptor\n");
			break;

		case 0x5b:
			verbose(TVSDK_DBG_ID,"multilingual network name descriptor\n");
			if (t == NIT) {
			}
			break;

		case 0x5c:
			verbose(TVSDK_DBG_ID,"multilingual bouquet name descriptor\n");
			if (t == BAT) {
			}
			break;

		case 0x5d:
			verbose(TVSDK_DBG_ID,"multilingual service name descriptor\n");
			if (t == SDT) {
			}
			break;

		case 0x5e:
			verbose(TVSDK_DBG_ID,"multilingual component descriptor\n");
			if (t == EIT) {
			}
			break;

		case 0x5f:
			verbose(TVSDK_DBG_ID,"private data specifier descriptor\n");
			//if ((t == NIT) || (t == BAT) || (t == SDT) || (t == EIT) || (t == PMT)) 
			if ((t == NIT) || (t == BAT) || (t == SDT) || (t == PMT)) { 
			}
			break;

		case 0x60:
			//verbose(TVSDK_DBG_ID,"service move descriptor\n");
			//if (t == PMT) { }
			break;

		case 0x61:
			//verbose(TVSDK_DBG_ID,"short smoothing buffer descriptor\n");
			//if (t == EIT) { }
			break;

		case 0x62:
			verbose(TVSDK_DBG_ID,"frequency list descriptor\n");
			if (t == NIT) {
			}
			break;

		case 0x63:
			//verbose(TVSDK_DBG_ID,"partial transport stream descriptor\n");
			break;

		case 0x64:
			//verbose(TVSDK_DBG_ID,"data_broadcast_descriptor\n");
			//if ((t == SDT) || (t == EIT)) { }
			//if ((t == SDT)) { }
			break;

		case 0x65:
			//verbose(TVSDK_DBG_ID,"scrambling descriptor\n");
			break;

		case 0x66:
			//verbose(TVSDK_DBG_ID,"data broadcast id descriptor\n");
			//if (t == PMT) { }
			break;

		case 0x67:
			//verbose(TVSDK_DBG_ID,"transport stream descriptor\n");
			break;

		case 0x68:
			//verbose(TVSDK_DBG_ID,"DSNG descriptor\n");
			break;

		case 0x69:
			//verbose(TVSDK_DBG_ID,"PDC descriptor\n");
			//if (t == EIT) { 
			//}
			break;

		case 0x6a:
			//verbose(TVSDK_DBG_ID,"AC3 descriptor\n");
			//if (t == PMT) { }
			break;

		case 0x6b:
			//verbose(TVSDK_DBG_ID,"ancillary descriptor\n");
			//if (t == PMT) { }
			break;

		case 0x6c:
			//verbose(TVSDK_DBG_ID,"cell list descriptor\n");
			//if (t == NIT) { }
			break;

		case 0x6d:
			//verbose(TVSDK_DBG_ID,"cell frequency link descriptor\n");
			//if (t == NIT) { }
			break;

		case 0x6e:
			//verbose(TVSDK_DBG_ID,"announcement support descriptor\n");
			//if (t == SDT) { }
			break;

		case 0x6f:
			//verbose(TVSDK_DBG_ID,"application signalling descriptor\n");
			//if (t == PMT) { }
			break;

		case 0x70:
			//verbose(TVSDK_DBG_ID,"adaptation field data descriptor\n");
			//if (t == PMT) { }
			break;

		case 0x71:
			//verbose(TVSDK_DBG_ID,"service identifier descriptor\n");
			//if (t == SDT) { }
			break;

		case 0x72:
			//verbose(TVSDK_DBG_ID,"service availabilty descriptor\n");
			//if (t == SDT) { }
			break;

		case 0x73:
			//verbose(TVSDK_DBG_ID,"default authority descriptor\n");
			//if ((t == NIT) || (t == BAT) || (t == SDT)) { }
			break;

		case 0x74:
			//verbose(TVSDK_DBG_ID,"related content descriptor\n");
			//if (t == PMT) { }
			break;

		case 0x75:
			//verbose(TVSDK_DBG_ID,"TVA id descriptor\n");
			//if (t == EIT) { }
			break;

		case 0x76:
			//verbose(TVSDK_DBG_ID,"content identifier descriptor\n");
			//if (t == EIT) { }
			break;

		case 0x77:
			//verbose(TVSDK_DBG_ID,"time slice fec identifier descriptor\n");
			//if (t == NIT) { }
			break;

		case 0x78:
			//verbose(TVSDK_DBG_ID,"ECM repetition rate descriptor\n");
			//if (t == PMT) { }
			break;
		case 0xb1:
			break;

		case 0xcd:
			break;
		default :
			verbose(TVSDK_DBG_ID,"\t\t\tskip type %d descriptor: 0x%02x\n",t, descriptor_tag);
			break;

	}

}

void 
parse_descriptors(enum table_type t, const unsigned char *buf,
	int descriptors_loop_len, void *data, unsigned int network_type)
{

	while (descriptors_loop_len > 1) {
		unsigned char descriptor_tag = buf[0];
	//	unsigned char descriptor_len = buf[1] + 2;
		int descriptor_len = buf[1] + 2;

		switch (descriptor_tag) {
			case 0x09:
				verbose(TVSDK_DBG_ID,"CA descriptor %d %d %d\n", t, PMT, CAT);
				if ((t == PMT) || (t == CAT)) { 
				}
				break;

			case 0x0a:
				verbose(TVSDK_DBG_ID,"iso639 language descriptor\n");
				if (t == PMT) { 
					parse_iso639_language_descriptor (buf, data);
				}
				break;

			default:
				if((network_type == DTV_DVBS
							|| network_type == DTV_DVBT
							|| network_type == DTV_DVBC
							|| network_type == DTV_ARIB
							|| network_type == DTV_ISDBT)) {
					parse_si_descriptors(t, descriptor_tag, buf, data);
				}
				else if(network_type == DTV_ATSC) {
				}
				else {
					verbose(TVSDK_DBG_ID,"Unknown descriptor %x, network = %x\n", descriptor_tag, network_type);
				}
				break;
		}

		buf += descriptor_len;
		descriptors_loop_len -= descriptor_len;
	}
}

static HX_STATUS
parse_psi_section(HX_INT8 dtv, const unsigned char *buf, struct service_st *service, HX_UINT16 pid)
{
	struct parse_info_st parse_info;

	unsigned char table_id;
	int section_length;
	int table_id_ext;
	int section_version_number;
	int section_number;
	int last_section_number;
	unsigned net_type;

	table_id = buf[0];

	verbose(TVSDK_DBG_ID,"parse_psi_section(table_id 0x%02x)\n", table_id);

	if ((buf[1] & 0x80) != 0x80) { /* section syntax indicator 1 */
		errorn(TVSDK_DBG_ID,"Invalid section syntax indicator for PSI\n");
		return HX_ERROR;
	}

	section_length = (((buf[1] & 0x0f) << 8) | buf[2]);

	buf +=3;
	
	section_length -= 4; /* skip CRC field */

	table_id_ext = (buf[0] << 8) | buf[1]; //PAT : transpot_stream_id PMT : program_number (service_id)
	section_version_number = (buf[2] >> 1) & 0x1f;

//	infon(TVSDK_DBG_ID,"table_id_ext %d version_number %d \n",table_id_ext, section_version_number);

	if (service != NULL) {
		service->version_number = (HX_INT32)section_version_number;
		service->current_next_indicator = (HX_INT32)(buf[2] & 0x01);
	}

	section_number = buf[3];
	last_section_number = buf[4];

	if (table_id == 0x42) {
		verbose(TVSDK_DBG_ID,"sect = %x, %x \n", section_number, last_section_number);
	}

	buf += 5;
	section_length -= 5;

	parse_info.dtv = dtv;
	parse_info.pid = pid;
	parse_info.table_id = table_id;
	parse_info.buf = buf;
	parse_info.section_length = section_length;
	parse_info.table_id_ext = table_id_ext;
	parse_info.section_version_number = section_version_number;
	parse_info.net_index = TVSDK_GetTunerList()->tuner[dtv].net_index;
	parse_info.network_type = net_type = TVSDK_GetTunerList()->tuner[dtv].type;

//	infon(TVSDK_DBG_ID," net_index %d net_type %d \n",parse_info.net_index, parse_info.network_type);

	switch (table_id) {
	case 0x00:
		verbose(TVSDK_DBG_ID,"PAT: Program Association Section\n");
		break;
	case 0x01:
		verbose(TVSDK_DBG_ID,"CAT: Conditional Access Setion(PID: 0x%04x)\n", table_id_ext);
		break;
	case 0x02:
		verbose(TVSDK_DBG_ID,"PMT: Program Map Setion(for service 0x%04x)\n", table_id_ext);
		break;
	case 0x03:
		verbose(TVSDK_DBG_ID,"TSDT: Transport Stream Description Section\n");
		break;
	default:
	//	info(TVSDK_DBG_ID,"Unknown Section, table_id = %x\n", table_id);
		break;
	}

	if (net_type == DTV_DVBS || net_type == DTV_DVBT || net_type == DTV_DVBC) {
		parse_si_section(&parse_info, service);
	}
	else if (net_type == DTV_ATSC) {
	}
	else if (net_type == DTV_ISDBT) {
		parse_si_section(&parse_info, service);
	}

	return 1;
}

static HX_STATUS
parse_private_section(const unsigned char *buf, struct service_st *service, unsigned int network_type, HX_UINT16 pid)
{
	unsigned char table_id;
	int section_length;
	
	table_id = buf[0];

	if ((buf[1] & 0x80) != 0x00) { /* section syntax indicator = 0 */
		errorn(TVSDK_DBG_ID,"Invalid section syntax indicator for Private Section\n");
		return HX_ERROR;
	}

	section_length = (((buf[1] & 0x0f) << 8) | buf[2]);
	buf +=3;

//	infon(TVSDK_DBG_ID,"pid 0x%04x Section %x\n",pid, table_id);

	switch(table_id) {
	case 0x70:
		verbose(TVSDK_DBG_ID,"TDT: Time Date Section\n");
		break;
	case 0x71: 
		verbose(TVSDK_DBG_ID,"Running Status Section\n");
		break;
	case 0x72: 
		verbose(TVSDK_DBG_ID,"Stuffing Section\n");
		break;
	case 0x73: 
		verbose(TVSDK_DBG_ID,"Time Offset Section\n");
		break;
	default:
		infon(TVSDK_DBG_ID,"pid 0x%04x Unknown Section %x\n",pid, table_id);
		break;
	}
		
	return HX_OK;
}

void parse_section(HX_INT8 dtv, HX_UINT16 pid, HX_UINT8 *pBuf, HX_UINT32 length, HX_INT32 param1, HX_INT32 param2)
{
	stSectionMap * sec_map;

	HX_STATUS ret;

	HX_UINT8 table_id;
	HX_INT32 section_syntax_indicator;
	HX_UINT32 section_length;
	HX_UINT16 table_id_ext;
	HX_INT16 version_number;
	HX_INT16 section_number;
	HX_INT16 last_section_number;
	int i;

	tuner_list = TVSDK_GetTunerList();

	if (!pBuf)
		return;

	table_id = pBuf[0];
	section_syntax_indicator = pBuf[1] & 0x80;
	section_length = ((pBuf[1] & 0x0f) << 8 | pBuf[2]);

	if ((section_length + 3) != length) {
		errorn(TVSDK_DBG_ID,"invalid section length(%lu != %lu)\n", section_length, length);
		return;
	}

	debug(TVSDK_DBG_ID,"%x_ -> section debug.\n", dtv);
	debug(TVSDK_DBG_ID,"\ttable_id: 0x%02x\n", table_id);
	debug(TVSDK_DBG_ID,"\tsection_length: %lu\n", section_length);

	if (section_syntax_indicator == 0x00) {
#if 1
		HX_UINT net_type = tuner_list->tuner[dtv].type;

		debugn(TVSDK_DBG_ID,"\tprivate section\n");

		ret = parse_private_section(pBuf, NULL, net_type,pid); 
		if (ret != HX_OK) {
			warningn(TVSDK_DBG_ID,"%x_fail to parse private section\n", dtv);
		}
#endif

		return;
	}


	table_id_ext = (pBuf[3] << 8) | pBuf[4];
	/* version number on bit 5..1, current_next_indicator on bit 0*/
	version_number = (pBuf[5] & 0x3e) >> 1;
	section_number = pBuf[6];
	last_section_number = pBuf[7];

	debug(TVSDK_DBG_ID,"\ttable_id_extension = 0x%04x\n", table_id_ext);
	debug(TVSDK_DBG_ID,"\tversion_number = %d\n", version_number);
	debug(TVSDK_DBG_ID,"\tsection_number = %d of %d\n",
			section_number, last_section_number);


	/*
	 * Use SECTION_FLAG_CHECK_VERSION_NUMBER 
	 * if it is not segmented section as PAT, PMT, SDT and etc...
	 * In case of EIT, don't use SECTION_FLAG_CHECK_VERSION_NUMBER
	 */

	sec_map = TVSDK_SectionMapFind(dtv, pid, table_id);

	//info(TVSDK_DBG_ID,"section table_id_ext is (0x%04X --> 0x%04X) table_id %02X\n",	sec_map->table_id_ext, table_id_ext,table_id);

	if (sec_map) {
		if ((sec_map->table_id_ext != 0x0000) && (sec_map->table_id_ext != table_id_ext)) {
			//tmp by hwan 2008.10.23
			HX_UINT16 tmp_table_id_ext = sec_map->table_id_ext;

			debug(TVSDK_DBG_ID,"\tsection table_id_ext is changed(0x%04X --> 0x%04X)\n", sec_map->table_id_ext, table_id_ext);

			// It is not supported
			// If this is EIT section, you have to implement 
			// specific code for filtering it.

			TVSDK_SectionMapFlush(sec_map);

			if (table_id == 0x02 ) 
			{
				debug(TVSDK_DBG_ID, "PMT unknown sid(W:0x%04x - R:0x%04x)\n", tmp_table_id_ext, table_id_ext);
				sec_map->table_id_ext = tmp_table_id_ext; 
				return;
			}
		}

		if ((sec_map->version_number != version_number)) {
			verbose(TVSDK_DBG_ID,"\tversion_number is changed(%d --> %d)\n",
					sec_map->version_number, version_number);

			TVSDK_SectionMapFlush(sec_map);
		}
		else if(last_section_number > 0){
			verbose(TVSDK_DBG_ID,"need more section parsing\n");
		}

		if (sec_map->done)
		{
			//info(TVSDK_DBG_ID,"\tsec_map->done is done(dtv = %d, table_id = 0x%02x\n",	dtv, table_id);
			return;
		}

		sec_map->table_id_ext = table_id_ext;
		sec_map->version_number = version_number;
		sec_map->last_section_number = last_section_number;

		if (get_bit(sec_map->section_done, section_number))
			return;

		set_bit(sec_map->section_done, section_number);

		if (sec_map->done) {
			info(TVSDK_DBG_ID,"\tsection is done(dtv = %d, table_id = 0x%02x\n",
					dtv, table_id);
		}

		if ( table_id == 0x02 && sec_map->done == 1 ) {
			info(TVSDK_DBG_ID,"\tsec_map->done is done table_id = 0x%02x TD200\n", table_id);
			return;
		}
	}


	if (parse_psi_section(dtv, pBuf, NULL,pid)==0) {
		return;
	}

	//info(TVSDK_DBG_ID,"------ parse finish ------\n");

	if (sec_map) {
		i=0;
		// check whether secion is done or not
		for (i = 0; i <= sec_map->last_section_number; i++) {
			if (get_bit(sec_map->section_done, i) == 0) {
				break;
			}
		}

		if (i > sec_map->last_section_number) {
			sec_map->done = 1;
			//info(TVSDK_DBG_ID,"------ sec_map->done ------\n");
		}

	}
	return;
}

