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

FICHIER     : [dvdcopy.c]

DATE        : 2005/12/0001 22:04:33

CREATEUR    : [Linux!jef]

COMMENTAIRE :
		Released under GPL license, see gnu.org
================================================================================
	COPY sans garder les menus
==============================================================================*/
#define __USE_LARGEFILE64
#define _LARGEFILE64_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/time.h>
#include <sys/stat.h>

#include "dvdformat.h"
#include "dvdinfo.h"
#include "dvdtools.h"
#include "dvdcopy.h"
#include "const.h"
#include "dvdbackup.h"


#define IsValidAudioTrack( pgc, t )		(( pgc->audio_control[t] >> 8) != 0 )
#define IsValidSubpTrack( pgc, t )		(( pgc->subp_control[t] >> 24) != 0 )

static char *_AudioFormat[7] = { "ac3", "?", "mpeg1", "mpeg2", "lpcm ", "sdds ", "dts" };
// static char *AudioType[5] = { "Undefined", "Normal", "Impaired", "Comments1", "Comments2" };
static char *SubpType[16] = {
	"", "Normal", "Large", "Children", "reserved", "Normal_CC",
	"Large_CC", "Children_CC",
	"reserved", "Forced", "reserved", "reserved", "reserved", "Director",
	"Large_Director", "Children_Director"
};

static char TitreDvd[128];

/*------------------------------------------------------------------------------
	NROFSUBP-
Linux!jef 2006/01/25 21:43:53
------------------------------------------------------------------------------*/

static int NrOfSubp( vtsi_mat_t * vtsi_mat, pgc_t * pgc )
{
	int i;
	int count = 0;

	for( i = 0; i < vtsi_mat->nr_of_vts_subp_streams; i++ ) {
		if( IsValidSubpTrack( pgc, i ) )	count++;
	}
	return( count );
}


long long GetMenuSize()
{
	int menuSizes[100];
	int ts;
	int i;
	vmgi_mat_t * vmgi_mat;
	vtsi_mat_t * vtsi_mat;
	pgcit_t * vts_pgcit;
	pgc_t * pgc;
	long long menuSize;

	vmgi_mat = Ifo_zero->vmgi_mat;
	memset( menuSizes, 0, sizeof(menuSizes));

	menuSizes[0] = vmgi_mat->vmg_last_sector;

	for( ts = 1; ts <= Ifo_zero->vts_atrt->nr_of_vtss; ts++ ) {
		vtsi_mat   = Ifo[ts]->vtsi_mat;
		vts_pgcit  = Ifo[ts]->vts_pgcit;
// fprintf(stderr,"%p %p nr: %d\n", vtsi_mat, vts_pgcit,vts_pgcit->nr_of_pgci_srp );
	        for( i = 0; i < vts_pgcit->nr_of_pgci_srp; i++) {
			pgc = vts_pgcit->pgci_srp[i].pgc;
// fprintf(stderr,"pgc%d: %p\n", i, pgc );
			if( vtsi_mat && (pgc->nr_of_cells >0)) {
				menuSizes[ts] = vtsi_mat->vtstt_vobs + vtsi_mat->vtsi_last_sector +1;
			}
	        }
	}
// fprintf(stderr,"here\n");
	menuSize = 0;
	for( i = 0; i < 100; i++ )	menuSize += (long long)menuSizes[i];
	return( menuSize * SECTOR_SIZE );
}
/*------------------------------------------------------------------------------
	SUBPID-
Linux!jef 2006/02/02 22:33:20
------------------------------------------------------------------------------*/

static int SubpId( unsigned int control )
{
	unsigned char subpc;
	int id = 0;

	subpc = control>>24;
	if ((subpc & 0x80)==0x80) {
		id = 0;

		if( (subpc &0x1F) !=0 )	id = (subpc & 0x1F);
		subpc = control>>16;
		if( (subpc &0x1F) !=0 ) id = (subpc & 0x1F);
		subpc = control>>8;
		if( (subpc &0x1F) !=0 ) id = (subpc & 0x1F);
		subpc = control;
		if( (subpc &0x1F) !=0 ) id = (subpc & 0x1F);
	}
	return( id );
}
/*------------------------------------------------------------------------------
	GETSUBID-
Linux!jef 2006/02/02 22:41:39
------------------------------------------------------------------------------*/

int GetSubId( int noPisteVideo, int noPisteSub )
{
	pgcit_t *vts_pgcit;
	int title_set_nr;
	int vts_ttn;
	pgc_t *pgc;

	vts_pgcit = Ifo[Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr]->vts_pgcit;
	vts_ttn = Ifo_zero->tt_srpt->title[noPisteVideo].vts_ttn;
	title_set_nr = Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr;
	pgc = vts_pgcit->pgci_srp[Ifo[title_set_nr]->vts_ptt_srpt->title[vts_ttn - 1].ptt[0].pgcn - 1].pgc;

	return( SubpId( pgc->subp_control[noPisteSub ] ) );
}


/*------------------------------------------------------------------------------
	AUDIOPID-
Linux!jef 2006/02/02 22:33:20
------------------------------------------------------------------------------*/

static int AudioId( unsigned int control )
{
	return( (control >> 8) & 0x07 );
}

/*------------------------------------------------------------------------------
	GETSUBID-
Linux!jef 2006/02/02 22:41:39
------------------------------------------------------------------------------*/

int GetAudioId( int noPisteVideo, int noPisteAudio )
{
	pgcit_t *vts_pgcit;
	int title_set_nr;
	int vts_ttn;
	pgc_t *pgc;

	vts_pgcit = Ifo[Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr]->vts_pgcit;
	vts_ttn = Ifo_zero->tt_srpt->title[noPisteVideo].vts_ttn;
	title_set_nr = Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr;
	pgc = vts_pgcit->pgci_srp[Ifo[title_set_nr]->vts_ptt_srpt->title[vts_ttn - 1].ptt[0].pgcn - 1].pgc;

	return( AudioId( pgc->audio_control[noPisteAudio ] ) );

}


/*------------------------------------------------------------------------------
	GETSECTOR-
Linux!jef 2005/12/07 22:17:13
------------------------------------------------------------------------------*/

static unsigned long GetSector( chapitre, pgc )
int chapitre;
pgc_t * pgc;
{
	int i;
	int cell = 0;
	unsigned int total = 0;

	for( i = 0; i < pgc->nr_of_programs; i++ ) {
		unsigned int sectors = 0;
		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) {
			sectors += pgc->cell_playback[cell].last_sector - pgc->cell_playback[cell].first_sector + 1;
			cell++;
		}
		total += sectors;
		if ((i + 1) == chapitre )	return( sectors );
	}
	return( total );
}
/*------------------------------------------------------------------------------
	TOTALAUDIOSIZE-
Linux!jef 2006/01/30 23:39:05
------------------------------------------------------------------------------*/

long long TotalAudioSize( int noPisteVideo, int * pDuree )
{
	pgcit_t *vts_pgcit;   vtsi_mat_t *vtsi_mat;
	vmgi_mat_t *vmgi_mat;
	audio_attr_t *audio_attr;
	video_attr_t *video_attr;
	int title_set_nr;
	int vts_ttn;
	pgc_t *pgc;
	long long totalAudioSize = 0;
	int audioKBPS;
	int duree;
	int i;

	vtsi_mat = Ifo[Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr]->vtsi_mat;
	vts_pgcit = Ifo[Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr]->vts_pgcit;
	video_attr = &vtsi_mat->vts_video_attr;
	vts_ttn = Ifo_zero->tt_srpt->title[noPisteVideo].vts_ttn;
	vmgi_mat = Ifo_zero->vmgi_mat;
	title_set_nr = Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr;
	pgc = vts_pgcit->pgci_srp[Ifo[title_set_nr]->vts_ptt_srpt->title[vts_ttn - 1].ptt[0].pgcn - 1].pgc;

	duree = ( pgc->playback_time.hour * 3600 ) + ( pgc->playback_time.minute * 60 ) + pgc->playback_time.second;

	for( i = 0; i < vtsi_mat->nr_of_vts_audio_streams; i++ ) {
		if( IsValidAudioTrack( pgc, i ) ) {
			audio_attr = &vtsi_mat->vts_audio_attr[i];

			if((audio_attr->channels + 1) == 2)
				audioKBPS = 128;
		        else
		        	audioKBPS = 384;
		        totalAudioSize += ((long long)audioKBPS * (long long)duree * 1000LL) / 8LL;
		}
	}
	if( pDuree )	*pDuree = duree;
	return( totalAudioSize );
}
/*------------------------------------------------------------------------------
	AUDIOSIZE-
Linux!jef 2006/01/30 23:44:00
------------------------------------------------------------------------------*/

long AudioSize( int noPisteVideo, int noPisteAudio, pgc_t * pgc )
{
	pgcit_t *vts_pgcit;   vtsi_mat_t *vtsi_mat;
	vmgi_mat_t *vmgi_mat;
	audio_attr_t *audio_attr;
	video_attr_t *video_attr;
	int title_set_nr;
	int vts_ttn;
	int audioKBPS;
	int duree;
	long long size;

	vtsi_mat = Ifo[Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr]->vtsi_mat;
	vts_pgcit = Ifo[Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr]->vts_pgcit;
	video_attr = &vtsi_mat->vts_video_attr;
	vts_ttn = Ifo_zero->tt_srpt->title[noPisteVideo].vts_ttn;
	vmgi_mat = Ifo_zero->vmgi_mat;
	title_set_nr = Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr;

	duree = ( pgc->playback_time.hour * 3600 ) + ( pgc->playback_time.minute * 60 ) + pgc->playback_time.second;

	audio_attr = &vtsi_mat->vts_audio_attr[noPisteAudio];
	if((audio_attr->channels + 1) == 2)
		audioKBPS = 128;
        else
        	audioKBPS = 384;

	size = ((long long)audioKBPS * (long long)duree * 1000LL) / 8LL;
	//DBG('c',fprintf(stderr,"%s: pisteAudio %d KPS: %d duree: %d size: %lld\n", __FUNCTION__, noPisteAudio, audioKBPS, duree, size ););
	return( size );
}

/*------------------------------------------------------------------------------
	SUBLANG-
Linux!jef 2005/12/16 22:07:24
------------------------------------------------------------------------------*/

static unsigned short SubCode( int noPisteVideo, int noSubtitle )
{
	vtsi_mat_t *vtsi_mat;
	subp_attr_t *subp_attr;

	vtsi_mat = Ifo[Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr]->vtsi_mat;

	subp_attr = &vtsi_mat->vts_subp_attr[noSubtitle];
	return( subp_attr->lang_code & 0xFFFF );
}


/*------------------------------------------------------------------------------
	DEFAULTREQUANTFACTOR-
Linux!jef 2005/12/16 23:37:02
------------------------------------------------------------------------------*/

static double DefaultRequantFactor( int noPisteVideo, AudioMap_t * audioMap, SubMap_t * subMap, int useMenuF )
{
	pgcit_t *vts_pgcit;   vtsi_mat_t *vtsi_mat;
	vmgi_mat_t *vmgi_mat;
	audio_attr_t *audio_attr;
	video_attr_t *video_attr;
	int title_set_nr;
	int vts_ttn;
	pgc_t *pgc;
	long long totalSectors;
	long long totalSize;
	long long totalAudioSize = 0;
	long long menuSize = 0;
	int audioKBPS;
	int duree;
	long long audioSize;
	int i;
	double factor;

	vtsi_mat = Ifo[Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr]->vtsi_mat;
	vts_pgcit = Ifo[Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr]->vts_pgcit;
	video_attr = &vtsi_mat->vts_video_attr;
	vts_ttn = Ifo_zero->tt_srpt->title[noPisteVideo].vts_ttn;
	vmgi_mat = Ifo_zero->vmgi_mat;
	title_set_nr = Ifo_zero->tt_srpt->title[noPisteVideo].title_set_nr;
	pgc = vts_pgcit->pgci_srp[Ifo[title_set_nr]->vts_ptt_srpt->title[vts_ttn - 1].ptt[0].pgcn - 1].pgc;

	totalSectors = GetSector( -1, pgc );

	totalSize = totalSectors * SECTOR_SIZE;

	if( totalSize < DVD5_WANTED_BYTES_LL ) {
		//DBG('c',fprintf(stderr,"%s: totalSize: %lld < %lld(DVDSize)\n", __FUNCTION__, totalSize, DVD5_WANTED_BYTES_LL););
		return( 1.0 );
	}

	totalAudioSize = TotalAudioSize( noPisteVideo, &duree );
	audioSize = 0;
	for( i = 0; i < MAX_AUDIO_TRACK; i++ ) {
		if( audioMap->audioTracks[i] ) {
			long long size;

			audio_attr = &vtsi_mat->vts_audio_attr[i];
			if((audio_attr->channels + 1) == 2)
				audioKBPS = 128;
		        else
		        	audioKBPS = 384;

			size = ((long long)audioKBPS * (long long)duree * 1000LL) / 8LL;
			audioSize += size;
			//DBG('c',fprintf(stderr,"%s: pisteAudio %d KPS: %d size: %lld audioSize: %lld\n", __FUNCTION__, i, audioKBPS, size, audioSize ););
		}
	}

	if( useMenuF )	menuSize = GetMenuSize();

	//DBG('c',fprintf(stderr,"%s: totalSize: %lld totalAudioSize: %lld\n", __FUNCTION__, totalSize, totalAudioSize ););
	//DBG('c',fprintf(stderr,"%s: menuSize: %lld\n", __FUNCTION__, menuSize ););

	factor = (double)(totalSize - totalAudioSize) / (double) (DVD5_WANTED_BYTES_LL - audioSize - menuSize );

	factor = factor + (factor / (double) 100 * (double) 3);    // 3 % Reserve

/* Pour eviter de compter plusieurs fois le meme subpicture */
	{
		unsigned short lastCode = -1;

		for( i = 0; i < MAX_SUB_TRACK; i++ ) {
			if( subMap->subTracks[i] ) {
				unsigned short subCode = SubCode( noPisteVideo, i );
				if( subCode != lastCode )	factor = factor + (factor / (double) 100);   // 1 % Reserve pour soustitre
				lastCode = subCode;
			}
		}
	}
	factor = factor + (factor / (double) 200); // 0.5 % Overhead
	if (factor < 1)		factor = 1;
	//DBG('c',fprintf(stderr,"%s: factor: %f\n", __FUNCTION__, factor ););

	return( factor );
}



/*------------------------------------------------------------------------------
	EXECUTEMKISOFS-
Linux!jef 2005/12/20 22:17:17
------------------------------------------------------------------------------*/

int ExecuteMkIsoFs( char * sysCmd )
{
	FILE * fp;
	char line[1024];
	int res = 0;
	int status;

/* re-direct stderr */
	strcat( sysCmd, " 2>&1" );
	//DBG('c',fprintf(stderr,"%s: executing (%s)\n", __FUNCTION__, sysCmd ););
	fp = popen( sysCmd, "r" );
	if( !fp )	 return( -1 );
	while( 1 )
	{
		char * p, * s;

		if( !fgets( line, sizeof(line), fp ) )	break;
		if( !*line )	continue;
		s = line;
		while( *s == ' ' || *s == '\t' )	s++;
// fprintf(stderr,"line(%s)\n", s );
		p = strchr( s, '%' );
		if( p ) {
			double pct;

			*p = 0;
/* locale troubles . => , */
			pct = atof( s );
			pct /= 100.0;
//fprintf(stderr,"pct: %f\n", pct );
		}
	}
	status = pclose( fp );
	if( !res && status ) {
		fprintf(stderr,"%s: retCode=%d\n", __FUNCTION__, status );
		return( -1 );
	}
	return( res );
}
