//---This Script will get the latest build---
//---Written by Denis Barth(Denis@crytek.de)

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.");
}


// Defintion of used variables
// !!!!!!! CHANGE THE VARIABLE UNDER THIS COMMENT TO YOUR LOCAL BUILD FOLDER!!!!!!!!!!!!
var copyDestDir = startedInPath;

// Folder where the buildscript is located  
var buildScriptLocation = WSHSHELL.CurrentDirectory + "\\";
var buildStorageServer = "\\\\storage";
var buildStoragePath = buildStorageServer + "\\builds";

var copySourceDir = "";
var copyBuildName = "";
var startCopying = true;
var result = 1;
var cleanup = false;
var searchForBuilds = true;
var excludeFile = "\\\\storage\\builds\\Build_tools\\";
var branchBuilds = false;

// Catch the path to an build
if (WScript.Arguments.Named.Exists("BuildSource"))
{	
		var tempStr = WScript.Arguments.Named.Item("BuildSource");
		var regExp = /(.*)\\(.*_\d+_\d+[^\\]*)/i;
		if(tempStr.search(regExp) != "-1")
		{
			searchForBuilds = false;
			buildStoragePath = RegExp.$1;
			copyBuildName = RegExp.$2;
		}
		else 
			WScript.Echo("Could not extract the buildname out of the given build path.");
}
else if (WScript.Arguments.Named.Exists("Latest"))
	buildStoragePath += "\\procedurally_generated_builds";
else if (WScript.Arguments.Named.Exists("LatestMP"))
{
	buildStoragePath += "\\Special_Builds\\Daily_MP_Test";
	searchForBuilds = false;
	copyBuildName = "Latest";
}
else
	buildStoragePath += "\\Approved_builds"; 


WScript.Echo("Get latest build script");
WScript.Echo("*******************************************");
WScript.Echo("For bugs and comments: Denis@Crytek.de\r\n\r\n");

WScript.Echo("Server build directory is: "+buildStoragePath);

// Catch path to the local build dir
if (WScript.Arguments.Named.Exists("BuildDir"))
{	
		copyDestDir = WScript.Arguments.Named.Item("BuildDir");
		WScript.Echo("Local build directory is: "+copyDestDir);
}

// Catch wheter branch builds should be considered
if (WScript.Arguments.Named.Exists("branchBuilds"))
{	
		branchBuilds = true;
		WScript.Echo("Script will also get branch builds");
}

// Catch Name of the Project to build
if (WScript.Arguments.Named.Exists("NoLevels"))
{	
		excludeFile += "NoLevels.txt";
}
// Catch Name of the Project to build
else if (WScript.Arguments.Named.Exists("NoBinaries"))
{	
		excludeFile += "NoBinaries.txt";
}
// Catch Name of the Project to build
else if (WScript.Arguments.Named.Exists("Exclude"))
{
		excludeFile += WScript.Arguments.Named.Item("Exclude");
}
else
	excludeFile = "";


if(copyDestDir == "" )
{
	ErrorExit("ERROR! No local build directory was given.");
}

	
// Catch Name of the Project to build
if (!WScript.Arguments.Named.Exists("Force"))
{	
	var regExp = /^(S:|P:|C:\\windows).*$/i;
	if(copyDestDir.search(regExp) != "-1")
	{
		ErrorExit("ERROR! Your local build directory is linking to a server or windows path!!!");
	}
}

// Catch Name of the Project to build
if (WScript.Arguments.Named.Exists("Cleanup"))
{	
		cleanup = true;
		WScript.Echo("Cleanup enabled\n");
}

var isNewestBuildFile = copyDestDir + "\\BuildName.txt";


///////////////////////////////////////////////////////////////////////////////
// Main.
///////////////////////////////////////////////////////////////////////////////

// Is checking if script can run, use only output to screen
CheckLinkToDir(buildStoragePath);

// Get the Name of the latest build and create a complete link to it
if(searchForBuilds)
	copyBuildName = FindNewestBuild(buildStoragePath);
	
copySourceDir = buildStoragePath + "\\" + copyBuildName;

CheckLinkToDir(copySourceDir);

// Delete the local folder
if(cleanup)
	Cleanup();

// Figure out whether the newest build is already on the hard drive
if(searchForBuilds)
	startCopying = IsNewestBuild();
	
if(startCopying==true)
{
	// Copy the build from the server
	Copy ( copySourceDir , copyDestDir + "\\" , true , true , true , true, excludeFile );
	IsNewestBuild(copyBuildName);
}
else if(startCopying==false)
{
	Log("Newest build is already on the hard drive, no need for update");
}


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



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


//+++++++++++++++++++++++++Function for making folders+++++++++++++++++++++++++
function MakeFolder( folder )
{
	if (FSO.FolderExists(folder) == false)
	{
		Log( "Making Folder: "+folder );
		try
		{
			FSO.CreateFolder(folder);
		}
		catch(e)
		{
			Log("Couldn't create folder beacause of: "+folder+e.description);
		}
	}
}

// Will check if link exists and quit if not
function ErrorExit(errStr)
{
	Log(errStr);
	Log("<ReturnCode:1>");
	WScript.StdErr.Write("<ReturnCode:1>");
	WScript.Sleep(5000);
	WScript.Quit(1);
}

// Will check if link exists and quit if not
function CheckLinkToDir(path)
{
	if(!FSO.FolderExists(path))
		ErrorExit("ERROR! Path: " + path + "\nDoes not exists.");
}


//+++++++++++++++++++++++++Function for deleting files+++++++++++++++++++++++++
function DeleteFiles( FileSpec )
{
	Log( "Delete Folder: "+FileSpec );
	var cmdLine ="cmd /c rmdir "+FileSpec+" /S /Q";

		
	result = WSHSHELL.Run( cmdLine, 1, true );
//	if(result != 0)
//		errorExit( "error: Deleting couldn't be finished correctly"  , aFailEmail , aErrFiles );
}

//+++++++++++++++++++++++++Delete and check if it was succesful+++++++++++++++++++++++++
function DeleteAndCheck(path,isFile) 
{
	var regExpStar = /\*+/i;
	if(isFile==true)
	{
		if (FSO.FileExists( path ) || path.search(regExpStar) != "-1")
		{
			try
			{
			FSO.DeleteFile( path );
			Log("Successful deleted file "+path );
			return true;
			}
			catch(e)
			{
				Log(e.description + " on: " + path);
				return false;
			}
		}
		else
		{
				Log("Could not find file for deleting:"+path);
				return true;
		}
	}
	else if(isFile==false)
	{
		if (FSO.FolderExists( path ) || path.search(regExpStar) != "-1")
		{
			try
			{
				FSO.DeleteFolder( path, true );
				Log("Successful deleted folder "+path );
				return true;
			}
			catch(e)
			{
				Log(e.description + " on: " + path);
				return false;
			}
		}
		else
		{
				Log("Could not find folder for deleting:"+path);
				return true;
		}
	}
	else
		Log("Function \"DeleteAndCheck\"Could not figure out of the argument given if path is an file or a folder")
}

//+++++++++++++++++++++++++Clean up the test build directory+++++++++++++++++++++++++
function Cleanup()
{
	if (FSO.FolderExists( copyDestDir ))
	{
		if(!DeleteAndCheck(copyDestDir + "\\*",false) || !DeleteAndCheck(copyDestDir + "\\*.*",true))
			ErrorExit("Could not clean up the copy destination directory!(" + copyDestDir + ")\r\nThis can have several reasons e.g. a program is accessing the folder. Please solve the problem then restart the script.");
		
		WScript.Sleep(100);
		
		if (FSO.FileExists( copyDestDir + "\\*.*"))
		{
			ErrorExit("Failed to delete "+copyDestDir  );
		}
		else
		{
			Log("Successful deleted "+copyDestDir );
		}
	}
}

//+++++++++++++++++++++++++Handling with newest build is already on the hard drive informations+++++++++++++++++++++++++
function IsNewestBuild(saveBuildName)
{
	if(saveBuildName)
	{
		Log("Writing copied build name to file: "+isNewestBuildFile);
		FSO.CreateTextFile( isNewestBuildFile,true );  
		var LoadedisNewestBuildFile = FSO.GetFile( isNewestBuildFile );   
		var Stream = LoadedisNewestBuildFile.OpenAsTextStream( forWriting,tristateUseDefault );
		Stream.Write(copyBuildName);
		Stream.Close();
	}
	else if(!saveBuildName)
	{
		if (FSO.FileExists( isNewestBuildFile ))
		{
			try
			{
				Log("Loading isNewestBuildFile file from: " + isNewestBuildFile);
				var loadedIsNewestBuildFile = FSO.OpenTextFile( isNewestBuildFile , forReading);
				var Output = loadedIsNewestBuildFile.ReadAll();
				loadedIsNewestBuildFile.Close();
				if( Output == copyBuildName )
					return(false);
				else
					return(true);				
			}
			catch(e)
			{
				Log("WARNING: This problem \"" + e.description + "\" occured during accessing the file \"" + isNewestBuildFile + "\"");
				return(true);
			}
			
		}
		else
		{
			Log("WARNING:Could not find flag file which says whether copying of build is needed from:"+isNewestBuildFile);
			return(true);
		}
	}
	else
		Log("ERROR: Wrong parameter was given to function IsNewestBuild.");
		return(true);	
}

//++++++++++++++++++++++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");
	}
}

//+++++++++++++++++++++++++Figure out what is the name of the newest build+++++++++++++++++++++++++
function FindNewestBuild(dir)
{
	Log( "Start figuring out what is the newest build.");
	
	var regExp = /game..\((\d+)\)_\d+_\d+_*/i;
	var	regExp2 = /branch/i;
	
	// Create the folderobject and enumerator with the subfolders
	var oFolder = FSO.GetFolder(dir);
  var enumSubFolders = new Enumerator(oFolder.SubFolders);
  	
	var aFinalBuildPaths = new Array();
	
	// Fill the array with the matching builds
  for (; !enumSubFolders.atEnd(); enumSubFolders.moveNext())
  {
     var tempBuildPath = enumSubFolders.item();
     tempBuildPath += "";
     if(branchBuilds)
     {
     	if(tempBuildPath.search(regExp2) != "-1" && tempBuildPath.search(regExp) != "-1")
	     {
	     	var tempArray = new Array(tempBuildPath, parseInt(RegExp.$1));
	     	aFinalBuildPaths.push(tempArray);
	     }     	
     }
     else
     {
	     if(tempBuildPath.search(regExp2) == "-1" && tempBuildPath.search(regExp) != "-1")
	     {
	     	var tempArray = new Array(tempBuildPath, parseInt(RegExp.$1));
	     	aFinalBuildPaths.push(tempArray);
	     }
	    }
  }
  
  // Sort the list ascending to the buildnumbers
	var done = false;
	do
  {
  	done = true;
    for (var i=0; i<aFinalBuildPaths.length-1; i++)
    {
      if(aFinalBuildPaths[i][1] < aFinalBuildPaths[i+1][1])
      {      		
        var tmp = aFinalBuildPaths[i];
        aFinalBuildPaths[i] = aFinalBuildPaths[i+1];
        aFinalBuildPaths[i+1] = tmp;
        done = false;
      }
    }
   }while (!done);
   
 regExp = /(game..\(\d+\)_\d+_\d+.*)/i;
 if(aFinalBuildPaths[0][0].search(regExp) != "-1")
 {
 	// return the name of the newest build
 	return(RegExp.$1);
 }
 else
 {
 	ErrorExit("Could not find a build");
 }
}

//+++++++++++++++++++++++++Copying folders and files with arguments+++++++++++++++++++++++++
function Copy(Source,Destination,Recrusive,KeepAttributes,CopyHiddenFiles,onlyNewer,Exclude)
{
	var cmdLine = "xcopy ";
	cmdLine += "\"" + Source + "\" \"" + Destination + "\"";
	cmdLine +=" /I /Y /C /R";
	if (Exclude != "") cmdLine +=" /exclude:"+Exclude;
	if (Recrusive) cmdLine +=" /E";
	if (KeepAttributes) cmdLine +=" /K";
	if (CopyHiddenFiles) cmdLine +=" /H";
	if (onlyNewer) cmdLine +=" /D";
	Log( "Start copying Folder "+Source+" to "+Destination);
	Log(cmdLine);
	result = WSHSHELL.Run( cmdLine,1,true );
	if(result != 0)
	{
		ErrorExit("Error: Copying couldn't be done correctly");
	}
}

//+++++++++++++++++++++++++Function for writing to the log+++++++++++++++++++++++++
function Log(str) 
{
	WScript.Echo( str );
}

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

}
catch(e)
{
	WScript.Echo("error: "+e);
	WScript.Echo("error number: "+e.number & 0xFFFF);
	WScript.Echo("error description: "+e.description);
	ErrorExit("Script failed because of an internal problem");
}