#include "stdio.h"
#include "stdlib.h"

#include "CRB_Main.h"

#include "windows.h"

#define __CRB_Includes_SNA__
#include "SNA/snafile.h"
#include "sna/snammg.h"
#undef __CRB_Includes_SNA__

/*
unsigned long fn_ulGetFileSize( FILE *_p_xFile )
{
	long lFilePosition;
	long lFileSize;

	lFilePosition = ftell( _p_xFile );
	fseek( _p_xFile, 0, SEEK_END );
	if( (lFileSize = ftell( _p_xFile )) == -1 ) 
		lFileSize = 0;
	fseek( _p_xFile, lFilePosition, SEEK_SET );
	return (unsigned long)lFileSize;
}
*/
unsigned long fn_ulGetFileSize( HANDLE hFile )
{
	DWORD dwResult;

	dwResult = GetFileSize (hFile,NULL);

	return ( (dwResult == 0xFFFFFFFF) ? 0 : dwResult);
}

// Read a pointer file.
unsigned long CRB_fn_bReadPtrBlocks(char *szFilename ,struct tdstBloc_** p_stMemory, char *szFileTypeName )
{
	HANDLE hFile;
	unsigned long ulSizeOfBloc;
	DWORD dwBytesRead;

	hFile = CreateFile(szFilename , GENERIC_READ, 0 , NULL , OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL , NULL);
	if(hFile == INVALID_HANDLE_VALUE)
	{
		printf("Warning - %s Pointer File not found : %s !\n", szFileTypeName, szFilename);
//		getchar();
//		exit(0);
		return 0;
	}

	ulSizeOfBloc = fn_ulGetFileSize( hFile );
	ulSizeOfBloc &= 0xfffffffc;
	p_stMemory[0]=(struct tdstBloc_ *)malloc(sizeof(struct tdstBloc_));
	p_stMemory[0]->cMemory=(unsigned long *)malloc(ulSizeOfBloc);

	p_stMemory[0]->ulSize = ulSizeOfBloc;
	if (ReadFile (hFile , p_stMemory[0]->cMemory , ulSizeOfBloc , &dwBytesRead , NULL) && (dwBytesRead != ulSizeOfBloc))
	{
		printf("Error reading %s Pointer File (%s) !\n", szFileTypeName, szFilename);
		getchar();
		exit(1);
	}

	CloseHandle (hFile);

	return 1;
}

// Search a block in the memory table.
// Returns a pointer to the block entry
struct tdstBloc_ * CRB_fn_p_stSearchBlock( 
    struct tdstBloc_ *_p_stMemory[], unsigned long _ulNbBlocks, 
    unsigned char _ucModule, unsigned char _ucBlock )
{
	struct tdstBloc_ *p_stCurMemory;
	unsigned long i;

	for( i=0; i<_ulNbBlocks; i++ )
	{
		p_stCurMemory = _p_stMemory[i];
		if(   p_stCurMemory->ulModuleNumber == _ucModule 
		   && p_stCurMemory->ulBlocNumber == _ucBlock )
		{
			return p_stCurMemory;
		}
	}

	return NULL;
}

// Read SNA file
unsigned long CRB_fn_bReadAllMemoryBlocks(char *szFilename,struct tdstBloc_** p_stMemory,unsigned char ucMode)
{ 
	struct SNA_tdstFile_ stFile;
//	FILE *p_xFile;
	unsigned char ucModule,ucBlock;
	unsigned long ulNbOfBloc;
	struct tdstBloc_ *p_stCurrentBlock;
	struct tdstBloc_ stTmpBlock;
	unsigned char ucUpdateBlock;
	DWORD dwBytesRead;

	if(ucMode==C_CRB_NEW)
	{
		ulNbOfBloc=0;
	}
	else
	{
		ulNbOfBloc=g_ulNbBloc;
	}
	
	SNA_fn_bFOpen( szFilename, SNA_C_ucRead, SNA_C_ucUseEncryption, &stFile );

	//if (! stFile.p_xFile )
	if (stFile.hFile == INVALID_HANDLE_VALUE)
	{
		printf("\nError - SNA File not found : %s !",szFilename);
		getchar();
		exit(2);
	}
	
	stFile.bReadSuccess = ReadFile(stFile.hFile,&stFile.ulCryptKey,sizeof(stFile.ulCryptKey),&dwBytesRead,NULL);
	if( stFile.ulCryptKey == 0 )
	{
		stFile.ucOptions &= ~SNA_C_ucUseEncryption;
	}

	while(stFile.bReadSuccess)
	{	
		memset( &stTmpBlock, 0, sizeof(struct tdstBloc_) );

		// Read module ID and block ID.
		if(SNA_fn_ulFRead(&ucModule,1,1,&stFile)==0)
			break;
		SNA_fn_ulFRead(&ucBlock,1,1,&stFile);

		// Tells if block has already been loaded
		p_stCurrentBlock = CRB_fn_p_stSearchBlock( p_stMemory, ulNbOfBloc, ucModule, ucBlock );

		if( p_stCurrentBlock == NULL )
		{
			// If block not loaded, add it.
			ucUpdateBlock = 1;
			p_stCurrentBlock = p_stMemory[ulNbOfBloc++] = (struct tdstBloc_ *)malloc(sizeof(struct tdstBloc_));
		}
		else if( p_stCurrentBlock->cMemory == NULL )
			// If only blocks infos have been loaded, update them
			ucUpdateBlock = 1;
		else
			// Block info AND content have been loaded, do not update them.
			ucUpdateBlock = 0;


		stTmpBlock.ulModuleNumber=ucModule;
		stTmpBlock.ulBlocNumber=ucBlock;
		
		// Read location of the block (fix or level)
//		SNA_fn_ulFRead( &ucModuleBlocLocation[ucModule][ucBlock], 1, 1, &stFile);
		SNA_fn_ulFRead( &stTmpBlock.ucLocation, 1, 1, &stFile);

		SNA_fn_ulFRead( &stTmpBlock.ulBeginBloc, 4, 1, &stFile );
		
		if( stTmpBlock.ulBeginBloc == 0XFFFFFFFF )
		{
			if( ucUpdateBlock )
				memcpy( p_stCurrentBlock, &stTmpBlock, sizeof(struct tdstBloc_) );
			continue;
		}
		
		SNA_fn_ulFRead(&(stTmpBlock.ulEndBloc),4,1,&stFile);
		SNA_fn_ulFRead(&(stTmpBlock.ulFreeSpace),4,1,&stFile);
		SNA_fn_ulFRead(&(stTmpBlock.ulMaxSpace),4,1,&stFile);
		
		SNA_fn_ulFRead(&stTmpBlock.ulSize,4,1,&stFile);
		
		// Size of block is not null, the block's content follows.
		if(stTmpBlock.ulSize !=0 )
		{
			if( ucUpdateBlock )
			{
				// Allocate the memory for the block's content and read it.
				stTmpBlock.cMemory = (unsigned long *)malloc( stTmpBlock.ulSize );
				SNA_fn_ulFRead( stTmpBlock.cMemory, 1, stTmpBlock.ulSize, &stFile );
			}
			else
			{
				// We already have loaded this block, print a warning and continue.
				printf( "Warning - Module %i block %i is loaded more than once.\n\tKeeping only first version...\n",
				        ucModule, ucBlock );
				SNA_fn_bFseek( &stFile, stTmpBlock.ulSize, SEEK_CUR );
			}
		}
		else
		{
			// This was only a block header, no content to load.
			stTmpBlock.cMemory = NULL;
		}

		// Update block infos if necessary.
		if( ucUpdateBlock )
		{
			memcpy( p_stCurrentBlock, &stTmpBlock, sizeof(struct tdstBloc_) );
		}
		
	}
	SNA_fn_bFClose(&stFile);
	return ulNbOfBloc;
}
