/*************************************************************************
*
* ADOBE CONFIDENTIAL
* ___________________
*
*  Copyright 2010 Adobe Systems Incorporated
*  All Rights Reserved.
*
* NOTICE:  All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any.  The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
**************************************************************************/
//max length of any file path
var MAX_PATH =  ((navigator.platform == "Win32") ? 260 : 1024);

// this is the highest version of Android platform we allow EasyInstall to download.
// To just get whatever the latest is, then just set this to ""
var g_androidSDKSourceURL_Mac = "http://dl.google.com/android/android-sdk_r08-mac_86.zip";
var g_androidSDKSourceURL_Win = "http://dl.google.com/android/android-sdk_r08-windows.zip";
var g_androidSDKSourceURL = ((navigator.platform == "Win32") ? g_androidSDKSourceURL_Win : g_androidSDKSourceURL_Mac);
var g_androidMaxSDKVersion = "2.2";

//--------------------------------------------------------------------
// FUNCTION:
//   browseForFolder()
//
// DESCRIPTION:
//   Opens the file browser dialog and allows the user to choose
//   a folder and then populates that back to the given input
//
// ARGUMENTS: 
//   inputId - the ID of the input associated with the folder
//
// RETURNS:
//   The file path that was selected.
//--------------------------------------------------------------------
function browseForFolder(inputId) 
{
	var inputObj = document.getElementById(inputId);
	if( !inputObj )
		return;
	
	var fileUri = new DWUri();
	fileUri.localPathToURI( inputObj.value );	
	
	if (DWfile.exists(fileUri)) 
 	{
		fileUri = new DWUri(escape(dw.browseForFolderURL(MM.MSG_ProxyChooseFolder, fileUri, false)).replace("#", "%23"));
	}
	else 
	{
		fileUri = new DWUri(escape(dw.browseForFolderURL(MM.MSG_ProxyChooseFolder, "", false)).replace("#", "%23"));
	}
	
	if (DWfile.exists(fileUri)) 
	{
		//on mac we expressly want the unix form of the local path
		inputObj.value = (navigator.platform == "Win32")  ? fileUri.toLocalPath() : fileUri.toLocalPathUnix();
	}
	
	return fileUri;
}

//--------------------------------------------------------------------
// FUNCTION:
//   browseForFile()
//
// DESCRIPTION:
//   Opens the file browser dialog and allows the user to choose
//   a file and then populates that back to the given input
//
// ARGUMENTS: 
//   inputId - the ID of the input associated with the folder
//...type - what type of file. Currently the only special typs is PNG
//
// RETURNS:
//   Nothing.
//--------------------------------------------------------------------
function browseForFile(inputId, type) 
{
	var inputObj = document.getElementById(inputId);
	if( !inputObj )
		return;
	
	var fileUri = new DWUri();
	fileUri.localPathToURI( inputObj.value );
	
	var allowPreview = false;
	var fileFilter = null;
	var fileArg = null;
	
	if( DWfile.exists(fileUri) )
	{
		fileArg = fileUri;
	}
	
	if( type == "PNG" )
	{
		var filterString = (navigator.platform == "Win32") ? "PNG (*.png)|*.png|PNG|" : "PNG (*.png)|*.png|****|";
		fileFilter	= new Array(filterString);
	}
	
	// Unless we tell it otherwise, browseForFileURL() returns a document relative path. This is not what we want when slecting images.
	// naf_forceAbsolutePath tells browseForFileURL() to return the full path to the selected file ignoring any open document. - rwe
	fileUri = new DWUri(escape(dw.browseForFileURL((type == "PNG") ? "naf_forceAbsolutePath" : "", "", false, true, fileFilter, fileUri, false)).replace("#", "%23"));

	if (DWfile.exists(fileUri)) 
	{
		//on mac we expressly want the unix form of the local path
		inputObj.value = (navigator.platform == "Win32")  ? fileUri.toLocalPath() : fileUri.toLocalPathUnix();
	}
    else
    {
        // how can the file not exist? we just selected it...unless its a site relative path
        // in which case we need to create an absolute path.
        if (fileUri.toString() != "")
        {
            var fullURI = new DWUri(site.getLocalRootURL(site.getCurrentSite()) + fileUri.toString());
     
            if (DWfile.exists(fullURI)) 
            {
                inputObj.value = (navigator.platform == "Win32")  ? fullURI.toLocalPath() : fullURI.toLocalPathUnix();
            }
        }
    }
}


//--------------------------------------------------------------------
// FUNCTION:
//   validateFolderPath()
//
// DESCRIPTION:
//   Valdidates the given path and alerts the user if the validation fails. 
//		Currently it just checks the length of the path and that the folder
//		infact exists 
//
// ARGUMENTS: 
//   path - string - the file path to validate
//   controlLabel - optional - the name of the label to refer to in the alert.
//                  If there is no label, then there is no alert
//  paddingLen - optional - if you want to reuire addtional space you 
//                  can add it here
//
// RETURNS:
//   Nothing.
//--------------------------------------------------------------------
function validateFolderPath( path, controlLabel,  paddingLen)
{
	//check that length is not over MAX_PATH
	var maxLen = MAX_PATH;
	if( paddingLen )
		maxLen = maxLen - paddingLen;
		
	if( path.length > maxLen )
	{
		if( controlLabel && controlLabel != "" )
			alert( dwscripts.sprintf(dw.loadString('NAF/configureAppFrameworks/fileNameTooLong/alert'), controlLabel) );
		
		return false;
	}
	
	//check that the file is a really safe path, we're currently having issues with 
	//hi-ascii and double byte paths with the android SDK or other paths
	//look for anything not in the safe list
	if( path.search(/[^a-zA-Z#-_\.\\\/\:\~ ]/) != -1 )
	{
		if( controlLabel && controlLabel != "" )
			alert( dwscripts.sprintf(dw.loadString('NAF/configureAppFrameworks/lowAsciiOnly/alert'), controlLabel) );
		
		return false;
	}
	
	var fileUri = new DWUri();
	fileUri.localPathToURI(path);
	
	//verify something is there
	if( !DWfile.exists(fileUri) )
	{
		if( controlLabel && controlLabel != "")
			alert( dwscripts.sprintf(dw.loadString('NAF/configureAppFrameworks/folderDoesNotExist/alert'), controlLabel) );
		
		return false;
	}
	
	return true;
}

//--------------------------------------------------------------------
// FUNCTION:
//   validateBundleId()
//
// DESCRIPTION:
//   Valdidates the bundle ID and alerts the user if the validation fails. 
//		The validation rule is only letters, numbers, and periods ("com.compary") 
//
// ARGUMENTS: 
//   path - string - the file path to validate
//	 controlLabel - the name of the label to refer to in the alert
//
// RETURNS:
//   Nothing.
//--------------------------------------------------------------------
function validateBundleId( bundleID )
{
	//use a regex to look for any char outside and verify it's exactly three sections
	var parts = bundleID.split(".");
	var invalidCharsTest = /[^\w\d\.\-\_]/
	if( bundleID.length == 0 || 
		!parts || 
		parts.length != 3 || 
		parts.some( function( ele, i, array ) { return !ele || ele == "" || ele.search(invalidCharsTest) != -1; } ) )
	{
		alert( dw.loadString('NAF/configureAppFrameworks/bundleIdBadChars/alert' ) );
		return false;
	}
	
	return true;
}

//--------------------------------------------------------------------
// FUNCTION:
//   validateNonEmpty()
//
// DESCRIPTION:
//   Validates that the given field is non-empty. If it is empty it 
//   pops up an alert telling the user to fill in the field.
//
// ARGUMENTS: 
//   val - value to varify
//	 controlLabel - the name of the label to refer to in the alert
//
// RETURNS:
//   Nothing.
//--------------------------------------------------------------------
function validateNonEmpty( val, controlLabel )
{
	//use a regex to look for any char outside
	if( !val || dwscripts.trim(val).length == 0 )
	{
		alert( dwscripts.sprintf(dw.loadString('NAF/configureAppFrameworks/requiredValue/alert'), controlLabel) );
		return false;
	}
	
	return true;
}

//--------------------------------------------------------------------
// FUNCTION:
//   validateAppName()
//
// DESCRIPTION:
//  Validatate the App name
//
// ARGUMENTS: 
//   appNamt to validate.
//
// RETURNS:
//   true if valid
//--------------------------------------------------------------------
function validateAppName( appName )
{
	//can't be empty
	if( !validateNonEmpty( appName, dw.loadString("NAF/configureAppSettings/appName/label") ) )
		return false;
	
	//edge case, but can't be a Java reserved word
	if( IsReservedWord( appName ) )
	{
		alert( dw.loadString('NAF/configureAppSettings/appNameCantBeJavaWord/alert') );
		return false;
	}
	
	//must be at least four characters
	if( appName.length < 4 )
	{
		alert( dw.loadString('NAF/configureAppSettings/appNameTooShort/alert') );
		return false;
	}
	
	//can't be more than 256
	if( appName.length > 256 )
	{
		alert( dw.loadString('NAF/configureAppSettings/appNameTooLong/alert') );
		return false;
	}
	
	return true;
}

//--------------------------------------------------------------------
// FUNCTION:
//   validateVersion()
//
// DESCRIPTION:
//  Validatate the version (nn.nn.nn)
//
// ARGUMENTS: 
//   version to validate.
//
// RETURNS:
//   true if valid
//--------------------------------------------------------------------
function validateVersion( version )
{
	//can't be empty
	if( !validateNonEmpty( version, dw.loadString("NAF/configureAppSettings/appName/label") ) )
		return false;
		
	//Must be "x.x" or "x.x.x"
	if( !( /^\d+(\.\d+){1,2}$/.test(version)))
	{
		alert( dw.loadString('NAF/configureAppSettings/versionBadFormat/alert') );
		return false;
	}
	
	return true;
}

//--------------------------------------------------------------------
// FUNCTION:
//   stripDWCommandTags()
//
// DESCRIPTION:
//  Strips the everything from <DW>...</DW>. The tags are included in 
//  the command results in some of the functions
//
// ARGUMENTS: 
//   string to strip
//
// RETURNS:
//   the stripped string
//--------------------------------------------------------------------
function stripDWCommandTags( stringToStrip )
{
	return stringToStrip.replace( /<DW>(?:.|\n|\r)*?<\/DW>/g, "");
}

//--------------------------------------------------------------------
// FUNCTION:
//   parseLineListToObj()
//
// DESCRIPTION:
//  Takes an array of lines with name value pairs separated by colons
//  and parsed them into an object. This is useful with android commands
//  where the output looks like "Name: Android 2.2", "Type: Platform" so 
//  you can turn that into something like obj.name = "Anroid 2.2";
//
// ARGUMENTS: 
//   Array of lines to parse
//
// RETURNS:
//   the parsed obj
//--------------------------------------------------------------------
function parseLineListToObj( arrayOfLines )
{
	var parsedObj = new Object();
	var lastID = new String();
	
	for( var i = 0 ; i < arrayOfLines.length ; i++ )
	{
		var curLine = arrayOfLines[i];
		var splits = curLine.split(":");
		if( !splits || splits.length < 2 || dwscripts.trim(splits[0]) == "")
		{
			//this is a a continuation of the previous line because the ID is not
			//in a valid format
			var trimmed = dwscripts.trim(curLine);
			if( parsedObj[lastID] && trimmed.length > 0 )
			{
				parsedObj[lastID] = parsedObj[lastID] + "\n" + trimmed;
			}
		}
		else
		{
			lastID = dwscripts.trim(splits.shift());
			parsedObj[lastID] = dwscripts.trim(splits.join(":"));
		}
	}
	
	return parsedObj;
}

//--------------------------------------------------------------------
// FUNCTION:
//   shiftArrayPastLine()
//
// DESCRIPTION:
//  Takes a string array and removes the top of it until it removes
//  the line matches the given regexp
//
// ARGUMENTS: 
//   Array - the array to shift
//   RegExp - the regex to top shifting at
//
// RETURNS:
//  none, that array is pass by ref
//--------------------------------------------------------------------
function shiftArrayPastLine( lineArray, targetLine )
{
	var curLine;
	while( curLine = lineArray.shift() )
	{
		if( targetLine.test(curLine) )
			return;
	}
}

//--------------------------------------------------------------------
// FUNCTION:
//   parseLinesToBlockList()
//
// DESCRIPTION:
//  Takes an array of line and creates a block list out of it. A block
//  list is a and array of lines the includes the match. It basically 
//  splits a repeating list of lines into each repeated section
// ARGUMENTS: 
//  lineArray - the array to split
//  RexExp - the match that divides the blocks
//
// RETURNS:
//   Array - an arrya of blocks
//--------------------------------------------------------------------
function parseLinesToBlockList( lineArray, blockStart )
{
	var blockList = new Array();
	var curBlock;
	
	for( var i = 0 ; i < lineArray.length ; i++ )
	{
		var curLine = lineArray[i];
		//see if this line starts a new block
		if( blockStart.test( curLine ) )
		{
			curBlock = new Array();
			blockList.push( curBlock );
		}
		
		if( curBlock )
			curBlock.push( curLine );
	}
	
	return blockList;
}

//--------------------------------------------------------------------
// FUNCTION:
//   parseAndroidTargetInfo()
//
// DESCRIPTION:
//  Takes a string from "android list targets" and turns the results
//  into a list of objects about the 
//
// ARGUMENTS: 
//   String - the string to parse
//
// RETURNS:
//   Array - the array of parsed objects
//--------------------------------------------------------------------
function parseAndroidTargetInfo( rawOutput )
{
	var targetInfos = new Array();
	//we're going parse it line by line
	var lines = rawOutput.split( /(?:\r|\n)+/ ); 
	
	//peel the top up to the starting line
	shiftArrayPastLine( lines, /^\s*Available Android targets:\s*$/i );
	
	//split the repeating sections into blocks
	var blocks = parseLinesToBlockList( lines,  /^\s*id:/i );
	
	//the id value is messed up, we'll need to correct it with this regexp
	var splitIdAndAltId = /\s*(\d+)(?:\s+or\s+"(.*?)")?/i;
	
	//Go through the blocks and parse them individually
	blocks.forEach( function( ele, i, arr) 
	{
		var parsedObj = parseLineListToObj( ele );
		//we need to clean up the id and altID
		if( parsedObj.id )
		{
			splitIdAndAltId.lastIndex = 0;
			var splits = splitIdAndAltId.exec(parsedObj.id);
			if( splits )
			{
				parsedObj.id = splits[1];
				if( splits[2] )
					parsedObj["altId"] = splits[2];
			}
		}
		targetInfos.push( parsedObj );
	} );
	
	return targetInfos;
}

//--------------------------------------------------------------------
// FUNCTION:
//   getAndroidTargetInfos()
//
// DESCRIPTION:
//  Returns a parsed array of objects from the commans "android list targets"
//  Each object in the array is the key value pair from the output
//
// ARGUMENTS: 
//   none
//
// RETURNS:
//   Array - the array of parsed objects
//--------------------------------------------------------------------
function getAndroidTargetInfos()
{
	var parsedArray = new Array();
	var rawResults = dw.nativeAppFramework.executeAndroidToolCommand("list targets");
	if( rawResults )
	{
		rawResults = stripDWCommandTags( rawResults );
		parsedArray = parseAndroidTargetInfo(rawResults);
	}
	return parsedArray;
}

//--------------------------------------------------------------------
// FUNCTION:
//   getAndroidMaxTargetIdForMaxSDKVersion()
//
// DESCRIPTION:
//  Goes through all the current adroid targets and finds that highest
//  one that is less than or equal to the given SDK version number
//
// ARGUMENTS: 
//   number - the max version to get. If it's empty it returns the 
//            highest targetID
//
// RETURNS:
//  number - the targetId to use, or undefined if no targets defined
//           that match the criteria
//--------------------------------------------------------------------
function getAndroidMaxTargetIdForMaxSDKVersion(maxVersion)
{
	var targetInfos = getAndroidTargetInfos();
	if( !targetInfos || targetInfos.length == 0 )
		return;
		
	//ensure this is a number
	if( !maxVersion || maxVersion == "" )
		return parseInt(targetInfos.pop().id);
	
	//Ensure we were passed in a Number
	maxVers = new Number(maxVersion);
	if( !maxVers || isNaN(maxVers) || maxVers < 1 )
	{
		dwscripts.debugAlert("getAndroidMaxTargetIdForMaxSDKVersion() passed in a bad version number: " + maxVersion);
		return parseInt(targetInfos.pop().id);
	}
	
	var targetId;
	var foundVers = 0;
	
	var versRegExp = /Android\s+(\d[0-9.]*)/i;
	
	//now lets get through the array and look
	targetInfos.forEach( function( ele, i, arr) 
	{
		var thisVers = 0;
		
		if( ele.Type && ele.Type.toLowerCase() == "platform" &&  ele.Name )
		{
			versRegExp.lastIndex = 0;
			var splits = versRegExp.exec(ele.Name);
			if( splits )
				thisVers = parseFloat(splits[1]);
		}
		//didn't find it in the platform section, check the other fields in case 
		//this is an add-on, so long as it's a google add-on
		if( thisVers <= 0 && ele.Vendor && ele.Vendor.toLowerCase() == "google inc." )
		{
			for each ( var val in ele )
			{
				versRegExp.lastIndex = 0;
				var splits = versRegExp.exec(val);
				if( splits )
					thisVers = parseFloat(splits[1]);
				if( thisVers > 0 )
					break;
			}
		}
		
		if( thisVers >= foundVers && thisVers > 0 && thisVers <= maxVers)
		{
			targetId = parseInt(ele.id);
			foundVers = thisVers;
		}
	} );
	
	return targetId;
}

//--------------------------------------------------------------------
// FUNCTION:
//   lanuchAndroidSDKManager()
//
// DESCRIPTION:
//  launches the android SDK Manager. The main reason we need to do this
//  is if the user doesn't have the JDK installed, we want the android 
//  SDK manager to find our version of the JDK
//
// ARGUMENTS: 
//   none
//
// RETURNS:
//  none
//--------------------------------------------------------------------
function lanuchAndroidSDKManager()
{
	//just call android with no args and detached
	dw.nativeAppFramework.executeAndroidToolCommand("", true);
}
