#include "ma_ff8.h"

char *CMassFF8::GetIdent( void )
{
	static char Ident[] = "FI(Final Fantasy 8)";

	return Ident;
}

char *CMassFF8::GetExtension( void )
{
	static char Ext[] = "fi";
	return Ext;
}

int	 CMassFF8::CheckFileType( void )
{
	FILE	*f;
	char	str[ FileNameWithPathMaxLen ];

	if ( massf == NULL )
		return 0;

	fseek( massf, 0, SEEK_END );
	if ( ftell( massf ) % SizeOfFiRec != 0 )
		return 0;

	sprintf( str, "%s%s", MassFilePath, MassFileName );

	//check .fs
	strcpy( fsName, str );
	strcat( fsName, ".fs" );
	
	f = fopen( fsName, "rb" );
	if ( f == NULL )
		return 0;
	fclose( f );

	//check .fl
	strcpy( flName, str );
	strcat( flName, ".fl" );

	fl = fopen( flName, "rb" );
	if ( fl == NULL )
		return 0;
	fclose( fl );

	return 1;
}

void CMassFF8::GetFileMainInfo( void )
{
	files_count = 0;

	if ( massf == NULL )
		return;

	fseek( massf, 0, SEEK_END );
	filesize = ftell( massf );

	files_count = filesize / SizeOfFiRec;
}

int	 CMassFF8::ReadRec( long num )
{
	if ( massf == NULL ) 
		return 0;
	if (( (unsigned long)num >= files_count ) && ( num != -1 ))
		return 0;
	if (( num == -1 ) && 
		(( ! next_set ) || ((unsigned long)next_rec_num >= files_count )) )
		return 0;
	
	memset( &FileRec, 0, sizeof( FileRec ) );

	fl = fopen( flName, "rb" );
	if ( fl == NULL )
		return 0;

	//seek
	if ( num == -1 ) {
		if ( fseek( massf, next_rec_pos, SEEK_SET ) != 0 ) {
			fclose( fl );
			return 0;
		}
		if ( fseek( fl, next_name_rec_pos, SEEK_SET ) != 0 ) {
			fclose( fl );
			return 0;
		}
		pos = next_rec_num;
		num = next_rec_num;
	}
	else {
		if ( fseek( massf, SizeOfFiRec * num, SEEK_SET ) != 0 ) {
			fclose( fl );
			return 0;
		}
		pos = 0;
	}

	int		i;
	char	c, str[ FileNameWithPathMaxLen ];
	//read
	if ( fread( &fiRec, SizeOfFiRec, 1, massf ) != 1 ) {
		fclose( fl );
		return 0;
	}
	//read name from .fl
	do {
		i = 0;
		do {
			fread( &c, 1, 1, fl );
			str[ i++ ] = c;
		} while ( c != 0xA );
		pos++;
	} while ( pos <= (unsigned long)num );

	str[ i-2 ] = 0;

	//set position of the next
	next_rec_pos = ftell( massf );
	next_name_rec_pos = ftell( fl );

	fclose( fl );

	if ( num == -1 )
		next_rec_num ++;
	else
		next_rec_num = num + 1;
	if ( num + 1 >= (long)files_count )
		next_set = false;
	else
		next_set = true;
	
	//get info
	FileRec.SetName( &str[7] );
	FileRec.offset = fiRec.offset;
	FileRec.size = fiRec.size;
	FileRec.flag = fiRec.packed;
//	if ( fiRec.packed == 1 )
//		strcat( FileRec.name, "#" );

	return 1;
}
/*
void CMassFF8::SaveNextPos( void )
{
	save.next_rec_num = next_rec_num;
	save.next_rec_pos = next_rec_pos;
	save.next_set = next_set;
	save.next_name_rec_pos = next_name_rec_pos;
}

void CMassFF8::LoadNextPos( void )
{
	next_rec_num = save.next_rec_num;
	next_rec_pos = save.next_rec_pos;
	next_set = save.next_set;
	next_name_rec_pos = save.next_name_rec_pos;
}
*/
unsigned long CMassFF8::Extract( unsigned long offset, unsigned long size, unsigned char *output )
{
	return 0;

/*	FILE			*fs;
	unsigned long	insize;
	unsigned long	start, end, ctrlpos;

	unsigned long	pos, outpos, i, ofs, sz, src;
	unsigned char	control, ch, ctrlcnt, cha[2], okctrlpos, okoutsize, s;


	if (( offset != 0 ) && ( offset != ex_last_ofs ))
		return 0;

	if ( offset == 0 )
		ex_last_pos = 4;			//prve 4 bytes su info

	fs = fopen( fsName, "rb" );
	if ( fs == NULL )
		return 0;

	if ( offset + size > FileRec.size )
		return 0;

	//if no compression
	if ( FileRec.flag == 0 ) {
		if ( fseek( fs, FileRec.offset + offset, SEEK_SET ) != 0 )
			return 0;
		s = fread( output, 1, size, fs );
	}
		//compression
	else {

		//nejde extraktovat po castiach, pretoze v dalsej casti moze byt
		//odkaz do casti predchadzajucej, odkazy mozu byt az do -4096b ?
		fseek( fs, FileRec.offset + ex_last_pos, SEEK_SET );
		pos = 0;
		outpos = 0;
		ctrlcnt = 0;

		do {
			if ( ctrlcnt == 0 ) {
				//uchovam si poziciu, aby som ju mohol vratit ak som nahodou na konci [size]
				okctrlpos = pos; okoutsize = outpos;
				fread( &control, 1, 1, fs ); pos ++;
				ctrlcnt = 8;
			}

			if ( outpos >= size )
				break;

			if (( control & 1 ) == 1 ) {
				fread( &ch, 1, 1, fs ); pos++;
				output[ outpos++ ] = ch;
			}
			else {
				fread( cha, 2, 1, fs ); pos += 2;
				sz = ( cha[1] & 0xF ) + 3;
				ofs = (( cha[1] & 0xF0 ) << 4 ) + cha[0];
				src = ( outpos - 18 - ofs ) & 0xFFF;
				src = outpos - src;

				if ( outpos + sz > size )
					break;

				memcpy( &output[ outpos ], &output[ src ], sz );
				outpos += sz;
			}

			control >>= 1;
			ctrlcnt --;
		} while ( outpos < size );

		if ( ctrlcnt == 0 ) {
			okctrlpos = pos; okoutsize = outpos;
		}

		ex_last_ofds = offset + okoutsize;
		ex_last_pos += okctrlpos;
		s = okoutsize;

/*
		memset( output, '?', size );
		fseek( fs, FileRec.offset, SEEK_SET );
		fread( &insize, 4, 1, fs );

		start = offset;
		if ( start > insize )
			start = insize;
		end = offset + size;
		if ( end > insize )
			end = insize;

		if ( start != end ) {
			if ( fseek( fs, FileRec.offset + 4 + start, SEEK_SET ) != 0 )
				return 0;
			if ( fread( output, end - start, 1, fs ) != 1 )
				return 0;
		}

	}

	fclose( fs );

	return s;
*/
}

int CMassFF8::GetFlags( void )
{
	return ma_flag_extract_only_whole_file;
}

int CMassFF8::ExtractWholeFile( FILE *fout )
{
#define FF8bufferSize	4096

	unsigned char	buf[ FF8bufferSize * 3 ];
	unsigned long	pos, size;

	FILE			*fs;
	unsigned long	bufs;

	long			outpos, ofs, sz, src, i;
	unsigned char	control, ch, ctrlcnt, cha[2];

	//open data file
	fs = fopen( fsName, "rb" );
	if ( fs == NULL )
		return 0;

	//if no compression
	if ( FileRec.flag == 0 ) {
		if ( fseek( fs, FileRec.offset, SEEK_SET ) != 0 )
			return 0;

		pos = 0; size = FF8bufferSize;
		while ( pos < FileRec.size ) {

			if ( pos + size > FileRec.size )
				size = FileRec.size - pos;
			
			if ( fread( buf, 1, size, fs ) != size )
				return 0;

			if ( fwrite( buf, 1, size, fout ) != size )
				return 0;

			pos += size;
		}
	}
		//uncompression ... learned from ficedula's doc
	else {

		//relative offsets are max 12bits = 4095 bytes, so i have buffer for data
		// and im uncompressing it there, when its full i write it, so there are allways
		// at least 4095 bytes for offseting to work
		fseek( fs, FileRec.offset, SEEK_SET );
		fread( buf, 4, 1, fs );
		pos = 0;
		outpos = 0;
		ctrlcnt = 0;
		bufs = 0;

		do {
			if ( ctrlcnt == 0 ) {
				//uchovam si poziciu, aby som ju mohol vratit ak som nahodou na konci [size]
//				okctrlpos = pos; okoutsize = outpos;
				fread( &control, 1, 1, fs ); pos ++;
				ctrlcnt = 8;
			}

			if (( control & 1 ) == 1 ) {
				fread( &ch, 1, 1, fs ); pos++;
				buf[ outpos++ ] = ch;
			}
			else {
				fread( cha, 2, 1, fs ); pos += 2;
				sz = ( cha[1] & 0xF ) + 3;
				ofs = (( cha[1] & 0xF0 ) << 4 ) + cha[0];
				src = ( outpos - 18 - ofs ) & 0xFFF;
				src = outpos - src;

				//if offset goes beyond beginning of file, write out zeroes
				if ( src < 0 ) {
					i = -src;
					if ( sz < i )
						i = sz;
					memset( &buf[ outpos ], 0, i );
					outpos += i;	//move outpointer
					sz -= i;		//sub zereoes size from rest
					src += i;		//move source
				}

				//if copied block goes after current position, copy the same thing again.
				if ( src + sz > outpos ) {
					i = 0;
					while( i < sz ) {
						buf[ outpos + i ] = buf[ src + i ];
						i++;
					}
				}
				else 
					memcpy( &buf[ outpos ], &buf[ src ], sz );

				outpos += sz;
			}

			if ( outpos > FF8bufferSize * 2 ) {
				fwrite( buf, FF8bufferSize, 1, fout );
				outpos -= FF8bufferSize;
				//i dont want to overleap copied buffers
				memcpy( &buf[ 0 ], &buf[ FF8bufferSize ], FF8bufferSize );
				memcpy( &buf[ FF8bufferSize ], &buf[ 2*FF8bufferSize ], FF8bufferSize );
				bufs++;
			}

			control >>= 1;
			ctrlcnt --;
		} while ( bufs * FF8bufferSize + outpos < FileRec.size );

		fwrite( buf, outpos, 1, fout );

//		if ( ctrlcnt == 0 ) {
//			okctrlpos = pos; okoutsize = outpos;
//		}

//		ex_last_ofs = offset + okoutsize;
//		ex_last_pos += okctrlpos;
//		s = okoutsize;

/*
		memset( output, '?', size );
		fseek( fs, FileRec.offset, SEEK_SET );
		fread( &insize, 4, 1, fs );

		start = offset;
		if ( start > insize )
			start = insize;
		end = offset + size;
		if ( end > insize )
			end = insize;

		if ( start != end ) {
			if ( fseek( fs, FileRec.offset + 4 + start, SEEK_SET ) != 0 )
				return 0;
			if ( fread( output, end - start, 1, fs ) != 1 )
				return 0;
		}
*/
	}

	fclose( fs );

	return 1;
}
