/* 
 *  IFOParser.cpp 
 *
 *	Copyright (C) Alberto Vigata - January 2000  ultraflask@yahoo.com
 *                 
 *
 *  This file is part of FlasKMPEG, a free MPEG to MPEG/AVI converter
 *	
 *  FlasKMPEG is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *   
 *  FlasKMPEG is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *   
 *  You should have received a copy of the GNU General Public License
 *  along with GNU Make; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
 *
 */

#include "IFOParser.h"
#include <stdio.h>

#include <io.h>
#include <stdlib.h>

#include <sys/types.h>
//#include <unistd.h>
#include <fcntl.h>
#include "..\CArray.h"
#include "ifo.h"
#include "misc.h"
 
static long gAudioTypes[] = {Ac3Audio, Ac3Audio, MpegAudio, MpegAudio, LPCMAudio, DTSAudio, SDDSAudio};
char version[] = "V0.1.1";
extern void ifo_print_audiosub (u_char *ptr);
extern void ifoPrintSPU		(ifo_spu_t *spu, u_int num);
extern void ifoPrintAudio	(ifo_audio_t *audio, u_int num);
extern void ifoPrintTMT		(ifo_t *ifo);
extern void ifoPrint_ptt (ifo_ptt_t *ptt);
extern void ifoPrint_vts_vobu_addr_map (ifo_t *ifo);
extern void ifoPrint_vtsm_vobu_addr_map (ifo_t *ifo);
extern void ifoPrint_vts_cell_addr (ifo_t *ifo);
extern void ifoPrint_vtsm_cell_addr (ifo_t *ifo);
extern void ifoPrint_title_pgci (ifo_t *ifo);
extern void ifoPrintToast (u_char *toast);
extern void ifoPrint_menu_pgci (ifo_t *ifo);
extern void ifoPrint_pgc_cmd (u_char *pgc_ptr);
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CIFOParser *IFOGlobal;

CIFOParser::CIFOParser()
{
   IFOGlobal = this;
   ifo     = NULL;
}

CIFOParser::~CIFOParser()
{
	UnLoad();
}

int CIFOParser::Load(char *file)
{
	int i,j;

	//Initializing...
	this->AudioCount       = 0;
	this->SubpicCount      = 0;
	this->fatal_error_flag = 0;

	if ((fd = open (file, O_RDONLY|_O_BINARY)) < 0) {
		return 0;	
	}
	if (!(ifo = ifoOpen (fd, 0))) {
		return 0;
	}
	ifoPrintVideo (ifo->data[ID_MAT] + IFO_OFFSET_VIDEO);

	if (!ifoIsVTS (ifo)) {
		char *ptr;
		int num;

		if ((num = ifoGetAudio ((char *)ifo->data[ID_MAT] + IFO_OFFSET_AUDIO, &ptr)) > 0)
			ifoPrintAudio ((ifo_audio_t *)ptr, num);
			if(fatal_error_flag){
				ifoClose (ifo);
				close(fd);
				return 0;
			}

		if ((num = ifoGetSPU ((char *)ifo->data[ID_MAT] + IFO_OFFSET_SUBPIC, &ptr)) > 0)
			ifoPrintSPU ((ifo_spu_t *)ptr, num);
			if(fatal_error_flag){
				ifoClose (ifo);
				close(fd);
				return 0;
			}

		//ifoPrintSPU (ifoGetSPU (ifo->data[ID_MAT] + IFO_OFFSET_SUBPIC));

		ifoPrintTMT (ifo);

		ifoPrint_ptt (ifo_get_ptt (ifo));
	}

	if (!ifoIsVMG (ifo)) {
		ifo_print_audiosub (ifo->data[ID_TMT]);
		ifoPrintToast (ifo->data[ID_PTT]);

//		ifoPrint_ptt (ifo_get_ptt (ifo));
	}

	ifoPrint_title_pgci (ifo);
	if(fatal_error_flag){
		ifoClose (ifo);
		close(fd);
		return 0;
	}
/*	ifoPrint_menu_pgci (ifo);
	ifoPrint_vtsm_cell_addr (ifo);
	ifoPrint_vtsm_vobu_addr_map (ifo);
*/
	ifoPrint_vts_cell_addr (ifo);
/*	ifoPrint_vts_vobu_addr_map (ifo);
*/
	ifoClose (ifo);
	close(fd);
/*	for(i=0; i<PGCCount; i++)
		for(j=0; j<first[i].vob_span_count; j++){
			if( first[i].vs[j].start >
		}
*/
	// IFO Parsing is finished
	// Perform miscellaneous routines
	// Set all PGCS parsed flag to 0
	if(pgcs.GetCount()<=0)
		return 0;

	for(i=0; i<pgcs.GetCount(); i++)
		for(j=0; j<pgcs[i].chain_cells.GetCount(); j++)
			pgcs[i].chain_cells[j].parsed = 0;

	int angle_count;
	// for each pgc
	PGCs.SetArraySize( pgcs.GetCount() );
	for(i=0; i<pgcs.GetCount(); i++)
	{
		angle_count = 0;
		while(1){
			// Find the first item that hasn't been parsed
			j=0;
			while( j != pgcs[i].chain_cells.GetCount() )  
			{
				if (pgcs[i].chain_cells[j].parsed==0)
					break;
				j++;
			}
			if( j==pgcs[i].chain_cells.GetCount() )
				// All possible angles were found
				break;
			// j, stores the first not parsed item
			// Create a new pgc.
			PGCs[i].BuiltPGC.SetArraySize( angle_count + 1 );
						
			// BuildPGCAngle
			while(1)
			{
				RenderCell(i, angle_count, j);
				// Set cell as parsed
				pgcs[i].chain_cells[j].parsed=1;
				// Find first cell whose start point
				// is greater than the current cell end point
				int current_cell = j;
				int    next_cell = j+1;

				while( next_cell != pgcs[i].chain_cells.GetCount() )  
				{
					if (pgcs[i].chain_cells[next_cell].start >
						pgcs[i].chain_cells[current_cell].end)
						break;
					next_cell++;
				}
				if( next_cell==pgcs[i].chain_cells.GetCount() )
					// If we've reached the top
					break;
				j = next_cell;
			}
			PGCs[i].BuiltPGC[angle_count].chain_time = pgcs[i].chain_time;
			angle_count++;
		}
	}
	
  // Adjust audio types to actual audio types
  for(i=0; i<AudioCount; i++)
    AudioMode[i] = gAudioTypes[AudioMode[i]];
	return 1;
}
int CIFOParser::RenderCell(int pgc_number, int angle, int cell_to_render)
{
	int vobid, cellid,i;
	CArr<TSpan> cell_spans;

	 vobid = pgcs[pgc_number].chain_cells[cell_to_render].vobid;
	cellid = pgcs[pgc_number].chain_cells[cell_to_render].cellid;

	GetCellSpans( cell_spans, vobid, cellid );
	for(i=0; i<cell_spans.GetCount(); i++)
	{
		PGCs[pgc_number].BuiltPGC[angle].playinfo.AddItem( &cell_spans[i] );
	}
	return 1;
}

int CIFOParser::GetCellSpans(CArr<TSpan>& cell_spans, int vobid, int cellid)
{
	int i;
	for(i=0; i<cell_address.GetCount(); i++)
	{
		if(cell_address[i].vobid  == vobid 
		&& cell_address[i].cellid == cellid)
			break;
	}
	cell_spans = cell_address[i].pos;
	return 1;
}


int CIFOParser::UnLoad(){
	return 1;
}
int CIFOParser::GetAudioCount()
{
    return this->AudioCount;
}

char *CIFOParser::GetAudioID(int id)
{
	if(id >= this->AudioCount)
		return NULL;
    return this->AudioID[id];
}

int CIFOParser::GetSubpicCount()
{
    return this->SubpicCount;
}

int CIFOParser::GetSubpicCLUT(TPGC *pgc, char *clut)
{
    return 0;
}

int CIFOParser::GetPGCCount()
{
    return this->pgcs.GetCount();
}

TPGC *CIFOParser::GetPGC(int id)
{
/*	if(id >= this->PGCCount)
		return NULL;*/
    return NULL;
}

unsigned int CIFOParser::GetPGCTime(TPGC *pgc)
{
    return 0;
}

char *CIFOParser::GetSubpicID(int id)
{
	if(id >= this->SubpicCount)
		return NULL;
    return this->SubpidID[id];
}

TCellAdressInfo& TCellAdressInfo::operator =(TCellAdressInfo& right)
{
	this->cellid = right.cellid;
	pos = right.pos;
	this->vobid  = right.vobid;
	return *this;
}

TPGC& TPGC::operator =(TPGC& right)
{
	this->chain_cells = right.chain_cells;
	this->chain_time  = right.chain_time;
	memcpy( clut, right.clut, sizeof(char)*16*4 );

	return *this;
}
