
#include "stdafx.h"
#include "GlobalData.h"
#include "util.h"
#include "file.h"
#include "process.h"

// Timeout is 10 min for engine
#define C_TimeOutForEngine   (1000 * 60 * 10)
//#define C_TimeOutForEngine   (1000 * 15)
// Timeout is 1 min for crb
#define C_TimeOutForCRB      (1000 * 60 * 1)

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
tdeStatus fn_eBinarizeOneLevel( CString _csLevelName, BOOL _bTakeCareOfFix )
{
	char                   szExe[512];
	char                   szCommandLine[512];
	tdeStatus              eStatus;
	tdstCopyFileContext    stCopyContext;
	CString                csOutput;

	csOutput = "Starting binarize level '" + _csLevelName + "'\r\n";
	fn_vOutputLine( csOutput );

	// Will be used by fn_bTreatArrayOfFiles
	stCopyContext.csMainDirectory = g_stTheGlobalData.csMainDirectory;
	stCopyContext.csBinDirectory = g_stTheGlobalData.csBinDirectory;
	stCopyContext.csLevelName = _csLevelName;

	// Clean main directory and bin level directory
	if( (eStatus = fn_eTreatArrayOfFiles( g_a_szFilesBeforeBinarize, &stCopyContext )) != STATUS_C_OK )
		return eStatus;

	csOutput = "\tFirst pass for " + g_stTheGlobalData.csExeName + "\r\n";
	fn_vOutputLine( csOutput );

	sprintf( szExe, "%s\\%s", (const char *)g_stTheGlobalData.csMainDirectory, (const char *)g_stTheGlobalData.csExeName );
	sprintf( 
			szCommandLine, 
			"%s -bin:2 -dsc:2 -mem:2 -level:%s", 
			(const char *)g_stTheGlobalData.csExeName, 
			(const char *)_csLevelName );

	// First pass for engine 
	// Wait for end of engine or for user break.
	eStatus = fn_eSpawnAndWaitForProcessWithTimeout( szExe, szCommandLine, C_TimeOutForEngine );

	if( eStatus != STATUS_C_OK )
		return eStatus;

	// Here, everything went ok, so we continue.

//	fn_vOutputLine( "\tCopying binarized files from first pass\r\n"  );
	if( (eStatus = fn_eTreatArrayOfFiles( g_a_szFilesAfterFirstPass, &stCopyContext )) != STATUS_C_OK )
		return eStatus;

	// Second pass for engine.
	csOutput = "\tSecond pass for " + g_stTheGlobalData.csExeName + "\r\n";
	fn_vOutputLine( csOutput );

	sprintf( 
			szCommandLine, 
			"%s -bin:2 -dsc:2 -mem:3 -level:%s", 
			(const char *)g_stTheGlobalData.csExeName, 
			(const char *)_csLevelName );
	
	if( (eStatus = fn_eSpawnAndWaitForProcessWithTimeout( szExe, szCommandLine, C_TimeOutForEngine )) != STATUS_C_OK )
		return eStatus;

//	fn_vOutputLine( "\tCopying binarized files from second pass\r\n"  );
	if( (eStatus = fn_eTreatArrayOfFiles( g_a_szFilesAfterSecondPass, &stCopyContext )) != STATUS_C_OK )
		return eStatus;

	if( _bTakeCareOfFix )
	{
		// Now, execute CRB on fix.
		fn_vOutputLine( "\tBuild relocation table for Fix\r\n"  );
		sprintf( szExe, "%s\\crb.exe", (const char *)g_stTheGlobalData.csMainDirectory );
		if( (eStatus = fn_eSpawnAndWaitForProcessWithTimeout( szExe, "crb.exe FIX -s", C_TimeOutForCRB )) != STATUS_C_OK )
			return eStatus;

//		fn_vOutputLine( "\tCopying fix files to bin directory\r\n" );
		if( (eStatus = fn_eTreatArrayOfFiles( g_a_szFixFilesAfterCRB, &stCopyContext )) != STATUS_C_OK )
			return eStatus;
	}
	else
	{
		if( (eStatus = fn_eTreatArrayOfFiles( g_a_szDeleteFixFilesAfterCRB, &stCopyContext )) != STATUS_C_OK )
			return eStatus;
	}

	// Now, execute CRB on level.
	fn_vOutputLine( "\tBuild relocation table for Level\r\n"  );
	sprintf( szExe, "%s\\crb.exe", (const char *)g_stTheGlobalData.csMainDirectory );
	sprintf( szCommandLine, "crb.exe %s -s", (const char *)_csLevelName );
	if( (eStatus = fn_eSpawnAndWaitForProcessWithTimeout( szExe, szCommandLine, C_TimeOutForCRB )) != STATUS_C_OK )
		return eStatus;

//	fn_vOutputLine( "\tCopying level files to bin directory\r\n" );
	if( (eStatus = fn_eTreatArrayOfFiles( g_a_szLevelFilesAfterCRB, &stCopyContext )) != STATUS_C_OK )
		return eStatus;

	if( (eStatus = fn_eTreatArrayOfFiles( g_a_szDeleteFilesAfterBinarize, &stCopyContext )) != STATUS_C_OK )
		return eStatus;

	csOutput = "\tBinarization is finished for level '" + _csLevelName + "'\r\n\r\n";
	fn_vOutputLine( csOutput );
	return STATUS_C_OK;
}


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
// Thread for binarization ;
//   Launch MainWinX two times (with different parameters)
//   then execute crb two times
//   then move binary files to destination directory.
UINT fn_uiThreadBinarize( LPVOID _p_stParam )
{
	CByteArray             *p_oSelectedLevels = (CByteArray *)_p_stParam;
	CString                csOutput;
	tdeStatus              eBinarizationOK;
	BOOL                   bALevelHasBeenSkipped = FALSE;
	BOOL                   bALevelWasBinarizedOK = FALSE;
	tdstCopyFileContext    stCopyContext;
	BOOL                   bTakeCareOfFix        = TRUE;


	fn_vOutputLine( "\r\n=== New binarization task =======================\r\n" );
	
	stCopyContext.csMainDirectory = g_stTheGlobalData.csMainDirectory;
	stCopyContext.csBinDirectory = g_stTheGlobalData.csBinDirectory;
	stCopyContext.csLevelName = "";

	if( ! g_stTheGlobalData.bCommonFilesAreCopied )
	{
		if( (eBinarizationOK = fn_eTreatArrayOfFiles( g_a_szCommonFiles, &stCopyContext )) != STATUS_C_OK )
			return eBinarizationOK;
		g_stTheGlobalData.bCommonFilesAreCopied = TRUE;
	}

	for( int i=0; i<p_oSelectedLevels->GetSize(); i++ )
	{
		// if level is not selected for binarization, go to next one.
		if( (*p_oSelectedLevels)[i] == 0 )
			continue;


		eBinarizationOK = fn_eBinarizeOneLevel( g_stTheGlobalData.a_csLevelNames[i], bTakeCareOfFix );

		// We build reloc tables for fix for first level only.
        if( eBinarizationOK == STATUS_C_OK )
		    bTakeCareOfFix = FALSE;

		// if an error accured during binarization,
		// test if we have to continue with binarization.
		if( eBinarizationOK != STATUS_C_OK )
		{
			if( eBinarizationOK == STATUS_C_UserBreak )
			{
				fn_vOutputLine( "\tBinarization aborted by user.\r\n\r\n\r\n" );
				// If we don't continue, exit binarization processs.
				AfxEndThread( (UINT)STATUS_C_UserBreak );
			}
			else // eBinarizationOK == STATUS_C_Error
			{
				if( g_stTheGlobalData.bStopBinarizeOnError )
				{
					fn_vOutputLine( "\r\nBinarization aborted.\r\n\r\n\r\n" );
					// If we don't continue, exit binarization processs.
					AfxEndThread( (UINT)STATUS_C_Error );
				}
				// Else, go with next level.
				else
				{
					fn_vOutputLine( "\tSkipping level....\r\n" );
					bALevelHasBeenSkipped = TRUE;
					// Before we go for next level, wait for a few moments
					// to allow program to terminate.
					SleepEx( 1250, FALSE );
				}
			}
		}
		else // eBinarizationOK == STATUS_C_OK
		{
			// Level was binarized, we deselect it.
			p_oSelectedLevels->SetAt( i, 0 );

			// and we add it to the list of binarized levels
			g_stTheGlobalData.a_cBinarizedLevels.SetAt( i, 1 );

			bALevelWasBinarizedOK = TRUE;
		}

		fn_vOutputLine( "\r\n" );
	} // End for each level

	if( bALevelHasBeenSkipped )
	{
		fn_vOutputLine( "\r\nWarning : At least one level was not binarized because of errors.\r\n" );
	}
	else
	{
		fn_vOutputLine( "\r\nThe binarization is successful !.\r\n" );
	}

	fn_vOutputLine( "\r\n" );

	if( bALevelWasBinarizedOK )
		return (UINT)STATUS_C_OK;
	else
		return STATUS_C_Error;
}


