#include "ma_mea.h"
#include "utools.h"

char *CMassMea::GetIdent( void )
{
	static char Ident[] = "EXE (Executable with archive)";

	return Ident;
}

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

int CMassMea::GetFlags( void )
{
	return ma_flag_add_file | ma_flag_unlink_file | ma_flag_create_archive;
}

int	 CMassMea::CheckFileType( void )
{
	if ( massf == NULL )
		return 0;

	char			buf[ 10 ];
	unsigned long	ul;

	fseek( massf, -8, SEEK_END );
	fread( &ul, 4, 1, massf );
	fread( buf, 4, 1, massf );

	if (( memcmp( buf, "MEAF", 4 ) == 0 ) &&
		( ftell( massf ) == ul ))
		return 1;
	
	if ( UnmassTools::_strcasecmp( MassFileExt, "exe" ) == 0 )
		return 1;

	return 0;
}

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

	if ( massf == NULL )
		return;

	char	buf[ 4 ];

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

	// zistim ci to nieje ciste exe-cko
	fseek( massf, -4, SEEK_END );
	fread( buf, 4, 1, massf );

	if ( memcmp( buf, "MEAF", 4 ) == 0 ) {
		EmptyExe = 0;
	
		fseek( massf, -16, SEEK_END );
		fread( &lib_start, 4, 1, massf );
		fread( &files_count, 4, 1, massf );
	}
	else {
		EmptyExe = 1;

		lib_start	= filesize;
		files_count	= 1;
	}
}

int	 CMassMea::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 ) );

	if (( next_set ) && ( (signed)next_rec_num == num ))
		num = -1;

	if (( EmptyExe == 1 ) && ( num == 0 )) {
		sprintf( FileRec.name, "%s.exe", MassFileName );
		FileRec.offset	= 0;
		FileRec.size	= filesize;
		FileRec.set		= 1;

		return 1;
	}

	//seek
	if ( num == -1 ) {
		if ( fseek( massf, next_rec_pos, SEEK_SET ) != 0 )
			return 0;
	}
	else {
		pos = lib_start + SizeOfMeaRec * num;
		if ( fseek( massf, pos, SEEK_SET ) != 0 )
			return 0;
	}

	//read
	if ( fread( &MeaRec, SizeOfMeaRec, 1, massf ) != 1 )
		return 0;

	//set position of the next
	next_rec_pos = ftell( massf );
	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( MeaRec.name );
	FileRec.offset	= MeaRec.offset;
	FileRec.size	= MeaRec.size;
	FileRec.set		= 1;

	return 1;
}

int	CMassMea::AddFileRecord( void )
{
	unsigned long	i;

	SetErrorStr( "Mea.AddFileRecord:" );

	if ( ! file_open_for_write ) {
		SetErrorStr( "Not open for writing" );
		return 0;
	}

	FileRec.index = files_count;
	FileRec.offset = lib_start;

	files_count++;
	if ( GrowFileList() == 0 )
		return 0;

	pFileList[ files_count - 1 ] = FileRec;

	lib_start += FileRec.size;
	filesize = filesize + FileRec.size + SizeOfMeaRec;

	if ( EmptyExe ) {
		filesize += sizeof( MeaHeader );		// archive data at the end
		EmptyExe = 0;
	}

	if ( WriteLib() == 0 ) {
		SetErrorStr( "error writing lib" );
		return 0;
	}

	return 1;
}

int	CMassMea::UnlinkFile( unsigned long index )
{
	if ( index >= files_count ) {
		SetErrorStr( "Index out of bounds" );
		return 0;
	}
//	if ( index == 0 ) {
//		SetErrorStr( "Cannot unlink 1st file in MEA archive" );
//		return 0;
//	}


	unsigned long	i;

	files_count--;

	//remove record out of pFileList
	for( i=index; i<files_count; i++ )
		memcpy( &pFileList[ i ], &pFileList[ i+1 ], sizeof( s_FileRec ) );

	//should i shrink the pFileList

	lib_start += sizeof( s_FileRec );

	if ( WriteLib() == 0 ) {
		SetErrorStr( "error writing lib" );
		return 0;
	}

	return 1;
}

int CMassMea::WriteLib( void )
{
	//extend file, write lib at the end
	if ( fseek( massf, lib_start, SEEK_SET ) != 0 )
		return 0;

	unsigned long	i, j, e;

	e = 0;

	for( i=0; i<files_count; i++ ) {

		memset( MeaRec.name, 0, MeaNameLen );
		j = strlen( pFileList[ i ].name );
		if ( j >= MeaNameLen )
			j = MeaNameLen - 1;
		memcpy( MeaRec.name, pFileList[ i ].name, j );
		MeaRec.offset	= pFileList[ i ].offset;
		MeaRec.size		= pFileList[ i ].size;

		j = fwrite( &MeaRec, sizeof( MeaRec ), 1, massf );
		if ( j != 1 )
			e = 1;
	}

	if ( files_count == 0 )
		MeaHeader.orig_file_size	= 0;
	else
		MeaHeader.orig_file_size	= pFileList[ 0 ].size;
	MeaHeader.lib_offset	= lib_start;
	MeaHeader.files_count	= files_count;
	MeaHeader.file_size		= filesize;
	memcpy( MeaHeader.ident, "MEAF", 4 );

	j = fwrite( &MeaHeader, sizeof( MeaHeader ), 1, massf );
	if ( j != 1 )
		e = 1;

	if ( e == 1 ) {
		SetErrorStr( "Some error during writing" );
		return 0;
	}

	return 1;
}

int CMassMea::CreateNewArchive( FILE *newf )
{
	//write file ident at the end
	memset( &MeaHeader, 0, sizeof( s_MeaHeader ) );
//	if ( files_count > 0 )
//		MeaHeader.orig_file_size	= pFileList[ 0 ].size;
	MeaHeader.orig_file_size	= 0;
	MeaHeader.lib_offset		= 0;
	MeaHeader.files_count		= 0;
	MeaHeader.file_size			= sizeof( s_MeaHeader );
	memcpy( MeaHeader.ident, "MEAF", 4 );

	if ( fwrite( &MeaHeader, sizeof( s_MeaHeader ), 1, newf ) == 0 ) {
		SetErrorStr( "Error writing header to file" );
		return 0;
	}

	return 1;
}
