#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <Platform_Lib/SubtitleParser/IDXSUBParser.h>
//#define MIN(a, b)	((a)<(b)?(a):(b))
//#define MAX(a, b)	((a)>(b)?(a):(b))


/**********************************************************************
 * SUB parsing                        private interface for internal class usage
 **********************************************************************/
int IDXSUBParser :: SUB_open(const char *filename)
{
	SUB_t *res = &m_sub;
	res->pts = 0;
	res->aid = -1;
	res->packet = NULL;
	res->packet_size = 0;
	res->packet_reserve = 0;
	res->fp_sub = fopen(filename, "rb");
	if (res->fp_sub==NULL)
	{
	    	printf("fopen SUB file failed\n");
	   	return -1;
	}
	return 0;
}

 void IDXSUBParser :: SUB_free(SUB_t *SUB)
{
    if (SUB->packet)
	free(SUB->packet);
    if (SUB->fp_sub)
	fclose(SUB->fp_sub);
}
 
int IDXSUBParser :: SUB_eof(SUB_t *SUB)
{
    return feof(SUB->fp_sub);
}

int IDXSUBParser :: SUB_tell(SUB_t *SUB)
{
    return ftell(SUB->fp_sub);
}

 int IDXSUBParser ::SUB_run(SUB_t *SUB, spudec_handle_t *pSpu)
{
    unsigned int len, idx, version;
    int c;
    /* Goto start of a packet, it starts with 0x000001?? */
    const unsigned char wanted[] = { 0, 0, 1 };
    unsigned char buf[5];

    SUB->aid = -1;
    SUB->packet_size = 0;
    pSpu->packet=NULL;
   while(1)
   {
	
    if (fread(buf, 4, 1, SUB->fp_sub) != 1)
	return -1;
    while (memcmp(buf, wanted, sizeof(wanted)) != 0) {
	c = getc(SUB->fp_sub);
	if (c < 0)
	    return -1;
	memmove(buf, buf + 1, 3);
	buf[3] = c;
    }
    switch (buf[3]) {
    case 0xb9:			/* System End Code */
	break;
    case 0xba:			/* Packet start code */
	c = getc(SUB->fp_sub);
	if (c < 0)
	    return -1;
	if ((c & 0xc0) == 0x40)
	    version = 4;
	else if ((c & 0xf0) == 0x20)
	    version = 2;
	else {
	   printf("Unsupported SUB version: 0x%02x\n", c);
	    return -1;
	}
	if (version == 4) {
	    if (fseek(SUB->fp_sub, 9, SEEK_CUR))
		return -1;
	}
	else if (version == 2) {
	    if (fseek(SUB->fp_sub, 7, SEEK_CUR))
		return -1;
	}
	else
	    abort();
	break;
    case 0xbd:			/* packet */
	if (fread(buf, 2, 1, SUB->fp_sub) != 1)
	    return -1;
	len = buf[0] << 8 | buf[1];
	idx = SUB_tell(SUB);
	c = getc(SUB->fp_sub);
	if (c < 0)
	    return -1;
	if ((c & 0xC0) == 0x40) { /* skip STD scale & size */
	    if (getc(SUB->fp_sub) < 0)
		return -1;
	    c = getc(SUB->fp_sub);
	    if (c < 0)
		return -1;
	}
	if ((c & 0xf0) == 0x20) { /* System-1 stream timestamp */
	    /* Do we need this? */
	    abort();
	}
	else if ((c & 0xf0) == 0x30) {
	    /* Do we need this? */
	    abort();
	}
	else if ((c & 0xc0) == 0x80) { /* System-2 (.VOB) stream */
	    unsigned int pts_flags, hdrlen, dataidx;
	    c = getc(SUB->fp_sub);
	    if (c < 0)
		return -1;
	    pts_flags = c;
	    c = getc(SUB->fp_sub);
	    if (c < 0)
		return -1;
	    hdrlen = c;
	    dataidx = SUB_tell(SUB) + hdrlen;
	    if (dataidx > idx + len) {
		printf("Invalid header length: %d (total length: %d, idx: %d, dataidx: %d)\n",
			hdrlen, len, idx, dataidx);
		return -1;
	    }
	    if ((pts_flags & 0xc0) == 0x80) {
		if (fread(buf, 5, 1, SUB->fp_sub) != 1)
		    return -1;
		if (!(((buf[0] & 0xf0) == 0x20) && (buf[0] & 1) && (buf[2] & 1) &&  (buf[4] & 1))) {
		   printf("IDX PTS error: 0x%02x %02x%02x %02x%02x \n",
			    buf[0], buf[1], buf[2], buf[3], buf[4]);
		    SUB->pts = 0;
		}
		else
		    SUB->pts = ((buf[0] & 0x0e) << 29 | buf[1] << 22 | (buf[2] & 0xfe) << 14
			| buf[3] << 7 | (buf[4] >> 1));
	    }
	    else /* if ((pts_flags & 0xc0) == 0xc0) */ {
		/* what's this? */
		/* abort(); */
	    }
	    fseek(SUB->fp_sub, dataidx, SEEK_SET);
	    SUB->aid = getc(SUB->fp_sub);
	    if (SUB->aid < 0 ) {
		printf("Bogus aid %d\n", SUB->aid);
		return -1;
	    }
	    SUB->packet_size += len - ((unsigned int) SUB_tell(SUB) - idx);
	    if (SUB->packet_reserve < SUB->packet_size) {
	
			if (!SUB->packet)
				SUB->packet = (unsigned char *)malloc(SUB->packet_size);
			else
				SUB->packet = (unsigned char *)realloc(SUB->packet,SUB->packet_size);
		
			if (SUB->packet)
				SUB->packet_reserve = SUB->packet_size;
	    
			if (SUB->packet == NULL) {
				printf("malloc sub failure");
				SUB->packet_reserve = 0;
				SUB->packet_size = 0;
				return -1;
				}
		}
	 	if (fread(SUB->packet + SUB->packet_size -(len - ((unsigned int) SUB_tell(SUB) - idx)) , len - ((unsigned int) SUB_tell(SUB) - idx), 1, SUB->fp_sub) != 1) 
		{
			printf("fread sub failure");
			SUB->packet_size = 0;
			return -1;
		}

	  	if(get_be16(SUB->packet)  == SUB->packet_size)
		{
			pSpu->packet=SUB->packet;
			pSpu->control_start = 0;
			pSpu->height = 0;
			pSpu->width = 0;
			pSpu->stride = 0;
			//pSpu->image = NULL;
			//pSpu->aimage = NULL;
			spudec_process_control(pSpu,0);
		}
	}
		
	break;
    case 0xbe:			/* Padding */
	if (fread(buf, 2, 1, SUB->fp_sub) != 1)
	    return -1;
	len = buf[0] << 8 | buf[1];
	if (len > 0 && fseek(SUB->fp_sub, len, SEEK_CUR))
	    return -1;
	return 0;
    default:
	if (0xc0 <= buf[3] && buf[3] < 0xf0) {
	    /* SUB audio or video */
	    if (fread(buf, 2, 1, SUB->fp_sub) != 1)
		return -1;
	    len = buf[0] << 8 | buf[1];
	    if (len > 0 && fseek(SUB->fp_sub, len, SEEK_CUR))
		return -1;
		
	}
	else {
	    printf("unknown header 0x%02X%02X%02X%02X\n",
		    buf[0], buf[1], buf[2], buf[3]);
	    return -1;
	}
	break;
    }
   }
    return 0;
}



/**********************************************************************
 * IDX Parsing                         private interface for internal class usage
 **********************************************************************/
int IDXSUBParser :: IDX_parse_id(IDX_t *vob, const char *line)
{
    // id: xx, index: n
    size_t idlen;
    unsigned int index =0;
    const char *p, *q;
    p  = line;
    while (isspace(*p))
	++p;
    q = p;
    while(*q != ',')//while (isalpha(*q))
	++q;
    idlen = q - p;
    if (idlen == 0)
	return -1;
    ++q;
    while (isspace(*q))
	++q;
    if (strncmp("index:", q, 6))
	return -1;
    q += 6;
    while (isspace(*q))
	++q;
    if (!isdigit(*q))
	return -1;
	
	index = atoi(q);
//	assert((index >= 0) && (index < 32));
	vob->SubLang[index].index = index;
	memcpy(vob->SubLang[index].LangName,p,idlen);
	vob->SubLang[index].LangName[idlen] = '\0';
	vob->SubLang[index].filepos = ftell(vob->fp_idx);

	printf("####################index = %d lang = %s\n",index,vob->SubLang[index].LangName);
	
    return 0;
}

 int IDXSUBParser :: IDX_parse_size(IDX_t *vob, const char *line)
{
    // size: WWWxHHH
    char *p;
    while (isspace(*line))
	++line;
    if (!isdigit(*line))
	return -1;
    vob->orig_frame_width = strtoul(line, &p, 10);
    if (*p != 'x')
	return -1;
    ++p;
    vob->orig_frame_height = strtoul(p, NULL, 10);
    return 0;
}

 int IDXSUBParser ::IDX_parse_origin(IDX_t *vob, const char *line)
{
    // org: X,Y
    char *p;
    while (isspace(*line))
	++line;
    if (!isdigit(*line))
	return -1;
    vob->origin_x = strtoul(line, &p, 10);
    if (*p != ',')
	return -1;
    ++p;
    vob->origin_y = strtoul(p, NULL, 10);
    return 0;
}

 int IDXSUBParser :: IDX_parse_palette(IDX_t *vob, const char *line)
{
    // palette: XXXXXX, XXXXXX, XXXXXX, XXXXXX, XXXXXX, XXXXXX, XXXXXX, XXXXXX, XXXXXX, XXXXXX, XXXXXX, XXXXXX, XXXXXX, XXXXXX, XXXXXX, XXXXXX
    unsigned int n;
    n = 0;
    while (1) {
	const char *p;
	int r, g, b, y, u, v, tmp;
	while (isspace(*line))
	    ++line;
	p = line;
	while (isxdigit(*p))
	    ++p;
	if (p - line != 6)
	    return -1;
	tmp = strtoul(line, NULL, 16);
	r = tmp >> 16 & 0xff;
	g = tmp >> 8 & 0xff;
	b = tmp & 0xff;
//	y = MIN(MAX((int)(0.1494 * r + 0.6061 * g + 0.2445 * b), 0), 0xff);
//	u = MIN(MAX((int)(0.6066 * r - 0.4322 * g - 0.1744 * b) + 128, 0), 0xff);
//	v = MIN(MAX((int)(-0.08435 * r - 0.3422 * g + 0.4266 * b) + 128, 0), 0xff);
	y = r;
	u = g;
	v = b;
	vob->palette[n++] = y << 16 | u << 8 | v;
	if (n == 16)
	    break;
	if (*p == ',')
	    ++p;
	line = p;
    }

	//change the background color to transparent
//	vob->palette[0]=RESERVED_COLOR_KEY;
	
    vob->have_palette = 1;
    return 0;
}

int IDXSUBParser :: IDX_parse_custom(IDX_t *vob, const char *line)
{
    //custom colors: OFF/ON(0/1)
    if ((strncmp("ON", line + 15, 2) == 0)||strncmp("1", line + 15, 1) == 0)
        vob->custom=1;
    else if ((strncmp("OFF", line + 15, 3) == 0)||strncmp("0", line + 15, 1) == 0)
        vob->custom=0;
    else
        return -1;
    return 0;
}

int IDXSUBParser ::IDX_parse_cuspal(IDX_t *vob, const char *line)
{
    //colors: XXXXXX, XXXXXX, XXXXXX, XXXXXX
    unsigned int n;
    n = 0;
    line += 40;
    while(1){
    	const char *p;
	while (isspace(*line))
	    ++line;
	p=line;
	while (isxdigit(*p))
	    ++p;
	if (p - line !=6)
	    return -1;
	vob->cuspal[n++] = strtoul(line, NULL,16);
	if (n==4)
	    break;
	if(*p == ',')
	    ++p;
	line = p;
    }
    return 0;
}

/* don't know how to use tridx */
int IDXSUBParser ::IDX_parse_tridx(const char *line)
{
    //tridx: XXXX
    int tridx;
    tridx = strtoul((line + 26), NULL, 16);
    tridx = ((tridx&0x1000)>>12) | ((tridx&0x100)>>7) | ((tridx&0x10)>>2) | ((tridx&1)<<3);
    return tridx;
}

 int IDXSUBParser ::IDX_parse_delay(IDX_t *vob, const char *line)
{
    int h, m, s, ms;
    int forward = 1;
    if (*(line + 7) == '+'){
    	forward = 1;
	line++;
    }
    else if (*(line + 7) == '-'){
    	forward = -1;
	line++;
    }
    h = atoi(line + 7);
    m = atoi(line + 10);
    s = atoi(line + 13);
    ms = atoi(line + 16);
    vob->delay = ms + 1000 * (s + 60 * (m + 60 * h)) * forward;
    return 0;
}


int IDXSUBParser ::IDX_set_lang(IDX_t *vob,const char *line)
{
        vob->LangIdx = atoi(line + 8);
		vob->defaultLangIdx =  vob->LangIdx;
    return 0;
}

 int IDXSUBParser ::IDX_parse_one_line(IDX_t *vob, FILE *fd)
{
    int res = -1;
	char line[1024];
    do {
	if(fgets(line, 1024, fd) == NULL) /* eof/error */
				return -1;
	if (*line == 0 || *line == '\r' || *line == '\n' || *line == '#')
	    continue;
	else if (strncmp("langidx:", line, 8) == 0)
	    res = IDX_set_lang(vob,line);
	else if (strncmp("delay:", line, 6) == 0)
	    res = IDX_parse_delay(vob, line);
	else if (strncmp("id:", line, 3) == 0)
	    res = IDX_parse_id(vob, line + 3);
	else if (strncmp("palette:", line, 8) == 0)
	    res = IDX_parse_palette(vob, line + 8);
	else if (strncmp("size:", line, 5) == 0)
	    res = IDX_parse_size(vob, line + 5);
	else if (strncmp("org:", line, 4) == 0)
	    res = IDX_parse_origin(vob, line + 4);
	else if (strncmp("timestamp:", line, 10) == 0)
	   	continue;
	else if (strncmp("custom colors:", line, 14) == 0)
	    //custom colors: ON/OFF, tridx: XXXX, colors: XXXXXX, XXXXXX, XXXXXX,XXXXXX
	    res = IDX_parse_cuspal(vob, line) + IDX_parse_tridx(line) + IDX_parse_custom(vob, line);
	else {
	//	printf( "IDX: ignoring %s\n", line);
	    continue;
	}
	if (res < 0)
	   printf("ERROR in %s\n", line);
	
    } while (1);
    return res;
}


int IDXSUBParser ::IDX_open(const char * filename)
{
    	IDX_t *vob =&m_idx;
	int flag = 0; //used to check if there is a lang in idx file,if no,idx is not a valid file	
	vob->custom = 0;
	vob->have_palette = 0;
	vob->orig_frame_width = 0;
	vob->orig_frame_height = 0;
	vob->delay = 0;
	vob->LangIdx = 0;
	vob->fp_idx = fopen(filename, "r");
	if (vob->fp_idx  == NULL) 
	{
		printf("IDX: Can't open IDX file\n");
		return -1;
	}
	
	for(int i=0;i<32;i++){   //IDX_INDEX_NOT_EXIST means dont have this idex
		m_idx.SubLang[i].index = IDX_INDEX_NOT_EXIST;
		memset(m_idx.SubLang[i].LangName,0,20);
	}
	
	while (!feof(vob->fp_idx))
		IDX_parse_one_line(vob,vob->fp_idx);
		    /* NOOP */ ;
	
	if ((vob->custom == 0)&&(vob->have_palette!=1))
		vob->custom = 1;

	//check if default langidx exist 
	if(m_idx.SubLang[m_idx.LangIdx].index == IDX_INDEX_NOT_EXIST){
		for(int i=0;i<32;i++){   //IDX_INDEX_NOT_EXIST means dont have this idex
			if(m_idx.SubLang[i].index != IDX_INDEX_NOT_EXIST){
				m_idx.LangIdx = i;
				m_idx.defaultLangIdx = i;
				flag = 1;
				goto DefaultLangChecked;
			}
		}
	}
	else
		 flag = 1;


DefaultLangChecked:
	m_pSPUDecoder = NULL;
	if(flag == 1){
		printf("####valid idx file\n");
		return 0;
	}
	else{
		printf("####invalid idx file\n");
		return -1;
	}
}



/**********************************************************************
 * SPU Parsing           private interface for internal class usage
 **********************************************************************/
// read a big endian 16 bit value
 unsigned int  IDXSUBParser :: get_be16(const unsigned char *p)
{
	  return (p[0] << 8) + p[1];
}

// read a big endian 24 bit value
unsigned int IDXSUBParser :: get_be24(const unsigned char *p)
{
  return (get_be16(p) << 8) + p[2];
}

void IDXSUBParser ::next_line(spudec_handle_t *spuHandle)
{
  if (spuHandle->current_nibble[spuHandle->deinterlace_oddness] % 2)
    spuHandle->current_nibble[spuHandle->deinterlace_oddness]++;
  spuHandle->deinterlace_oddness = (spuHandle->deinterlace_oddness + 1) % 2;
}

unsigned char IDXSUBParser ::get_nibble(spudec_handle_t *spuHandle)
{
  unsigned char nib;
  int *nibblep = spuHandle->current_nibble + spuHandle->deinterlace_oddness;
  if (*nibblep / 2 >= spuHandle->control_start) {
    fprintf(stderr,"SPUdec: ERROR: get_nibble past end of packet\n");
    return 0;
  }
  nib = spuHandle->packet[*nibblep / 2];
  if (*nibblep % 2)
    nib &= 0xf;
  else
    nib >>= 4;
  ++*nibblep;
  return nib;
}

void IDXSUBParser :: spudec_process_data(spudec_handle_t *spuHandle)
{
#if 1
	// now we use subpicture decoder (Video F/W) 
	// thus we don't need to process any data
	return;
#endif
  int i, x, y;
    if (spuHandle->image != NULL) {
      free(spuHandle->image);
      spuHandle->image_size = 0;
    }

    // allocate memory for image and alpha channel
    spuHandle->image = ( char *)malloc(2 * spuHandle->stride * spuHandle->height);
    if (spuHandle->image) {
      spuHandle->image_size = spuHandle->stride * spuHandle->height;
      spuHandle->aimage = spuHandle->image + spuHandle->image_size;
    }


  if (spuHandle->image == NULL){
    fprintf(stderr,"spuHandle->image == NULL\n");
    return;
  }

//FILE *fp;
//fp=fopen("123.alpha","wb");

  spuHandle->deinterlace_oddness = 0;
  i = spuHandle->current_nibble[1];
  x = 0;
  y = 0;
  while (spuHandle->current_nibble[0] < i
	 && spuHandle->current_nibble[1] / 2 < spuHandle->control_start
	 && y < spuHandle->height) {
    int len, color;
    unsigned int rle = 0;
    rle = get_nibble(spuHandle);
    if (rle < 0x04) {
      rle = (rle << 4) | get_nibble(spuHandle);
      if (rle < 0x10) {
	rle = (rle << 4) | get_nibble(spuHandle);
	if (rle < 0x040) {
	  rle = (rle << 4) | get_nibble(spuHandle);
	  if (rle < 0x0004)
	    rle |= ((spuHandle->width - x) << 2);
	}
      }
    }
    color = (rle & 0x3);
    len = rle >> 2;
    if (len > spuHandle->width - x || len == 0)
      len = spuHandle->width - x;

   assert( (color >=0) && (color <4));
    memset(spuHandle->image + y * spuHandle->stride + x, spuHandle->palette[color], len);
    // assign alpha values. The original pallet contains alpha values
    // in the range 0x0..0xf that are here transformed to 0x0..0xff.
//	fwrite(spuHandle->image + y * spuHandle->stride + x,len,1,fp);
    memset(spuHandle->aimage + y * spuHandle->stride + x,spuHandle->alpha[color] , len);
//	fwrite(spuHandle->aimage + y * spuHandle->stride + x,len,1,fp);
    x += len;
    if (x >= spuHandle->width) {
      next_line(spuHandle);
      x = 0;
      ++y;
    }
  }
  //fclose(fp);
}

void  IDXSUBParser :: spudec_process_control(spudec_handle_t *spuHandle, int pts100)
{
  int a,b; /* Temporary vars */
  int date=0, type;
  int off;
  int start_off = 0;
  int next_off;

  spuHandle->control_start = get_be16(spuHandle->packet + 2);
  next_off = spuHandle->control_start;
  while (start_off != next_off) {
    start_off = next_off;
    /* 
       get delay to wait till the command should be executed.
       The units are 90KHz clock divided by 1024.
    */
    date = get_be16(spuHandle->packet + start_off);
    next_off = get_be16(spuHandle->packet + start_off + 2);
    // fprintf(stderr,"date=%d\n", date);
    off = start_off + 4;
    for (type = spuHandle->packet[off++]; type != 0xff; type = spuHandle->packet[off++]) {
      //fprintf(stderr,"cmd=%d  ",type);
      switch(type) {
      case 0x00:
      case 0x01:
          if( spuHandle->end_pts==-1 ) {
            //  spuHandle->end_pts = pts100 + date*(100*1024/90000.0);
			  spuHandle->end_pts = pts100 + date*10;
              spudec_process_data(spuHandle);
          }
	/* Start display, no arguments */
	  //fprintf(stderr,"Start display:%d--%d!\n",pts100,date);
        spuHandle->is_forced = (type==0);
		spuHandle->end_pts = pts100 + date*10;
	//	spuHandle->start_pts = pts100 + date*(100*1024/90000.0);
        spuHandle->end_pts = -1;
	break;
      case 0x02:
	/* Stop display, no arguments */
	  //fprintf(stderr,"Stop display:%d--%d!\n",pts100,date);
	// spuHandle->end_pts = pts100 + date*(100*1024/90000.0);
	 spuHandle->end_pts = pts100 + date*10;
        spudec_process_data(spuHandle);
	break;
      case 0x03:
	/* Set Color. Provides four indices into the color lookup table.
           One nibble addresses one color so that 2 bytes set all 4 colors.
	   Format in stream: emph2 emph1 pattern background
	*/
	spuHandle->palette[0] = spuHandle->packet[off] >> 4;      // emph2
	spuHandle->palette[1] = spuHandle->packet[off] & 0xf;     // emph1
	spuHandle->palette[2] = spuHandle->packet[off + 1] >> 4;  // pattern
	spuHandle->palette[3] = spuHandle->packet[off + 1] & 0xf; // background
	//printf("Palette %d, %d, %d, %d\n",
	 //      spuHandle->palette[0], spuHandle->palette[1], spuHandle->palette[2], spuHandle->palette[3]);
	
	off+=2;
	break;
      case 0x04:
	/* Alpha blendig:
	   Directly provides the four contrast (alpha blend) values to associate with 
	   the four pixel values. One nibble per pixel value for a total of 2 bytes. 
	   0x0 = transparent, 0xF = opaque.
	   Format in stream : emph2 emph1 pattern background
	*/
	/* Alpha */
	//spuHandle->alpha[0] = spuHandle->packet[off] >> 4;        // emph2    
	//spuHandle->alpha[1] = spuHandle->packet[off] & 0xf;	// emph1    
	//spuHandle->alpha[2] = spuHandle->packet[off + 1] >> 4;	// pattern  
	//spuHandle->alpha[3] = spuHandle->packet[off + 1] & 0xf;	// background
	spuHandle->alpha[0] = 0;        // emph2    
	spuHandle->alpha[1] = 0xf;	// emph1    
	spuHandle->alpha[2] =0xf;	// pattern  
	spuHandle->alpha[3] =0;	// background
	off+=2;
	break;
      case 0x05:
	/* DISPLAY AREA 
	   Defines the display area, each pair (X and Y) of values is 3 bytes wide, 
	   for a total of 6 bytes, and has the form 
	   sx sx   sx ex   ex ex   sy sy   sy ey   ey ey 
	   sx = starting X coordinate 
	   ex = ending X coordinate 
	   sy = starting Y coordinate 
	   ey = ending Y coordinate 
	*/
	a = get_be24(spuHandle->packet + off);
	b = get_be24(spuHandle->packet + off + 3);
	spuHandle->start_col = a >> 12;
	spuHandle->end_col = a & 0xfff;
	spuHandle->width = spuHandle->end_col - spuHandle->start_col + 1;
	spuHandle->stride = (spuHandle->width + 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */
	spuHandle->start_row = b >> 12;
	spuHandle->end_row = b & 0xfff;
	spuHandle->height = spuHandle->end_row - spuHandle->start_row  + 1 ;
	/*fprintf(stderr,"Coords  col: %d - %d  row: %d - %d  (%dx%d)\n",
	       spuHandle->start_col, spuHandle->end_col, spuHandle->start_row, spuHandle->end_row,
	       spuHandle->width, spuHandle->height);
	*/
	off+=6;
	break;
      case 0x06:
	/* 
	   Graphic lines.
	   Two 16 bit values that indicate the first and second 
	   line of the subtitle image. (The subtitle image is
	   interlaced so that.)
	   Format in stream: line1 line2
	*/
	spuHandle->current_nibble[0] = 2 * get_be16(spuHandle->packet + off);
	spuHandle->current_nibble[1] = 2 * get_be16(spuHandle->packet + off + 2);
	/*fprintf(stderr,"Graphic offset 1: %d  offset 2: %d\n",
	       spuHandle->current_nibble[0] / 2, spuHandle->current_nibble[1] / 2);
	*/
	off+=4;
	break;
      case 0xff:
	/* End command. */
	//fprintf(stderr,"Done!\n");
	return;
	break;
      default:
	fprintf(stderr,"spudec: Error determining control type 0x%02x.  Skipping %d bytes.\n",
	       type, next_off - off);
	goto next_control;
      }
    }
  next_control:
    ;
  }
}


/**********************************************************************
 * public interface export
 **********************************************************************/
bool  IDXSUBParser ::Open(char *filename)
{
	char *tmp;
	int res;
	tmp = (char *)malloc(strlen(filename)+5);
	
	sprintf(tmp,"%s.idx",filename);
	res = IDX_open(tmp);
	
	if(res == -1)
	{    free(tmp);
		return false;
	}
	sprintf(tmp,"%s.sub",filename);
	res = SUB_open(tmp);
	if(res == -1)
	{	 free(tmp);
	    return false;
	}

	m_spu.image = NULL;
	m_spu.aimage = NULL;

	startTimeMs = 0;
	stopTimeMs = 0;
	lastStartTimeMs = 0;
	lastStopTimeMs = 0;
	lastFilepos = -1;
	free(tmp);
	return true;
}

bool  IDXSUBParser ::Close(void)
{
	if(m_idx.fp_idx)
		fclose(m_idx.fp_idx);
	SUB_free(&m_sub);
	if(m_spu.image !=NULL)
		free(m_spu.image);		//spu.aimage is following the spu.image, free image will also free aimage
	return true;
}

int  IDXSUBParser ::GetSubtitle(int timeMs,  SUBTITLE_STYLE_SHEET *stylesheet, char **image)
{
	int startH, startM, startS, startMs;
	unsigned int filepos;
	unsigned int index;
	int r;
	timeMs += 500; // prefetch and decode the data for 500ms

	if(timeMs < 0)
		return -1;
	
	/* style sheet initialization */
	stylesheet->type = BITMAP;
	memcpy(stylesheet->palette,m_idx.palette,16);
	*image = NULL;
	//*aimage = NULL;
	/* check current one */
		/* (1) [SUB_TIME START] <NAVTIME> [SUB_TIME STOP] */
	if(timeMs >= lastStartTimeMs && timeMs < lastStopTimeMs) {
		*image = m_spu.image;
		stylesheet->pSub = m_spu.image;
		stylesheet->pAlpha = m_spu.aimage;
		stylesheet->imageheight = m_spu.height;
		stylesheet->imagewidth = m_spu.width;
		//*aimage = m_spu.aimage;
		return(lastStopTimeMs - timeMs);
	}
	
	else {
			index = m_idx.LangIdx;
			//printf("In GetSubtitle: index = %d\n",index);
			if(m_idx.SubLang[index].LangName[0]== 0)
				return -1;
			fseek(m_idx.fp_idx, m_idx.SubLang[index].filepos,SEEK_SET);
		
			while(1)
			{
				char line[1024];
				if(fgets(line, 1024, m_idx.fp_idx) == NULL) /* eof/error */
				break;
				if (*line == 0 || *line == '\r' || *line == '\n' || *line == '#')
	    			continue;
				else if (strncmp("timestamp:", line, 10) == 0)
				{
					// get timestamp and filepos
					if(sscanf(line, "timestamp: %d:%d:%d:%d, filepos: %x", &startH, &startM, &startS, &startMs, &filepos) != 5) {
					return -1;
					}
					
					startTimeMs = m_idx.delay + ((startH * 60 + startM) * 60 + startS) * 1000 + startMs;
					
					if(timeMs < startTimeMs) 
						break;
					lastStartTimeMs = startTimeMs;
					lastFilepos = filepos;
				}
					
				else if (strncmp("id:", line, 3) == 0)
					{
					printf("reach the end of the timestamp\n");		
					break;
					}
				else
					{
					//printf("error in searching idx timestamp\n");
					continue;
					}
			}
				if(timeMs >lastStopTimeMs)	/* (2) [SUB_TIME START] [SUB_TIME STOP] <NAVTIME> */
				{
					if((lastFilepos != -1)&&(lastStartTimeMs != 0)&&((lastStartTimeMs > lastStopTimeMs)||(lastStopTimeMs ==0)))
					{
						if(fseek(m_sub.fp_sub, lastFilepos,SEEK_SET)==-1)return -1;
					//	printf("sub open filepos at %x\n",lastFilepos);
						if((r=SUB_run(&m_sub, &m_spu)) != -1) {
							int64_t pts = (long long)lastStartTimeMs * 90LL + m_basePTS;
							m_pInPinSpu->PrivateInfo(PRIVATEINFO_SPU_DVDV_PALETTE, (BYTE *)&spuPalette, sizeof(SPUDVDVPALETTE));
							m_pInPinSpu->PrivateInfo(PRIVATEINFO_PTS, (BYTE*)&pts, sizeof(int64_t));
							m_pInPinSpu->ReceiveData((BYTE *)(m_sub.packet), m_sub.packet_size);
						}
						if((r==-1)||(m_spu.packet == NULL))return -1;
						*image = m_spu.image;
						stylesheet->pSub = m_spu.image;
						stylesheet->pAlpha = m_spu.aimage;
						stylesheet->imageheight = m_spu.height;
						stylesheet->imagewidth = m_spu.width;
					//	*aimage = m_spu.aimage;
						lastStopTimeMs =lastStartTimeMs + m_spu.end_pts;
						return (lastStopTimeMs-timeMs);
					}
				}
				else	/* (3) <NAVTIME> [SUB_TIME START] [SUB_TIME STOP] */
				{
					#if 0				
					printf("lastfilepos %x laststarttime=%d\n",lastFilepos,lastStartTimeMs);
					if((lastFilepos != -1)&&(lastStartTimeMs != 0))
					{
						if(fseek(m_sub.fp_sub, lastFilepos,SEEK_SET)==-1)return -1;
						printf("sub open filepos at %x\n",lastFilepos);
						
						if((r=SUB_run(&m_sub, &m_spu)) != -1) {
							int64_t pts = (long long)lastStartTimeMs * 90LL;
							m_pInPinSpu->PrivateInfo(PRIVATEINFO_SPU_DVDV_PALETTE, (BYTE *)&spuPalette, sizeof(SPUDVDVPALETTE));
							m_pInPinSpu->PrivateInfo(PRIVATEINFO_PTS, (BYTE*)&pts, sizeof(int64_t));
							m_pInPinSpu->ReceiveData((BYTE *)(m_sub.packet), m_sub.packet_size);
						}
					
						if((r==-1)||(m_spu.packet == NULL))return -1;
						*image = m_spu.image;
						stylesheet->pSub = m_spu.image;
						stylesheet->pAlpha = m_spu.aimage;
						stylesheet->imageheight = m_spu.height;
						stylesheet->imagewidth = m_spu.width;
					//	*aimage = m_spu.aimage;
						lastStopTimeMs =lastStartTimeMs + m_spu.end_pts;
						return (lastStopTimeMs-timeMs);
					}
					#endif
					return SubtitleSeek(timeMs, stylesheet, image);
				}
			return -1;
		}
}



int IDXSUBParser ::SubtitleSeek(int timeMs, SUBTITLE_STYLE_SHEET *stylesheet, char **text)
{
	lastFilepos = -1;
	lastStartTimeMs= 0;
	lastStopTimeMs= 0;
	return GetSubtitle(timeMs,stylesheet,text);
}

int IDXSUBParser ::SwitchLang(char *LangName)
{

	do{
		m_idx.LangIdx++;
		if(m_idx.LangIdx >31)
			m_idx.LangIdx = 0;
		if(m_idx.LangIdx==m_idx.defaultLangIdx){
			printf("LangIdx===%d\n",m_idx.defaultLangIdx);	
			return -1;
		}
		if(m_idx.SubLang[m_idx.LangIdx].index != IDX_INDEX_NOT_EXIST){
			strcpy(LangName,m_idx.SubLang[m_idx.LangIdx].LangName);
			printf("LangIdx=%d,LangName=%s\n",m_idx.LangIdx,LangName);	
			return 0;
		}
	}
	while(1);
}

int IDXSUBParser ::GetDefaultLang(char *LangName){
	m_idx.LangIdx = m_idx.defaultLangIdx;
	printf("LangIdx=%d,LangName=%s\n",m_idx.LangIdx,m_idx.SubLang[m_idx.LangIdx].LangName);
	strcpy(LangName,m_idx.SubLang[m_idx.defaultLangIdx].LangName);
			return 0;
}


static int RGB2YUV (int c)
{
    int R = (c & 0xff0000) >> 16 ;
    int G = (c & 0xff00) >> 8 ;
    int B = (c & 0xff) ;

	return ((((257*R + 504*G +  98*B)/1000 +  16) & 0xff) << 16) +
			((((-148*R - 291*G + 439*B)/1000 + 128) & 0xff) << 8) + 
			(((439*R - 368*G -  71*B)/1000 + 128) & 0xff) ;
}

void IDXSUBParser::ConfigureSPUDecoder(CFilterSpu *pSPUDecoder) {
	IPin *pPin;
    SPUCONFIG spuConfig;
	int spicOnOff = 1;

	m_pSPUDecoder = pSPUDecoder;

	m_pSPUDecoder->FindPin(&pPin, "Input Pin");
	m_pInPinSpu = dynamic_cast<CInPinSpu*>(pPin);

	m_pInPinSpu->Flush();

	// initialize spu decoder
	spuConfig.type = SP_DVD_FOR_DIVX_TYPE;
	spuConfig.screen_width = m_idx.orig_frame_width; 
	spuConfig.screen_height = m_idx.orig_frame_height;
	m_pInPinSpu->PrivateInfo(PRIVATEINFO_SPU_CONFIG, (BYTE *)&spuConfig, sizeof(SPUCONFIG));

	// initialize spu pallete
	for(int i = 0 ; i<16 ; i++)
		spuPalette.color[i] = RGB2YUV(m_idx.palette[i]);

	m_pInPinSpu->PrivateInfo(PRIVATEINFO_SPU_DVDV_PALETTE, (BYTE *)&spuPalette, sizeof(SPUDVDVPALETTE));
	m_pInPinSpu->PrivateInfo(PRIVATEINFO_SPU_ON_OFF, (BYTE *)&spicOnOff, sizeof(int));
}

int IDXSUBParser ::GetLangNum(){
	int i, cnt;

	for(i = 0, cnt = 0 ; i < 32 ; i++) {
		if(m_idx.SubLang[i].index != IDX_INDEX_NOT_EXIST)
			cnt++;
	}

	return cnt;
}

void IDXSUBParser :: SetBasePTS(int64_t pts) {
	m_basePTS = pts;
}

