/*==============================================================================

FICHIER     : [dvdcell.c]

DATE        : 2006/02/0015 21:54:36

CREATEUR    : [Linux!jef]

COMMENTAIRE :
		Released under GPL license, see gnu.org
================================================================================

==============================================================================*/
#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>

#include "const.h"
#include "globals.h"
#include "dvdinfo.h"
#include "dvdcell.h"
#include "systools.h"
#include "dvdtools.h"

/*@$#[dvdcell.c] static proto. AutoProtoSigV1.1. date: 2009/02/04 23:16:18 */
#include "proto.h"
#ifdef __cplusplus
extern "C" {
#endif
/* dvdcell.c */
static int IsSelected PROTO((Cell_t *c, int noPisteVideo));
static int CellExist PROTO((CellArray_t *ca, int vts, uint32_t *start, uint32_t *end));
static void UnSelectLastCell PROTO((CellArray_t *ca));
#ifdef __cplusplus
}
#endif
/*@$% end of AutoProtoSigV1.1 (Dont remove this line) [-I ../include]*/

/*------------------------------------------------------------------------------
	NEWCELL-
Linux!jef 2005/12/28 21:15:15
------------------------------------------------------------------------------*/

Cell_t * NewCell( CellArray_t * ca )
{
	Cell_t * c;
	int idx = ca->nbCells;
	int size = (idx + 1) * sizeof( Cell_t );

	ca->cells =(Cell_t *)realloc( ca->cells, size );
	c = ca->cells + idx;
	memset( c, 0, sizeof(*c));
	c->idx = idx;
	ca->nbCells++;
	return( c );
}
/*------------------------------------------------------------------------------
	NEWTITLESET-
Linux!jef 2006/01/16 21:21:20
------------------------------------------------------------------------------*/

TitleSet_t * NewTitleSet( TitleArray_t * ta )
{
	TitleSet_t * t;
	int idx = ta->nbTitles;
	int size = (idx + 1) * sizeof( TitleSet_t );

	ta->titles =(TitleSet_t *)realloc( ta->titles, size );
	t = ta->titles + idx;
	memset( t, 0, sizeof(*t));
	ta->nbTitles++;
	return( t );
}

/*------------------------------------------------------------------------------
	NEWVOBU-
Linux!jef 2006/01/18 22:15:52
------------------------------------------------------------------------------*/

Vobu_t * NewVobu( VobuArray_t * va, uint32_t oldSector )
{
	Vobu_t * v;
	int idx = va->nbVobu;
	int size = (idx + 1) * sizeof( Vobu_t );
	int i;

	va->vobus =(Vobu_t *)realloc( va->vobus, size );
	v = va->vobus + idx;
	memset( v, 0, sizeof(*v));
	for( i = 0; i < 8; i++ ) v->firstAudio[i] = -1;
	for( i = 0; i < 32; i++ ) v->firstSubp[i] = -1;
	v->firstVideo = -1;
	v->idx = idx;
	v->oldSector = oldSector;
//!!	DBG('b',fprintf(stderr,"%s: idx: %d\n", __FUNCTION__, idx ););
///	DBG('v',fprintf(stderr,"%s: oldSector %u\n", __FUNCTION__, oldSector ););

	va->nbVobu++;
	return( v );
}


/*------------------------------------------------------------------------------
	ISSELECTED-
Linux!jef 2005/12/29 21:10:05
------------------------------------------------------------------------------*/

static int IsSelected( Cell_t * c, int noPisteVideo )
{
	Piste_t * piste = GetPiste( noPisteVideo );
	int vts = piste->vts; // Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr;
	int vts_ttn;
	pgcit_t *vts_pgcit;
	pgc_t *pgc;
	int i,j;

	if( vts != c->vts ) {
		DBG('b',fprintf(stderr,"%s: rejected because vts %d != c->vts %d\n", __FUNCTION__,vts, c->vts ););
		return( 0 );
	}
	vts_pgcit = piste->vts_pgcit; // Ifo[vts]->vts_pgcit;
	vts_ttn = Ifo_zero->tt_srpt->title[noPisteVideo].vts_ttn;
//	pgc = vts_pgcit->pgci_srp[Ifo[title_set_nr]->vts_ptt_srpt->title[vts_ttn - 1].ptt[0].pgcn - 1].pgc;
	for( j = 0; j < vts_pgcit->nr_of_pgci_srp; j++ ) {
		int cell = 0;

		pgc = vts_pgcit->pgci_srp[j].pgc;
		for( i = 0; i < pgc->nr_of_programs; i++ ) {
			int next;

			if( i == pgc->nr_of_programs - 1)
				next = pgc->nr_of_cells + 1;
			else
				next = pgc->program_map[i + 1];

			while (cell < next - 1) {
				unsigned int s = pgc->cell_playback[cell].first_sector;
				unsigned int e = pgc->cell_playback[cell].last_sector;

				if( c->startSector >= s && c->startSector <= e )	return( 1 );
				cell++;
			}
		}
	}
	DBG('b',fprintf(stderr,"%s: (%u-%u) rejected because not in range\n", __FUNCTION__, c->startSector, c->lastSector ););
	DBG('b',fprintf(stderr,"%s: vts_pgcit->nr_of_pgci_srp=%d\n", __FUNCTION__, vts_pgcit->nr_of_pgci_srp ););

	return( 0 );
}
/*------------------------------------------------------------------------------
	CELLEXIST-
Linux!jef 2006/01/25 01:11:11
------------------------------------------------------------------------------*/

static int CellExist( CellArray_t * ca, int vts, uint32_t * start, uint32_t * end )
{
	int i;

	for( i = 0; i < ca->nbCells; i++ ) {
		Cell_t * c = ca->cells + i;

		if( c->vts == vts ) {
			if( c->startSector <= *start && c->lastSector >= *end ) return( 1 );
#if 0
			if( c->startSector <= *start ) {
				*start = c->lastSector + 1;
			}
			else {
				*end = c->startSector - 1;
			}
#endif
		}
	}
	if( *start >= *end )	return( 1 );
	return( 0 );
}
/*------------------------------------------------------------------------------
	UNSELECTLASTCELL-
Linux!jef 2007/01/19 22:52:11
------------------------------------------------------------------------------*/

static void UnSelectLastCell( CellArray_t * ca )
{
	int i;

	for( i = ca->nbCells -1; i >= 0; i-- ) {
		Cell_t * c = ca->cells + i;

		if( c->selected ) {
			c->selected = 0;
			break;
		}
	}
}

/*------------------------------------------------------------------------------
	BUILDCELLS-
Linux!jef 2005/12/28 21:18:16
------------------------------------------------------------------------------*/

int BuildCells( int noPisteVideo, CellArray_t * ca, int lastF, int skipAngle )
{
	int nrTS = Ifo_zero->vmgi_mat->vmg_nr_of_title_sets; /* Number of title sets */
	int i,j,k;

	DBG('b',fprintf(stderr,"%s: nrTS=%d noPisteVideo=%d\n", __FUNCTION__, nrTS, noPisteVideo ););
	for( k = 1; k <= nrTS; k++ ) {
		ifo_handle_t * ifo = Ifo[k];
		int vts_ttn, title_set_nr;
		int nbChapter;

		if( !ifo )		continue;
		if( !ifo->vtsi_mat )	continue;
		DBG('b',fprintf(stderr,"VTS: %d PGCS: %d ifo: %p\n", k, ifo->vts_pgcit->nr_of_pgci_srp, ifo ););

		vts_ttn = Ifo_zero->tt_srpt->title[noPisteVideo].vts_ttn; /* Title number within VTS */
DBG('b',fprintf(stderr,"NumberOfAngles: %d\n", Ifo_zero->tt_srpt->title[noPisteVideo].nr_of_angles ););
		title_set_nr = Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr; /* Video Title Set number, VTSN */
DBG('b', fprintf(stderr,"nr_of_srpts=%d\n", Ifo[title_set_nr]->vts_ptt_srpt->nr_of_srpts ););

		g_assert( vts_ttn <= Ifo[title_set_nr]->vts_ptt_srpt->nr_of_srpts );
		nbChapter = Ifo[title_set_nr]->vts_ptt_srpt->title[vts_ttn - 1].nr_of_ptts;
DBG('b', fprintf(stderr,"(nbChapter) nr_of_ptts=%d\n", nbChapter ););
/* vts_ttn -1 because array is 0 based and number is 1 based */
		i = Ifo[title_set_nr]->vts_ptt_srpt->title[vts_ttn - 1].ptt[0].pgcn - 1;
DBG('b', fprintf(stderr,"title_set_nr=%d vts_ttn=%d pgcIndex=%d nbPgc=%d\n", title_set_nr, vts_ttn, i, ifo->vts_pgcit->nr_of_pgci_srp ););
//		for( i = 0; i < nbChapter; i++ ) {
		if( i < ifo->vts_pgcit->nr_of_pgci_srp ) {
			pgc_t * pgc = ifo->vts_pgcit->pgci_srp[i].pgc;
			cell_playback_t * cell_playback;
			cell_position_t * cell_position;
			int nr;

			g_assert( i < ifo->vts_pgcit->nr_of_pgci_srp );

			cell_playback = pgc->cell_playback;
			cell_position = pgc->cell_position;
			nr = pgc->nr_of_cells;
			DBG('b',fprintf(stderr,"NrOfCells: %d\n", nr ););
			for( j = 0; j < nr; j++ ) {
				uint32_t start = cell_playback[j].first_sector;
				uint32_t end = cell_playback[j].last_sector;

DBG('b',fprintf(stderr,"%s: cell(%d) b_mode=0x%x b_type=0x%x  at %u=>%u ", __FUNCTION__, j, cell_playback[j].block_mode, cell_playback[j].block_type, start, end ););
DBG('b',fprintf(stderr,"vobid: %d zero_1: %d cell_id: %d\n",cell_position[j].vob_id_nr, cell_position[j].zero_1, cell_position[j].cell_nr ););
				if( cell_position[j].zero_1 )	continue;

#if 0
				if( cell_playback[j].block_type == 1 ) {
					for( ++j; j < nr; j++ ) {
						if( cell_playback[j].block_type == 1 &&  cell_playback[j].block_mode == 3 )	break;
					}
					end = cell_playback[j].last_sector;
				}
#endif


				if( !CellExist( ca, k, &start, &end ) ) {
					Cell_t * c = NewCell( ca );

					c->vts = k;
					c->ifo = ifo;
					c->pgc = pgc;
					c->startSector = start;
					c->lastSector = end;
					c->selected = IsSelected( c, noPisteVideo );
					c->chapter = j;
					if( skipAngle ) {
/* FIXME: a l'interieur d'un angle block on ne devrait prendre qu'une cell sur deux ! take first, skip, take, ... */
						if( cell_playback[j].block_type == 1 && ( cell_playback[j].block_mode == 2 || cell_playback[j].block_mode == 3) )
							c->selected = 0;
					}
				}
			}
		}
		else { /* We have to generate a fake cell in order to generate VTS_xx... */
			Cell_t * c = NewCell( ca );
			pgc_t * pgc = ifo->vts_pgcit->pgci_srp[0].pgc;

			c->vts = k;
			c->ifo = ifo;
			c->pgc = pgc;
			c->startSector = 0;
			c->lastSector = 0;
			c->selected = 0;
			c->chapter = 0;
		}
	}
	if( lastF )	UnSelectLastCell( ca );

	DBG('b',fprintf(stderr,"NrCells: %d\n", ca->nbCells );
		long long tSize = 0;
		for( i = 0; i < ca->nbCells; i++ ) {
			Cell_t * c = ca->cells + i;
			long long size;

			fprintf(stderr,"Cell%d: ", i);
			size = (long long)SECTOR_SZ(c) * (long long)SECTOR_SIZE;
			tSize += size;
			fprintf(stderr,"vts: %d ", c->vts );
			fprintf(stderr,"start: %u end: %u ", c->startSector, c->lastSector );
			fprintf(stderr,"size: %s ", LLSize2Giga( size ) );
			fprintf(stderr,"selected: %d\n", c->selected );
		}
		fprintf(stderr,"Total size: %s\n", LLSize2Giga( tSize ) );
	);
	return( 0 );
}

/*------------------------------------------------------------------------------
	FREECELLARRAY-
Linux!jef 2005/12/28 21:30:33
------------------------------------------------------------------------------*/

void FreeCellArray( CellArray_t * ca )
{
	int i;

	for( i = 0; i < ca->nbCells; i++ ) {
		Cell_t * c = ca->cells + i;
		VobuArray_t * va = &c->va;

		if( va->nbVobu ) {
			free( va->vobus );
			va->nbVobu = 0;
		}
	}
	if( ca->nbCells ) {
		free( ca->cells );
	}
	ca->cells = NULL;
	ca->nbCells = 0;
}

/*------------------------------------------------------------------------------
	COUNTSELECTEDCELLS-
Linux!jef 2006/01/26 21:29:53
------------------------------------------------------------------------------*/

int CountSelectedCells( CellArray_t * ca )
{
	int i;
	int count = 0;

	for( i = 0; i < ca->nbCells; i++ ) {
		Cell_t * c = ca->cells + i;

		if( c->selected )	count++;
	}
	return( count );
}

/***************************************************************************//**
 *	COUNTTOTALSECTORS-
 * @date	2010/04/22 23:47:45
 * @author	jef-Linux
 * @brief
 *	Pas d'explication
 * @details
 *	Pas de details
 * @param[in]	Pas de detail
 * @param[out]	Pas de detail
*******************************************************************************/
int CountTotalSectors( CellArray_t * ca )
{
	int totalSectors = 0;
	int i;
/* Compute total sectors size */
	for( i = 0; i < ca->nbCells; i++ ) {
		Cell_t * c = ca->cells + i;

		if( c->selected )	totalSectors += SECTOR_SZ(c);
	}
	return( totalSectors );
}

/***************************************************************************//**
 *	COUNTDONESECTORS-
 * @date	2010/04/22 23:48:51
 * @author	jef-Linux
 * @brief
 *	Pas d'explication
 * @details
 *	Pas de details
 * @param[in]	Pas de detail
 * @param[out]	Pas de detail
*******************************************************************************/
int CountDoneSectors( CellArray_t * ca )
{
	int doneSectors = 0;
	int i;

/* Compute already done sectors size */
	for( i = 0; i < ca->nbCells; i++ ) {
		Cell_t * c = ca->cells + i;

		if( c->done )		doneSectors += SECTOR_SZ(c);
	}
	return( doneSectors );
}
/*------------------------------------------------------------------------------
	DUMPVOBUS-
Linux!jef 2006/01/18 23:06:39
------------------------------------------------------------------------------*/

void DumpVobus( Cell_t * c )
{
	int i;

	DBG('b',fprintf(stderr,"Vobus: number: %d\n", c->va.nbVobu ););
	for( i = 0; i < c->va.nbVobu; i++ ) {
		Vobu_t * v = c->va.vobus + i;

		DBG('b',fprintf(stderr,"Vobus%d: (%u)=>(%u,%u)\n", v->idx, v->oldSector, v->newSector, v->newSector + v->size ););
	}
}
