//																			Monkey King
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// This script is the client part of the Monkey King system which automates time consuming tasks 
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

try
{
// This will disable all important actions(update&processing of files) 
// in the build which allows to debug the script locally
var DEBUG = false;

// Create Shell objects.
var WSHSHELL = WScript.CreateObject("WScript.Shell");
var FSO = WScript.CreateObject("Scripting.FileSystemObject");
var WSHNETWORK = WScript.CreateObject("WScript.Network");

var forReading = 1, forWriting = 2, forAppending = 8;
var tristateUseDefault = -2, tristateTrue = -1, tristateFalse = 0;

NoGUIApplication();

// Specify here your mail if you want to get error mails
var adminMail = "Denis@Crytek.de";

// Folder where the buildfiles are located
var computerName = WSHNETWORK.ComputerName.toLowerCase();
var startedInPath = WSHSHELL.CurrentDirectory ;
var workingScriptPath = WScript.ScriptFullName;
var scriptName = "";
var scriptLocation = "";
var regExp = /(.+)\\(.+)\..+$/i;
if(workingScriptPath.search(regExp) != "-1")
{
	scriptLocation = RegExp.$1;
	scriptName = RegExp.$2;
}
else
{
	ErrorExit("Could not get the directory or script name of the working script.");
}

// Log file
var logFile = scriptLocation + "\\" + scriptName + ".log";
var openedLogFile = FSO.CreateTextFile( logFile,true );


// Important vars 

//default build destination
var buildDestinationPath = "D:\\buildforExport";

// pc specific build destination
if(computerName == "8core")
	buildDestinationPath = "C:\\buildforExport";

var serverSystemDir = "\\\\Autocompile1\\MonkeyKing\\MonkeyKingSysFiles";
// The server task file path, will be made out of the client name and the ServerSystemDir
var taskSF = "";

var clientF = scriptLocation + "\\"+ "Client.txt";
var lastTestF = scriptLocation + "\\" + "LastTestDate.txt";
var editorLogBackupPath = scriptLocation + "\\" + "Logs";
var systemCfgF = "\\\\storage\\builds\\Build_tools\\Scripts_for_update\\system.cfg";

var aLevels = new Array();
var aValidLevels = new Array();
var aNotValidLevels = new Array();
var aFailedExportLevels = new Array();;

var gExportFailed = false;
var gExportSuc = false;

var foundNotValidLevels = false;
var foundValidLevels = false;

// Path for the get build script
var getBuildScript = "\\\\storage\\builds\\Build_tools\\get_latest_build.js";
var startGetBuildScriptOptions = "/NoLevels /Cleanup";

var clientName = "";
var millSecOfTaskDate = "";
var millSecOfTestDate = "";
var couldNotLoadDates = false;
var saveSucess = false;

var testBuildPathS = "";

var checkEditor = false;
var checkGame = false;
var checkFPS = false;
var exportLevels = false;

// Perforce.
var p4_User = "Build";
var p4Src = "//data/Game02/Game/Levels/";
var p4_Client = computerName;

// P4 commandlines
var p4_SyncCmdLine = "p4" + " -c "+p4_Client + " -u "+p4_User + " sync -f "+p4Src;
var p4_EditCmdLine = "p4" + " -c "+p4_Client + " -u "+p4_User + " edit " +p4Src ;
var p4_RevertUnchangedCmdLine = "p4" + " -c "+p4_Client + " -u "+p4_User + " revert -a //...";
var p4_RevertCmdLine = "p4" + " -c "+p4_Client + " -u "+p4_User + " revert " +p4Src;
var p4_SubmitCmdLine = "p4" + " -c "+p4_Client + " -u "+p4_User + " submit -d \"!A Auto Export\"";
var p4_FstatCmdLine = "p4" + " -c "+p4_Client + " -u "+p4_User + " fstat " + p4Src;


// For mail 
var buildMailingList = "Fp_build@crytek.de";

var additionalMailInfo = "";

// Emailadresses where the emails are sent on specific situation
var aSuccessEmail = new Array(buildMailingList);
var aFailEmail = new Array(buildMailingList, adminMail, "timur@crytek.de");

if(DEBUG)
{
	aSuccessEmail = new Array(adminMail);
	aFailEmail = new Array(adminMail);
}

// files for attaching
var aErrFiles = new Array(logFile);
var aScsFiles = new Array(logFile);





///////////////////////////////////////////////////////////////////////////////
// *Main*
///////////////////////////////////////////////////////////////////////////////

Log("Start of exporting");
Log("*******************************************");
Log("For bugs and comments: Denis@Crytek.de\r\n\r\n");

if(DEBUG)
	Log("\r\n---You are in DEBUG mode!---\r\n");
	
// Get the current Date as custom formated string
startScriptTimeAsString = GetConvertedDate();
Log("Started at " + startScriptTimeAsString);

LoadSystemFiles();

// Check wheter a new testing task is available
if ( millSecOfTestDate <= millSecOfTaskDate || couldNotLoadDates)
{	
	if(couldNotLoadDates)
	{
		Log("Couldn't load all needed dates for figuring out whether a new task was given!");
		Log("But starting the task anyway, because this is the default behaviour.");
	}
	
	SaveTestDate();	
	
	if(FSO.FileExists(getBuildScript))
	{
		// Get the build without levels
		ExecuteWithTimeLimit( "cscript " + getBuildScript + " /BuildDir:" + "\"" +buildDestinationPath + "\" " + startGetBuildScriptOptions, 0 ); 
		// Copy the custom system cfg into the build
		fsoCopy(systemCfgF, buildDestinationPath + "\\system.cfg" , false, true );
			
		P4ConvertLevelsArray();
		
		// Get latest levels from p4
		var result = 0;
		Log("Get latest levels.");
		for(level in aLevels)
		{
			result = 0;
			result = ExecuteWithTimeLimit(	p4_SyncCmdLine + aLevels[level][0] + "/...", 0);
			if(result != 0)
				Log( "Error: Couldn't get latest level " + p4_SyncCmdLine + aLevels[level][0] + "/...");
		}
		
		CheckLocalLevels();
		
		// Start exporting of valid levels
		if(foundValidLevels)
		{
			for(level in aValidLevels)
			{
				if(!CheckOpenedInP4(aValidLevels[level][0] + "/level.pak", "byothers"))
				{
					Export(aValidLevels[level][0], aValidLevels[level][1]);
				}
				else
					AddFailedExport(aValidLevels[level][0]);
			}
			
			var result = 0;
			Log("Revert not changed files.");
			result = ExecuteWithTimeLimit(	p4_RevertUnchangedCmdLine , 0);
			if(result != 0)
				Log( "Error: Couldn't revert not changed files.", aFailEmail , aErrFiles );
		}
		else
			Log("No valid levels could be found!");
		
		SendSuccessMail();
	}
	else
	{
		ErrorExitWithMail("Script " + getBuildScript + " couldn't be found for execution.", aFailEmail , aErrFiles);
	}
		
}
else
	Log("No newer tasks found!");

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////





///////////////////////////////////////////////////////////////////////////////
// Functions.
///////////////////////////////////////////////////////////////////////////////


//++++++++++++++++++++++Prevents this script to be started without a dos window+++++++++++++
function NoGUIApplication()
{  
	var scriptHost = WScript.FullName;
	var regExp = /cscript.exe/i
	if(scriptHost.search(regExp) == "-1")
	{
		WSHSHELL.Popup( "Invalid script Host - This application is made for commandline use only\n"+
	                    "Please start the script with \"cscript\" before the scriptname e.g.: cscript <ScriptName>\n",
	                    0,"Error",0);
	                    
	 	ErrorExit("Script was started with the wrong host");
	}
}

//+++++++++++++++++++++++++Get converted date+++++++++++++++++++++++++
function GetConvertedDate()
{
	var jscriptDate = new Date();
	var convertedDate = jscriptDate.getYear()+"-"+(jscriptDate.getMonth()+1)+"-"+jscriptDate.getDate()+" "+jscriptDate.getHours()+":"+jscriptDate.getMinutes()+":"+jscriptDate.getSeconds();
	return(convertedDate);
}

//+++++++++++++++++++++++++Get converted date+++++++++++++++++++++++++
function GetCustomDateStr()
{
	var jscriptDate = new Date();
	var convertedDate = jscriptDate.getYear()+"-"+(jscriptDate.getMonth()+1)+"-"+jscriptDate.getDate()+" "+jscriptDate.getHours()+"h"+jscriptDate.getMinutes()+"m"+jscriptDate.getSeconds()+"s";
	return(convertedDate);
}

//+++++++++++++++++++++++++Log,Create and catch error+++++++++++++++++++++++++
function fsoCreateFolder(path)
{
	if(!DEBUG)
	{
		if (FSO.FolderExists(path) == false)
		{
			Log( "Making Folder: "+path );
			try
			{
				FSO.CreateFolder(path);
				return true;
			}
			catch(e)
			{
				Log("Error: Couldn't create: " + path + " because of: " + e.description);
				return false;
			}
		}
		else
			return true;
	}
	else
	{
		Log("(Creatings_test_logging: " + path );	
		return true;
	}	
}

//+++++++++++++++++++++++++Log,Copy and catch error+++++++++++++++++++++++++
function fsoCopy(source, destination , isDir, overwrite )
{
	if(!DEBUG)
	{
		Log("Copying: " + source + " to: " + destination );		
		try
		{	
			if(isDir)
				FSO.CopyFolder( source, destination, overwrite );
			else
				FSO.CopyFile( source, destination, overwrite );
				
			return true;
		}
		catch(e)
		{
			Log("Error: Couldn't copy: " + source + " to: " + destination + " because of: " + e.description);
			return false;
		}
	}
	else
	{
		Log("(Copying_test_logging: " + source + " to: " + destination );	
		return true;
	}
}

//+++++++++++++++++++++++++Log,Delete and catch error+++++++++++++++++++++++++
function fsoDelete(path , isDir, overwrite )
{
	if(!DEBUG)
	{
		Log("Deleting: " + path );		
		try
		{	
			if(isDir)
				FSO.DeleteFolder( path, overwrite );
			else
				FSO.DeleteFile( path, overwrite );
				
			return true;
		}
		catch(e)
		{
			Log("Error: Couldn't delete: " + path + " because of: " + e.description);
			return false;
		}
	}
	else
	{
		Log("(Deleting_test_logging: " + path );
		return true;
	}
}


//+++++++++++++++++++++++++removes or adds readonly from files+++++++++++++++++++++++++
function RemoveOrAddReadOnlyFlag(RemoveOrAdd,Directory,Recursive,IsDirectory)
{
	var logline = "";
			
	if(RemoveOrAdd=="Remove" || RemoveOrAdd=="remove")
	{
		cmdline = "attrib -R ";
		logline += "Removing Read-only attribute from \"";
	}
	else if(RemoveOrAdd=="Add" || RemoveOrAdd=="add")
	{
		cmdline = "attrib +R ";
		logline += "Adding Read-only attribute to \"";
	}
	cmdline += Directory
	if(IsDirectory)
	{
		cmdline += "\\*";
	}
	logline += Directory + "\"";
	
	if(Recursive)
	{
		// Remove read-only attribute in root of MasterCD.
		cmdline += " /S /D";
		logline += " with option: Recursive";
	}
	else
	{
		logline += " without option: Recursive";
	}

	Log( logline );
	
	result = WSHSHELL.Run( cmdline,1,true );
	if(result != 0)
		ErrorExitWithMail( "error: Removing of Adding of the read only flag couldn't be finished correctly"  , aFailEmail , aErrFiles );
}


function AddInfoToMail(sMsg)
{
	Log(sMsg);
	additionalMailInfo += "\r\n" + sMsg;
}

// saves the last test date
function SaveTestDate()
{
	try
	{
		Log("Saving last test time to: " + lastTestF);
		if(!DEBUG)
		{
			var loadedLastTestFile = FSO.CreateTextFile( lastTestF, true);	
			loadedLastTestFile.WriteLine(startScriptTimeAsString);
			loadedLastTestFile.Close();
		}
		saveSucess = true;
	}
	catch(e)
	{
		ErrorExitWithMail( "Error: Couldn't save the test date to file " + lastTestF + ". Error is: " + e.description, aFailEmail , aErrFiles );
	}
}


// Go through the given levels, check if they're valid and get relative path for P4 
function P4ConvertLevelsArray()
{
	Log("Getting level names and their relative level paths which are needed for syncing and open for edit in P4"); 
	for(level in aLevels)
	{
			var levelStr = aLevels[level][0];
				
			//replace all backslashes
			var regExp = /\\+/i;
			while(levelStr.search(regExp) != "-1")
			{
				levelStr = levelStr.replace( "\\", "/");
			}
			
			// Remove the slashes at the beginning
			var regExp = /^\/+(.*)/i;
			if(levelStr.search(regExp) != "-1")
			{
				levelStr = 	RegExp.$1;
			}
			
			// Remove the slashes at the end
			var regExp = /(.*)\/+$/i;
			if(levelStr.search(regExp) != "-1")
			{
				levelStr = 	RegExp.$1;
			}
			
			// Save cleaned relative path
			aLevels[level][0] = levelStr;
			
			// get the last part of path for the cry file name 
			// also remove a "_" in the beginning if there's one
			var regExp = /\/+/i;
			if(levelStr.search(regExp) != "-1")
				var regExp2 = /.*\/_*(.*)$/i;
			else
				var regExp2 = /_*(.*)$/i;
			
			if(levelStr.search(regExp2) != "-1")
			{
				aLevels[level][1]=RegExp.$1;
			}
	}
}

// Check if given levels really exists locally
function CheckLocalLevels()
{	
	for(level in aLevels)
	{
		
		var levelCryFile = buildDestinationPath + "\\Game\\Levels\\" + aLevels[level][0] + "\\" + aLevels[level][1] + ".cry";
		var levelCryFileWithUnderscore = buildDestinationPath + "\\Game\\Levels\\" + aLevels[level][0] + "\\_" + aLevels[level][1] + ".cry";
		if(FSO.FileExists( levelCryFile) || FSO.FileExists( levelCryFileWithUnderscore) || DEBUG)
		{
			foundValidLevels = true;
			// add to valid level array
			if(FSO.FileExists( levelCryFile) || DEBUG)
				aValidLevels.push(aLevels[level]);
			else
			{
				aLevels[level][1] = "_" + aLevels[level][1];
				aValidLevels.push(aLevels[level]);
			}
		}
		else
		{
			Log("Found not valid level! File does not exist: " +  levelCryFile);
			foundNotValidLevels = true;
			aNotValidLevels.push(aLevels[level]);
		}
	}
}

// Can check if a file is opened by itself or by others
function CheckOpenedInP4(sRelativePakPath, sbyWho)
{
	var tmpCmdLine = p4_FstatCmdLine + sRelativePakPath;
	if(sbyWho.toLowerCase() == "byothers")
		var regExp = /\n\.\.\. \.\.\. otherOpen0 (.*)\n/i
	else if(sbyWho.toLowerCase() == "byme")
		var regExp = /\n\.\.\. action (.*)\n/i
	else
		return false;
	
	runResult = 0;

	var oExec = WSHSHELL.Exec(tmpCmdLine);
	var p4fstat = oExec.StdOut.ReadAll();
	runResult = oExec.ExitCode;

	if(runResult == 0)
	{
		if(p4fstat.search(regExp) != "-1")
		{
			if(sbyWho.toLowerCase() == "byothers")
			{
				var errStr = "File \"" + sRelativePakPath + "\" already opened by " + RegExp.$1;
				AddInfoToMail(errStr);
			}
			else if(sbyWho.toLowerCase() == "byme")
				Log("File \"" + sRelativePakPath + "\" is already opened by you for action " + RegExp.$1);
			
			return true;
		}
		else
		{
			return false;
		}
	}
	else
	{
		Log("Failed to execute: " + tmpCmdLine);
		return true;
	}
}

// Add a level to the global failed array
function AddFailedExport(sPath)
{
	gExportFailed = true;
  aFailedExportLevels.push(sPath);
}

function Export(sPath,sLevelName)
{
	Log("\r\n---------------------\r\nExporting Level: " + sPath + "\\" + sLevelName + ".cry");
	
	// Remove read only from the pak
	RemoveOrAddReadOnlyFlag("remove", buildDestinationPath + "\\Game\\Levels\\" + sPath + "\\level.pak", false, false);	

	// Start export
	var exportCmdLine = buildDestinationPath + "\\Bin64\\Editor.exe /ExportTexture /ExportAI " + buildDestinationPath + "\\Game\\Levels\\" + sPath + "\\" + sLevelName + ".cry";	
  var runResult = 0;  
  var t0 = new Date();
  runResult = ExecuteWithTimeLimit( exportCmdLine , 5400 );
  var t1 = new Date();
  Log("Finished exporting in: " + GetTimeDiff(t0,t1));
  
  // Check if export was successful
  if(runResult != 0)
  {
  	Log("Exporting FAILED! Deleting the pak.");
  	AddFailedExport(sPath);
  	fsoDelete(buildDestinationPath + "\\Game\\Levels\\" + sPath + "\\level.pak", false, true );
  }
	else
	{
		Log("Exporting was sucessful.");
		
		// Check if file is not checked out by someone else
		if(!CheckOpenedInP4(sPath + "/level.pak", "byothers"))
		{
			// Try to oped for edit
			Log("Open pak for edit.");
			runResult = 0;
			runResult = ExecuteWithTimeLimit(	p4_EditCmdLine + sPath + "/level.pak", 0);
			
			// check if file is really opened
			var fileOpened = CheckOpenedInP4(sPath + "/level.pak", "byme");
			
			if(runResult != 0 || !fileOpened)
			{
				AddFailedExport(sPath);
				AddInfoToMail( "Error: Couldn't open pak for edit." + p4_EditCmdLine + sPath + "/level.pak. Please investigate!");
			}
			else
			{		
				runResult = 0;
				var tryCount = 0;
						
				Log("Submit edited files.");
				Log(p4_SubmitCmdLine);
				do
				{
					if(tryCount >= 1)
					{
						Log("Submit failed. Trying again...");
						// Sleep
	    			WScript.Sleep(3000);
					}	
						
					if(!DEBUG)
					{
						runResult = WSHSHELL.Run( p4_SubmitCmdLine, 1, true );
						WScript.Sleep(5000);
					}
					
					var stillOpened = CheckOpenedInP4(sPath + "/level.pak", "byme");
					
					tryCount++;
				}
				while((runResult != 0 || stillOpened) && tryCount <= 2)
				
				if(runResult != 0 || stillOpened)
				{
					AddInfoToMail( "Error: Couldn't submit file " + sPath + "/level.pak" );
					AddFailedExport(sPath);
					Log("An error accured while checking in! reverting file.");
					
					runResult = 0;
					runResult = ExecuteWithTimeLimit(	p4_RevertCmdLine + sPath + "/level.pak", 0);
					
					var stillOpened = CheckOpenedInP4(sPath + "/level.pak", "byme");
					
					if(runResult != 0 || stillOpened)
					{
						Log( "Error: Couldn't revert " + 	p4_RevertCmdLine + sPath + "/level.pak");
					}
				}
				else
					gExportSuc = true;
			}
		}
		else
			AddFailedExport(sPath);
	}
	
	Log("Exporting complete\r\n---------------------");
}

//+++++++++++++++++++++++++Function for execute something and terminate if the give timelimit in sec. was reached+++++++++++++++++++++++++
function ExecuteWithTimeLimit( sGivenCommand , timeLimit )
{
	var max_running_time_in_sec = timeLimit;
	var runing_time = 0;
	var runResult = 0;
	var sCommand = sGivenCommand;
	//var sCommand = "%comspec% /c " + sGivenCommand;
	
	if(DEBUG)
	{
		Log("[DEBUG] " + sCommand);
	}
	else
	{
		Log(sCommand);
		if(max_running_time_in_sec != 0)
		{
			var oExec = WSHSHELL.Exec(sCommand);
			while (oExec.Status == 0 && runing_time < max_running_time_in_sec)
		  {
		  	// Sleep one second
		    WScript.Sleep(1000);
		    runing_time = runing_time+1;
		    //WScript.Echo( runing_time );
		  }
		  runResult = oExec.ExitCode;
		  if (runing_time >= max_running_time_in_sec)
		  {
		  	Log("Task exceeded the timout of " + max_running_time_in_sec + " seconds. Trying to terminate it!");
		  	
		  	try
		  	{
		    	oExec.Terminate();
		    }
		    catch(e)
		    {
		    	Log(e.description);
		    }
		    WScript.Sleep(10000); // Sleep for 10 sec, try to let process terminate.
		    
		    runResult = 10;
		  }
		} 
		else
		{
			runResult = WSHSHELL.Run( sCommand,1,true );
	  }
	}
  
  return runResult;
}



//+++++++++++++++++++++++++Function for writing to the log+++++++++++++++++++++++++
function Log(str) 
{
	var couldNotLog = "   (Could not write this line to log file)";
	
	if(openedLogFile != null)
	{
		try
		{
			openedLogFile.WriteLine( str );
		}
		catch(e)
		{
			str += couldNotLog;
		}
	}
	else 
		str += couldNotLog;
		
	WScript.Echo( str );
}


//+++++++++++++++++++++++++Initial operation like loading files etc.+++++++++++++++++++++++++
function LoadSystemFiles()
{
	// Load the clientname
	try
	{
		Log("Loading ClientName file from: " + clientF);
		var loadedClientF = FSO.OpenTextFile( clientF, forReading );
		if(!loadedClientF.AtEndOfStream)
			clientName = loadedClientF.ReadLine();
		else if (loadedClientF.AtEndOfStream)
			ErrorExitWithMail("Could not get the client name. file is empty :" +clientF, aFailEmail , aErrFiles);
		
		loadedClientF.Close();
		
		Log("ClientName is: " + clientName);
	}
	catch(e)
	{
		ErrorExitWithMail(e.description + " On file:" + clientF, aFailEmail , aErrFiles);
	}
	
	taskSF = serverSystemDir + "\\" + computerName + "_" + clientName + "_Task.txt";
	Log("server task file is: " + taskSF);
	
	// Load the taskfile
	try
	{
		Log("Loading task file from: " + taskSF);
		var loadedTaskSF = FSO.OpenTextFile( taskSF, forReading );
		if(!loadedTaskSF.AtEndOfStream)
		{
			// Read the first line with the build name in it
			testBuildPathS = loadedTaskSF.ReadLine();
			latestRegExp = /latest/i;
			approvedRegExp = /approved/i;
			if(testBuildPathS.search(latestRegExp) != "-1")
				startGetBuildScriptOptions += " /Latest";
			else if(testBuildPathS.search(approvedRegExp) != "-1")
				startGetBuildScriptOptions += "";
			else if(FSO.FolderExists(testBuildPathS))
				startGetBuildScriptOptions += " /BuildSource:" + testBuildPathS;
			else
				ErrorExitWithMail("No valid build source was given by the task file", aFailEmail , aErrFiles);
				
			Log("The options for the get build script are: " +startGetBuildScriptOptions);
			
			// Read the second line with the Date in it
			var DateFromFile = loadedTaskSF.ReadLine();
			Log("The date from the server task file: " + DateFromFile);
			
			// Get the date of the current task on server in milli sec.
			millSecOfTaskDate = ConvertDateToMillSec( DateFromFile );
			if(!millSecOfTaskDate)
			{
				Log("Could not get task date. file is doesn't contain this information :" +taskSF);
				couldNotLoadDates = true;
			}
			
			// Search for which test needs to be done
			var textFromTaskFile = loadedTaskSF.ReadAll();
			loadedTaskSF.Close();
			
			if(textFromTaskFile.search("automatedTesting") != "-1" )
			{
				checkEditor = true;
				Log("checkGame activated");
			}
			
			if(textFromTaskFile.search("CheckGame") != "-1" )
			{
				checkGame = true;
				Log("checkGame activated");
			}
			
			if(textFromTaskFile.search("CheckFPS") != "-1" )
			{
				checkFPS = true;
				Log("checkfps activated");
			}
			
			if(textFromTaskFile.search("ExportLevels") != "-1" )
			{
				exportLevels = true;
				Log("Exporting activated");
			}
			
			Log("Following Levels are assigned to this client:");
			var aTextFromTaskFileSplitted = textFromTaskFile.split("\r\n");
			var regExp = /L:(.*)/i;
			var found = false;
			for(line in  aTextFromTaskFileSplitted)
			{
				if(aTextFromTaskFileSplitted[line].search(regExp) != "-1")
				{
					aLevels.push(new Array(RegExp.$1,""));
					Log(RegExp.$1);
					var found = true;
				}
			}
			
			if(!found)
				ErrorExitWithMail("Could not load any levels from" +taskSF, aFailEmail , aErrFiles);
		}
		else if (loadedTaskSF.AtEndOfStream)
			ErrorExitWithMail("Could not load data out of the tasks file, it's empty :" +taskSF, aFailEmail , aErrFiles);
	}
	catch(e)
	{
		ErrorExitWithMail(e.description + " On file:" + taskSF, aFailEmail , aErrFiles);
	}	

	try
	{
		Log("Loading last Test Date from: " + lastTestF);
		var loadedLastTestF = FSO.OpenTextFile( lastTestF, forReading );
		var lastTestDate = loadedLastTestF.ReadLine();
		Log("The local last test date is: " + lastTestDate);
		// Get the date of the last test in milli seconds
		millSecOfTestDate = ConvertDateToMillSec( lastTestDate );
		loadedLastTestF.Close();
	}
	catch(e)
	{
		Log("Could not get last Test Date.");
		Log(e.description + " On file:" + lastTestF);
		couldNotLoadDates = true;
		var openedLastTestF = FSO.CreateTextFile(  lastTestF,true );
		openedLastTestF.Close();
	}
	

}


//+++++++++++++++++++++++++Converts saved dates from files to milliseconds+++++++++++++++++++++++
function ConvertDateToMillSec( DateFromFile )
{
	if(DateFromFile == null || DateFromFile=="")
	{
		Log("Error: Could not covert date to milli seconds, given date is  NULL or empty!");
		return false;
	}
	else
	{ 
		// Extract each part of date or time
		var LastPosYear= DateFromFile.indexOf("-");
		var Year = DateFromFile.slice("0",LastPosYear);
		
		var FirstPosMonth= LastPosYear +1;
		var LastPosMonth= DateFromFile.indexOf("-",LastPosYear+1);
		var Month = DateFromFile.slice(FirstPosMonth,LastPosMonth);
		
		var FirstPosDay= LastPosMonth +1;
		var LastPosDay= DateFromFile.indexOf(" ");
		var Day = DateFromFile.slice(FirstPosDay,LastPosDay);
		
		var FirstPosHours= LastPosDay +1;
		var LastPosHours= DateFromFile.indexOf(":");
		var Hours = DateFromFile.slice(FirstPosHours,LastPosHours);
		
		var FirstPosMinutes= LastPosHours +1;
		var LastPosMinutes= DateFromFile.indexOf(":",LastPosHours +1);
		var Minutes = DateFromFile.slice(FirstPosMinutes,LastPosMinutes);
		
		var FirstPosSeconds= LastPosMinutes +1;
		var Seconds = DateFromFile.slice(FirstPosSeconds,DateFromFile.length);
		
		var millisecFromUTC = Date.UTC(Year,Month-1,Day,Hours,Minutes,Seconds); 
		return(millisecFromUTC);
	}
}

function SendMail( recipient,msg,subject,attachmentsArray,importance, scriptLogObjectForClose )
{
	
	var now = new Date();
	
	Log( "Sending Mail to "+recipient+", With subject: "+subject );
	
	if(DEBUG)
		Log( "Message is: " +  msg);
	else
	{
		if(scriptLogObjectForClose != null)
		{
			Log("Closing Log file");
			try
			{
				scriptLogObjectForClose.Close();
				scriptLogObjectForClose = null;
			}
			catch(e)
			{
				Log("Could not close the log file because of: " + e.description);
			}
		}
		
		var cdoConfig = new ActiveXObject("CDO.Configuration");
		cdoConfig.Fields("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2; //cdoSendUsingPort
		cdoConfig.Fields("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate") = 1; //cdoBasic
		cdoConfig.Fields("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "mail2.INTERN.CRYTEK.DE";
		cdoConfig.Fields("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25;
		cdoConfig.Fields.Update();
	
		var cdoMessage = new ActiveXObject( "CDO.Message" );
		cdoMessage.Configuration = cdoConfig;
	
		cdoMessage.subject = subject;
		cdoMessage.From = "Build@crytek.de";
		cdoMessage.To = recipient;
		cdoMessage.TextBody = msg;
	
		
		var i;	
		for (i = 0; i < attachmentsArray.length; i++)
		{
			if (FSO.FileExists( attachmentsArray[i] ))
			{
				Log("Adding file to mail: " + attachmentsArray[i].toString());
				cdoMessage.AddAttachment( attachmentsArray[i] );
			}
		}
	
		try
		{
			cdoMessage.Send();
		}
		catch(e)
		{
			Log("The following error occured while trying to send a mail:\r\n"+e.description);
			Log("\r\nMail properties:\r\nSubject:\r\n" + subject + "\r\nMessage:\r\n"+msg+"\r\n\Recipient:\r\n"+recipient);
		}
		cdoConfig = null;
		cdoMessage = null;
	}
}

//+++++++++++++++++++++++++Logs an error and send a mail if something goes wrong+++++++++++++++++++++++++
function ErrorExitWithMail( ErrStr , aErrRecipients , aErrLogs )
{
	errorString =ErrStr;
	error = true;
	WSHSHELL.LogEvent( 1, "MonkeyKing ERROR." );
	WSHSHELL.LogEvent( 1,errorString );
	//MailFailure(ErrStr , aErrRecipients , aErrLogs );
	ErrorExit (  errorString  );
}

function ErrorExit(errStr)
{
	Log(errStr);
	Log("<ReturnCode:1>");
	WScript.StdErr.Write("<ReturnCode:1>");
	WScript.Sleep(5000);
	WScript.Quit(1);
}



//+++++++++++++++++++++++++Send a mail if the build failes+++++++++++++++++++++++++
function MailFailure( ErrMailStr , aErrMailRecipients , aErrMailLogs )
{
	// Send build failure Message.
	var str = " ";

	var msg = "MonkeyKing ERROR on computer " +computerName+"!";
	
	msg += "\r\n"+ErrMailStr;

	
	var mailsubject = "MonkeyKing ERROR on computer " +computerName+"!";
	SendMail( aErrMailRecipients,msg,mailsubject,aErrMailLogs,2 ,openedLogFile);
}

//+++++++++++++++++++++++++Summery of job execution+++++++++++++++++++++++++
function SendSuccessMail()
{	
	var a_mailRecipient = aSuccessEmail;
	
	var mailSub = "Auto exporting of levels on computer " + computerName;	
  

	if(!foundValidLevels || !gExportSuc)
	{
		mailSub += " failed";
		a_mailRecipient = aFailEmail;
	}
	else if(foundNotValidLevels || gExportFailed)
	{
		mailSub += " was partially successful";
		a_mailRecipient = aFailEmail;
	}
	else
	{
		mailSub += " was successful";
	}
	
	var mailMsg = mailSub;
	
	if(foundValidLevels)
	{
		mailMsg += "\r\n\r\nResults of the exported levels: ";
		
		for(level in aValidLevels)
		{		
			var comfirmFailed = false;
			mailMsg += "\r\nLevel: \""+aValidLevels[level][0]+"\"";		
			
			for(failedExportlevel in aFailedExportLevels)
			{
				if(aFailedExportLevels[failedExportlevel] == aValidLevels[level][0])
				{
					mailMsg += " FAILED to export";
					comfirmFailed = true;
					break;
				}
			}
					
			if(!comfirmFailed || aFailedExportLevels[0] == null)
				mailMsg += " SUCCEED exporting";
		}
	}
	else
		mailMsg += "\r\n\r\nNo levels were exported because no valid levels were given!!";
	
	
	if(foundNotValidLevels)
	{
		a_mailRecipient = aFailEmail;
		
		Log("Some given levels couldn't be found locally. ");
		mailMsg += "\r\n\r\nThe following levels couldn't be found, please check the path: ";
		
		for(level in aNotValidLevels)
		{
			mailMsg += "\r\n" + aNotValidLevels[level][0];
		}
	}
	
	
	if(!saveSucess)
	{
		a_mailRecipient = aFailEmail;
		mailMsg += "\r\n\r\n Couldn't save the last test date!";
	}


	var startScriptTime = DateObjectFromDateString(startScriptTimeAsString);
		
	if(startScriptTime != null)
	{
		var endScriptTime = new Date();
		mailMsg += "\r\n\r\nThe exporting was started at " + startScriptTimeAsString;
		mailMsg += "\r\nTotal exporting time: " + GetTimeDiff(startScriptTime,endScriptTime);
	}
	
	mailMsg += "\r\n" + additionalMailInfo;
		
	SendMail( a_mailRecipient, mailMsg, mailSub , aScsFiles, 1, openedLogFile );
}

//+++++++++++++++++++++++++Mainfunction for sending mails+++++++++++++++++++++++++
function DateObjectFromDateString( dateString)
{
	var regExp = /(\d+)-(\d+)-(\d+)\s(\d+):(\d+):(\d+)$/i;
	if(dateString.search(regExp) != "-1")
	{
		var year = RegExp.$1;
		var month = RegExp.$2;
		var day = RegExp.$3;
		var hours = RegExp.$4;
		var minutes = RegExp.$5;
		var seconds = RegExp.$6;
		var dateObj = new Date(year, month - 1, day, hours, minutes, seconds) ;
	}
	else
	{
		var dateObj = null;
	 	Log("Could not convert date string to date object! string is: "+dateString);
	}
	
	return dateObj;
}


//+++++++++++++++++++++++++Get difference between Time1 and Time2+++++++++++++++++++++++++
function GetTimeDiff( t0,t1 )
{
	var timeDiff = t1.getTime() - t0.getTime();
	var secMilli = 1000;
	var minMilli = 1000 * 60;
	var hrMilli = minMilli * 60;
	var dyMilli = hrMilli * 24;
	
	var t,h,m,s;
	t = timeDiff;
	h = Math.floor( t / hrMilli);
	t = timeDiff % hrMilli;
	m = Math.floor( t / minMilli );
	t = t % minMilli;
	s = Math.floor( t / secMilli );
	var str = ""+h+"h:"+m+"m:"+s+"s";
	return str;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////


}
catch(e)
{
	WScript.Echo("error: "+e);
	WScript.Echo("error number: "+e.number & 0xFFFF);
	WScript.Echo("error description: "+e.description);
	var erroropenedLogFile = FSO.CreateTextFile(  scriptLocation + "\\" + scriptName + "_ERROR.log",true );
	erroropenedLogFile.WriteLine("error: "+e);
	erroropenedLogFile.WriteLine("error number: "+e.number & 0xFFFF);
	erroropenedLogFile.WriteLine("error message: "+e.message);
	erroropenedLogFile.WriteLine("error description: "+e.description);
	erroropenedLogFile.WriteLine("Trying to send out a mail with the log as last step");
	erroropenedLogFile.Close();
	//aErrFiles.push(scriptLocation + "\\" + scriptName + "_ERROR.log");
	//SendMail( aFailEmail,"Build failed because of an error in build script!","Auto exporting of Levels on computer " + computerName,aErrFiles,2 ,openedLogFile);
	WScript.Quit(1);
}
