
#include "stdafx.h"
#include "file.h"
#include "globaldata.h"

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 


tdeStatus fn_eCreateDirectory( const char *_szDirectory )
{
	if ( (!CreateDirectory( _szDirectory, NULL )) && (GetLastError() != ERROR_ALREADY_EXISTS) )
	{
		char *p_szCur;
		
		p_szCur = strchr( _szDirectory, '\\');
		while (p_szCur != NULL)
		{
			*p_szCur = 0;
			if ((!CreateDirectory (_szDirectory, NULL)) && (GetLastError() != ERROR_ALREADY_EXISTS) )
			{
				char szMessage[ 512 ];
				sprintf( szMessage, "Can't create local path '%s'", _szDirectory );
				AfxMessageBox( szMessage, MB_OK | MB_ICONSTOP );
				return STATUS_C_Error;
			}
			*p_szCur++ = '\\';
			p_szCur = strchr( p_szCur, '\\');
		};
		
		if ((!CreateDirectory (_szDirectory, NULL)) && (GetLastError() != ERROR_ALREADY_EXISTS) )
		{
			char szMessage[ 512 ];
			sprintf( szMessage, "Can't create local path '%s'", _szDirectory );
			AfxMessageBox( szMessage, MB_OK | MB_ICONSTOP );
			return STATUS_C_Error;
		}
	}
	return STATUS_C_OK;
}


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
// Copy a file or a directory (no '\' at end of directory name !)
// Source may contain wilcards. Dest must be a path to a directory !
// If source is a directory, the copy is recursive
tdeStatus fn_eCopyFileOrDirectory( const char *_szSource, const char *_szDest )
{
	HANDLE             hCopyhandle;
	WIN32_FIND_DATA    stFindData;
	int                iNbCharactersForSourcePath;
	char               szSource[512];
	char               szDest[512];
	tdeStatus          eStatus;

	if( (eStatus = fn_eCreateDirectory( _szDest )) != STATUS_C_OK )
		return eStatus;

	// No file to copy, nothing to do...
	if( (hCopyhandle = FindFirstFile( _szSource, &stFindData )) == INVALID_HANDLE_VALUE )
		return STATUS_C_OK;

	iNbCharactersForSourcePath = (strrchr( _szSource, '\\' ) - _szSource);
	do
	{
		// Skip . and .. 
		if( (stFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 
		    && ( (strcmp( stFindData.cFileName, ".") == 0)
		         || strcmp( stFindData.cFileName, "..") == 0) )
			continue;

		strncpy( szSource, _szSource, iNbCharactersForSourcePath+1 );
		szSource[iNbCharactersForSourcePath+1] = 0;
		strcat( szSource, stFindData.cFileName );
		sprintf( szDest, "%s\\%s", _szDest, stFindData.cFileName );

		// If file is a directory
		if( (stFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
		{
			strcat( szSource, "\\*.*" );
			if( (eStatus = fn_eCopyFileOrDirectory( szSource, szDest )) != STATUS_C_OK )
				return eStatus;
		}
		else
		{
			if( ! CopyFile( szSource, szDest, FALSE ) )
			{
				char szMessage[1024];
				sprintf( szMessage, "Copy failed: '%s' to '%s", szSource, szDest );
				AfxMessageBox( szMessage, MB_OK | MB_ICONSTOP );
				return STATUS_C_Error;
			}
		}

		// Test for end of work.
		if( g_stTheGlobalData.bStopWork )
			return STATUS_C_UserBreak;

	} while( FindNextFile( hCopyhandle, &stFindData ) );

	FindClose( hCopyhandle );

	return STATUS_C_OK;
}


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
// Copy some files to a directory. Function will also seach for files in sub-dirs of source.
// Source may contain wilcards. Dest must be a path to a directory !
tdeStatus fn_eRecursiveFileCopy( const char *_szSource, const char *_szDest )
{
	HANDLE             hDirectoryHandle;
	WIN32_FIND_DATA    stFindData;
	int                iNbCharactersForSourcePath;
	char               szSource[512];
	char               szDest[512];
	tdeStatus          eStatus;

	// Copy this level of directory
	if( (eStatus = fn_eCopyFileOrDirectory( _szSource, _szDest )) != STATUS_C_OK )
		return eStatus;

	// Now we are going to check for subdirs.
	iNbCharactersForSourcePath = (strrchr( _szSource, '\\' ) - _szSource);
	strncpy( szSource, _szSource, iNbCharactersForSourcePath+1 );
	szSource[iNbCharactersForSourcePath+1] = 0;
	strcat( szSource, "*.*" );

	// No files in directory, nothing to do...
	if( (hDirectoryHandle = FindFirstFile( szSource, &stFindData )) == INVALID_HANDLE_VALUE )
		return STATUS_C_OK;

	do
	{
		// Skip . and .. 
		if( (stFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 
		    && ( (strcmp( stFindData.cFileName, ".") == 0)
		         || strcmp( stFindData.cFileName, "..") == 0) )
			continue;

		// We treat only directories
		if( (stFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
		{
			strncpy( szSource, _szSource, iNbCharactersForSourcePath+1 );
			szSource[iNbCharactersForSourcePath+1] = 0;
			strcat( szSource, stFindData.cFileName );
			strcat( szSource, _szSource+iNbCharactersForSourcePath );

			sprintf( szDest, "%s\\%s", _szDest, stFindData.cFileName );

			if( (eStatus = fn_eRecursiveFileCopy( szSource, szDest )) != STATUS_C_OK )
				return eStatus;
		}

		// Test for end of work.
		if( g_stTheGlobalData.bStopWork )
			return STATUS_C_UserBreak;

	} while( FindNextFile( hDirectoryHandle, &stFindData ) );

	FindClose( hDirectoryHandle );

	return STATUS_C_OK;
}



// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
// Moves file(s) or a directory (no '\' at end of directory name !)
// Source may contain wilcards. Dest must be a path to a directory !
tdeStatus fn_eMoveFileOrDirectory( const char *_szSource, const char *_szDest )
{
	HANDLE            hCopyhandle;
	WIN32_FIND_DATA   stFindData;
	int               iNbCharactersForSourcePath;
	char              szSource[512], szDest[512];
	tdeStatus         eStatus;

	if( (eStatus = fn_eCreateDirectory( _szDest )) != STATUS_C_OK )
		return eStatus;

	// No file to copy, nothing to do...
	if( (hCopyhandle = FindFirstFile( _szSource, &stFindData )) == INVALID_HANDLE_VALUE )
		return STATUS_C_OK;

	iNbCharactersForSourcePath = (strrchr( _szSource, '\\' ) - _szSource);
	do
	{
		// Skip . and .. 
		if( (stFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 
		    && ( (strcmp( stFindData.cFileName, ".") == 0)
		         || strcmp( stFindData.cFileName, "..") == 0) )
			continue;

		strncpy( szSource, _szSource, iNbCharactersForSourcePath+1 );
		szSource[iNbCharactersForSourcePath+1] = 0;
		strcat( szSource, stFindData.cFileName );
		sprintf( szDest, "%s\\%s", _szDest, stFindData.cFileName );

		if( ! MoveFile( szSource, szDest ) )
		{
			char szMessage[1024];
			sprintf( szMessage, "Move failed: '%s' to '%s", szSource, szDest );
			AfxMessageBox( szMessage, MB_OK | MB_ICONSTOP );
			return STATUS_C_Error;
		}

		// Test for end of work.
		if( g_stTheGlobalData.bStopWork )
			return STATUS_C_UserBreak;

	} while( FindNextFile( hCopyhandle, &stFindData ) );

	FindClose( hCopyhandle );

	return STATUS_C_OK;
}



// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
// Deletes file(s) or directory (no '\' at end of directory name !)
// Source may contain wilcards.
// If source is a directory, the delete is recursive.
tdeStatus fn_eDeleteFileOrDirectory( const char *_szSource )
{
	HANDLE            hDeletehandle;
	WIN32_FIND_DATA   stFindData;
	int               iNbCharactersForSourcePath;
	char              szSource[512];
	tdeStatus         eStatus;

	// No file to delete, nothing to do...
	if( (hDeletehandle = FindFirstFile( _szSource, &stFindData )) == INVALID_HANDLE_VALUE )
		return STATUS_C_OK;

	iNbCharactersForSourcePath = (strrchr( _szSource, '\\' ) - _szSource);
	do
	{
		// Skip . and .. 
		if( (stFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 
		    && ( (strcmp( stFindData.cFileName, ".") == 0)
		         || strcmp( stFindData.cFileName, "..") == 0) )
			continue;

		strncpy( szSource, _szSource, iNbCharactersForSourcePath+1 );
		szSource[iNbCharactersForSourcePath+1] = 0;
		strcat( szSource, stFindData.cFileName );

		// If file is a directory
		if( (stFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
		{
			strcat( szSource, "\\*.*" );
			if( (eStatus = fn_eDeleteFileOrDirectory( szSource )) != STATUS_C_OK )
				return eStatus;
			*strrchr( szSource, '\\' ) = 0;
			if( ! RemoveDirectory( szSource ) )
			{
				char szMessage[1024];
				sprintf( szMessage, "Delete failed on '%s'", szSource );
				AfxMessageBox( szMessage, MB_OK | MB_ICONSTOP );
				return STATUS_C_Error;
			}
		}
		else if( ! DeleteFile( szSource ) )
		{
			char szMessage[1024];
			sprintf( szMessage, "Delete failed on '%s'", szSource );
			AfxMessageBox( szMessage, MB_OK | MB_ICONSTOP );
			return STATUS_C_Error;
		}

		// Test for end of work.
		if( g_stTheGlobalData.bStopWork )
			return STATUS_C_UserBreak;

	} while( FindNextFile( hDeletehandle, &stFindData ) );

	FindClose( hDeletehandle );

	return STATUS_C_OK;
}


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
// This part deals with batch copy/move of files :

// Common files for all binarised maps (no files generated by binarisation nor sound or textures)
// files relative to main directory
char *g_a_szCommonFiles[] =
{
	"Copy", "Gamedata\\Options\\current.cfg",  "%bin%\\Options",
	"End"
};

char *g_a_szFilesBeforeBinarize[] = 
{
	// Make sure main directory is clean
	"Delete", "fix*.sna",
	"Delete", "fix*.snd",
	"Delete", "fix*.ptx",
	"Delete", "fix*.gpt",
	"Delete", "fix.rt?",

	"Delete", "%level%*.sna",
	"Delete", "%level%*.snd",
	"Delete", "%level%*.ptx",
	"Delete", "%level%*.gpt",
	"Delete", "%level%.rt?",

	"End"
};

char *g_a_szFilesAfterFirstPass[] = 
{
	// Get fix files from gamedata\world\levels
	"Move",   "Gamedata\\World\\Levels\\fix*", "",
	"Rename", "Fix.sna", "Fix0.sna",
	"Rename", "Fix.snd", "Fix0.snd",
	"Rename", "Fix.ptx", "Fix0.ptx",
	"Rename", "Fix.gpt", "Fix0.gpt",

	// Get level files from gamedata\world\levels\<LevelName>
	"Rename", "Gamedata\\World\\Levels\\%level%\\%level%.sna", "%level%0.sna",
	"Rename", "Gamedata\\World\\Levels\\%level%\\%level%.snd", "%level%0.snd",
	"Rename", "Gamedata\\World\\Levels\\%level%\\%level%.ptx", "%level%0.ptx",
	"Rename", "Gamedata\\World\\Levels\\%level%\\%level%.gpt", "%level%0.gpt",

	"End"
};

char *g_a_szFilesAfterSecondPass[] = 
{
	// Get fix files from gamedata\world\levels
	"Move",   "Gamedata\\World\\Levels\\fix*", "",
	"Rename", "Fix.sna", "Fix1.sna",
	"Rename", "Fix.snd", "Fix1.snd",
	"Rename", "Fix.ptx", "Fix1.ptx",
	"Rename", "Fix.gpt", "Fix1.gpt",

	// Get level files from gamedata\world\levels\<LevelName>
	"Rename", "Gamedata\\World\\Levels\\%level%\\%level%.sna", "%level%1.sna",
	"Rename", "Gamedata\\World\\Levels\\%level%\\%level%.snd", "%level%1.snd",
	"Rename", "Gamedata\\World\\Levels\\%level%\\%level%.ptx", "%level%1.ptx",
	"Rename", "Gamedata\\World\\Levels\\%level%\\%level%.gpt", "%level%1.gpt",
	"End"
};


char *g_a_szFixFilesAfterCRB[] =
{
	// Delete previous fix files
	"Delete", "%bin%\\World\\Levels\\fix*",
	"Delete", "%bin%\\Game.dsb",

	// Delete files from second pass
	"Delete", "Fix1.*",

	// We will use files from first pass.
	"Rename", "Fix0.sna", "Fix.sna",
	"Rename", "Fix0.snd", "Fix.snd",
	"Rename", "Fix0.ptx", "Fix.ptx",
	"Rename", "Fix0.gpt", "Fix.gpt",
	"Move",   "Fix.*",    "%bin%\\World\\Levels",
//	"Move",   "Fix.rt?",  "%bin%\\World\\Levels",
	"Move",   "Gamedata\\Game.dsb", "%bin%",
	"End"
};

char *g_a_szDeleteFixFilesAfterCRB[] =
{
	// Delete fix files
	"Delete", "fix*.sna",
	"Delete", "fix*.snd",
	"Delete", "fix*.ptx",
	"Delete", "fix*.gpt",
	"Delete", "fix.rt?",
	"End"
};

char *g_a_szLevelFilesAfterCRB[] = 
{
	// Delete files from second pass
	"Delete", "%level%1.*",

	// We will use files from first pass.
	"Rename", "%level%0.sna", "%level%.sna",
	"Rename", "%level%0.snd", "%level%.snd",
	"Rename", "%level%0.ptx", "%level%.ptx",
	"Rename", "%level%0.gpt", "%level%.gpt",

	// Delete bin level directory
	"Delete", "%bin%\\World\\Levels\\%level%\\*.*",

	// Move all files to destination directory
	"Move",   "%level%*",    "%bin%\\World\\Levels\\%level%",
	"Move",   "Gamedata\\World\\Levels\\%level%\\%level%.dsb", "%bin%\\World\\Levels\\%level%",
	"End"
};

char *g_a_szDeleteFilesAfterBinarize[] = 
{
	// Delete all remaining files in main directory
	"Delete", "fix*.sna",
	"Delete", "fix*.snd",
	"Delete", "fix*.ptx",
	"Delete", "fix*.gpt",
	"Delete", "fix.rt?",

	"Delete", "%level%*.sna",
	"Delete", "%level%*.snd",
	"Delete", "%level%*.ptx",
	"Delete", "%level%*.gpt",
	"Delete", "%level%.rt?",

	// Also delete files in level
	"Delete", "Gamedata\\Game.dsb",
	"Delete", "Gamedata\\World\\Levels\\%level%\\%level%.dsb",
	"End"
};


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

// Analyse keyword
// Used by fn_eTreatArrayOfFiles
int fn_iGetKeyword( char *_szKeyword )
{
	if( stricmp( _szKeyword, "Copy" )==0 )
		return 0;
	else if( stricmp( _szKeyword, "Move" )==0 )
		return 1;
	else if( stricmp( _szKeyword, "Rename" )==0 )
		return 2;
	else if( stricmp( _szKeyword, "Delete" )==0 )
		return 3;
	else if( stricmp( _szKeyword, "End" )==0 )
		return 4;

	return -1;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

// Analyse parameter
// Used by fn_eTreatArrayOfFiles
void fn_vGetParameter( char *_szResult, char *_szParam, tdstCopyFileContext *_p_stContext )
{
	char *p_cSource = _szParam, *p_cDest = _szResult;

	// hack: if no %bin%, assume path is main directory
	if( strnicmp( p_cSource, "%bin%", 5 ) == 0 )
	{
		strcpy( p_cDest, _p_stContext->csBinDirectory );
		p_cDest += strlen( p_cDest );
		p_cSource += 5;
	}
	else
	{
		strcpy( p_cDest, _p_stContext->csMainDirectory );
		p_cDest += strlen( p_cDest );
		if( *p_cSource ) *p_cDest++ = '\\';
	}

	while( *p_cSource )
	{
		if( strnicmp( p_cSource, "%level%", 7 ) == 0 )
		{
			strcpy( p_cDest, _p_stContext->csLevelName );
			p_cDest += strlen( p_cDest );
			p_cSource += 7;
		}
		else
		{
			*p_cDest++ = *p_cSource++;
		}
	}
	
	*p_cDest = 0;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

// Execute copy/move/deletes/rename commands in given array
// See above for exemples.
// stContext contains strings used when replacing %bin%, %level%....
tdeStatus fn_eTreatArrayOfFiles( char *_a_szFileCommands[], tdstCopyFileContext *_p_stContext )
{
	char         szSource[512], szDest[512];
	int          iKeyWord;
	tdeStatus    eCommandOK;
	char         **p_szCommand = _a_szFileCommands;

	do
	{
		switch( fn_iGetKeyword( *p_szCommand++ ) )
		{
		case 0: // Copy
			fn_vGetParameter( szSource, *p_szCommand++, _p_stContext );
			fn_vGetParameter( szDest, *p_szCommand++, _p_stContext );
			eCommandOK = fn_eCopyFileOrDirectory( szSource, szDest );
			break;

		case 1: // Move
			fn_vGetParameter( szSource, *p_szCommand++, _p_stContext );
			fn_vGetParameter( szDest, *p_szCommand++, _p_stContext );
			eCommandOK = fn_eMoveFileOrDirectory( szSource, szDest );
			break;

		case 2: // Rename
			fn_vGetParameter( szSource, *p_szCommand++, _p_stContext );
			fn_vGetParameter( szDest, *p_szCommand++, _p_stContext );
			eCommandOK = STATUS_C_OK;
			if( ! MoveFile( szSource, szDest ) )
			{
				char szMessage[1024];
				sprintf( szMessage, "Move failed: '%s' to '%s", szSource, szDest );
				AfxMessageBox( szMessage, MB_OK | MB_ICONSTOP );
				eCommandOK = STATUS_C_Error;
			}
			break;

		case 3: // Delete
			fn_vGetParameter( szSource, *p_szCommand++, _p_stContext );
			eCommandOK = fn_eDeleteFileOrDirectory( szSource );
			break;

		case 4: // End
			return STATUS_C_OK;
			break;

		default: // Error in array !
			ASSERT(0);
			iKeyWord = -1;
			eCommandOK = STATUS_C_Error;
			break;
		}

	} while( eCommandOK == STATUS_C_OK );

	return eCommandOK;
}


// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
