
// Macromedia Fireworks Batch Script Template
// Copyright (c) 1998-2005 Macromedia. All rights reserved.

var gBatchOperationsArray =
#BATCH_OPERATIONS#
;

var gBatchSettings = 
#BATCH_SETTINGS#
;

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

if (this.fw == null) {
	var msg = Errors.EBadJsVersion;
	if (msg == null)
		msg = "This script does not work in this version of Fireworks.";
	alert(msg);
	theDocList = null;
} else {
	fw.checkFwJsVersion(0);
	if (theDocList == null || theDocList.length == 0) {
		theDocList = App.chooseScriptTargetDialog(App.getPref("MultiFileBatchTypes"));
	}
}

numUnopenedDocs = 0; // keep track of how many we could not open

if (theDocList == null) {
	// The user must have canceled the "select files" dialog.
} else if (theDocList.length == 0) {
	// The user did something like "current files" when no files are open.
	alert(Errors.ENoFilesSelected);
} else {
	App.progressCountCurrent = 0;
	App.progressCountTotal = theDocList.length;
	for (var iDocIndex = 0; iDocIndex < theDocList.length; iDocIndex++) {
		App.progressCountCurrent = iDocIndex + 1;
		if (ProcessOneDocPath(theDocList[iDocIndex]) == false) {
			writeLog("Could not process " + theDocList[iDocIndex]);
			break;
		}
	}
}

if (numUnopenedDocs > 0) {
	alert(Errors.EBatchFileOpenError);//"One or more documents could not be opened. See FireworksBatchLog.txt for details.");
}

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

	function ProcessOneDocPath(docPathName)
	{
		var result = true;

		if (gBatchOperationsArray[1] == undefined && gBatchOperationsArray[0] == "operation:rename") {
			// Rename is the ONLY opeartion, so don't open any documents.
			result = RenameOneDoc(gBatchSettings, docPathName);
			return result;
		}
		
		var theDocWasOpen = false;
		var theDoc = App.findOpenDocument(docPathName);

		if (theDoc == null) {
			theDoc = App.openDocument(docPathName, false, true); // openWithWindowHidden
			theDocWasOpen = false;
		} else {
			theDocWasOpen = true;
		}

		if (theDoc == null) {
			numUnopenedDocs += 1;
			writeLog("\n" + docPathName + " could not be opened");
			return true;
		}

		if (ProcessOneDoc(theDoc) == false)
			result = false;

		if (theDoc != null && theDocWasOpen == false)
			theDoc.close(false);	// discard changes

		return result;
	}

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

	function ProcessOneDoc(theDoc)
	{
		// If sourceDocumentPath is null, the file is either a new document,
		// was opened as untitled (e.g., via stationery), or is a nonnative
		// file format (e.g., .psd). In these cases, get the revert file path.
		// If *that* is null, abort.
		var sourceDocumentPath = theDoc.filePathForSave;
		if (sourceDocumentPath == null)
			sourceDocumentPath = theDoc.filePathForRevert;
		if (sourceDocumentPath == null) {
			writeLog("source doc path is null");
			App.batchStatusString = "";
			alert(Errors.EInternalError);
			return false;
		}
		writeLog("\n" + sourceDocumentPath);
		
		App.batchStatusString = Files.getFilename(sourceDocumentPath);

		var batchSettings = gBatchSettings;

		// Handle backup options before looping.
		if (batchSettings && (batchSettings.doBackupFiles)) {

			backupPath = GetBackupFile(sourceDocumentPath, batchSettings.doIncrementalBackup);
			if (backupPath == null) {
				writeLog("Unable to get backupPath");
				return false;
			}

			var errorString = SafeMoveFileTo(sourceDocumentPath, backupPath);
			if (errorString != null) {
				writeLog(errorString);
				alert(errorString);
				return false;
			}

			// Note that Files.swap(), and thus SafeMoveFileTo(), will change theDoc to
			// refer to backupPath rather than sourceDocumentPath. We don't want this, 
			// so we force the issue by setting it back to what we want. Note also that
			// it is not necessarily the case that theDoc.filePathForSave == sourceDocumentPath
			// (e.g., if the document was not originally a native Fireworks file), so we
			// really only want to reset it if it changed.
			if (theDoc.filePathForSave == backupPath) {
				theDoc.filePathForSave = sourceDocumentPath;
			}
		}

		// These are always done last, regardless of where they are in the list.
		var donelast = {
			doRename:false,
			doExport:false,
		};

		for (var i = 0; i < 1000; i++) {
			if (gBatchOperationsArray[i]) {
				if (ProcessOneDocForOneBatch(
						theDoc, 
						sourceDocumentPath,
						gBatchOperationsArray[i],
						batchSettings, 
						donelast) == false) {
					return false;
				}
			} else {
				break;
			}
		}

		// Only go through the DoRename function if:
		// 1. We are NOT exporting - if we are exporting, renaming is taken care of there.
		// 2. The file is a FW png file (i.e., has a savefile) - if it is not, it exports by default.
		if ((donelast.doRename) && (!donelast.doExport) && (theDoc.filePathForSave != null)) { 
			// NOTE: DoRename only renames original if original file is overwritten.
			// If a (*different*) custom output is specified, renaming is taken care of there
			DoRename(theDoc, sourceDocumentPath, batchSettings);
		}

		// If we are exporting, doExport takes care of exporting to the right location.
		if (donelast.doExport) {

			DoExport(theDoc, sourceDocumentPath, batchSettings);

		} else {

			if (theDoc.filePathForSave == null) { 

				// It's a non-FW file. We must export in order to "save".
				DoForceExport(theDoc, sourceDocumentPath, batchSettings);

			} else {

				if (!batchSettings.overwriteExstFiles) {
					// If there is a custom destination, alter theDoc.filePathForSave 
					// to point to the desired custom destination, and save again.
					DoFillInCustomDestinationForSave(theDoc, sourceDocumentPath, batchSettings);
				}
				theDoc.save(false);

			}
		}

		return true;
	}
	
	// ----------------------------------------------------------

	function DoForceExport(theDoc, sourceDocumentPath, batchSettings)
	{
		var curExportFormatOptions = theDoc.exportFormatOptions;

		// Always disable cropping.
		curExportFormatOptions.crop = false;

		var theDir = Files.getDirectory(sourceDocumentPath);
		if (!batchSettings.overwriteExstFiles) {
			theDir = batchSettings.outputDir;
		}
		var theName = FileRenamer(batchSettings, sourceDocumentPath);
				
		var exportPath = Files.makePathFromDirAndFile(theDir, theName);

		theDoc.exportTo(exportPath, curExportFormatOptions);
	}
	
	// ----------------------------------------------------------

	function DoExport(theDoc, sourceDocumentPath, batchSettings)
	{
		if (batchSettings && (batchSettings.exportOptions != null)) {

			var curExportFormatOptions;
			if (batchSettings.exportOptions.useFormatOptionsFromEachFile) {
				curExportFormatOptions = theDoc.exportFormatOptions;
			} else {
				curExportFormatOptions = Document.findExportFormatOptionsByName(batchSettings.exportOptions.exportFormatOptions.name);
				if (curExportFormatOptions == null)
					curExportFormatOptions = batchSettings.exportOptions.exportFormatOptions;
			}
					
			// Copy the scaling/cropping info back over, since we may have
			// gotten that info from the doc or the named settings,
			// and want to override it here.
			if (batchSettings.exportOptions.exportFormatOptions != null) {
				curExportFormatOptions.applyScale = batchSettings.exportOptions.exportFormatOptions.applyScale;
				curExportFormatOptions.useScale = batchSettings.exportOptions.exportFormatOptions.useScale;
				curExportFormatOptions.percentScale = batchSettings.exportOptions.exportFormatOptions.percentScale;
				curExportFormatOptions.xSize = batchSettings.exportOptions.exportFormatOptions.xSize;
				curExportFormatOptions.ySize = batchSettings.exportOptions.exportFormatOptions.ySize;
				curExportFormatOptions.cropTop = batchSettings.exportOptions.exportFormatOptions.cropTop;
				curExportFormatOptions.cropLeft = batchSettings.exportOptions.exportFormatOptions.cropLeft;
				curExportFormatOptions.cropBottom = batchSettings.exportOptions.exportFormatOptions.cropBottom;
				curExportFormatOptions.cropRight = batchSettings.exportOptions.exportFormatOptions.cropRight;
				curExportFormatOptions.crop = batchSettings.exportOptions.exportFormatOptions.crop;
			}
										
			// Always disable cropping.
			curExportFormatOptions.crop = false;
					
			// If you want to actually modify the document, jam the settings back in here, like so:
			// 			theDoc.exportFormatOptions = curExportFormatOptions;
			// We don't usually want to do this; instead, we pass the export settings
			// as the (optional) second argument to exportTo(), which will leave the document
			// unaffected.

			// if doing optimize to size
			if (batchSettings.exportOptions.batchExpOptToSize > 1) {
				writeLog("Trying to optimize to no more than " + batchSettings.exportOptions.batchExpOptToSize + " bytes.");
				// save current doc export options
				var savedExportOptions = theDoc.exportFormatOptions;
				
				// adjust the options to try to achieve the specified size
				theDoc.exportFormatOptions = curExportFormatOptions;
				theDoc.adjustExportToSize(batchSettings.exportOptions.batchExpOptToSize, false);
				curExportFormatOptions = theDoc.exportFormatOptions;
					
				// restore the original doc export options
				theDoc.exportFormatOptions = savedExportOptions;
			}

			var theDir = Files.getDirectory(sourceDocumentPath);
			if (!batchSettings.overwriteExstFiles) {
				theDir = batchSettings.outputDir;
			}
			var theName = FileRenamer(batchSettings, sourceDocumentPath);
					
			var exportPath = Files.makePathFromDirAndFile(theDir, theName);

			theDoc.exportTo(exportPath, curExportFormatOptions);
		}
	}

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

	function DoRename(theDoc, sourceDocumentPath, batchSettings)
	{
		// do not do anything if there is no data for renaming
		if ((batchSettings.batchRenameParms.filenamePrefix != null)
			|| (batchSettings.batchRenameParms.filenameSuffix != null)
			|| (batchSettings.batchRenameParms.replaceBlanks == true)
			|| (batchSettings.batchRenameParms.replaceString != null)) {

			var origDir = Files.getDirectory(sourceDocumentPath);
			theDir = batchSettings.outputDir;
			if (theDir == null)
				theDir = origDir; 
			
			// only rename if original files are overwritten
			// or if custom output destination is the original location
			if ((batchSettings.overwriteExstFiles) || (theDir == origDir)) {

				var theName = FileRenamer(batchSettings, sourceDocumentPath);
				var origName = Files.getFilename(sourceDocumentPath, true).toString();	// strip extension, if any, and ensure string-ness	
				var theExtension = Files.getExtension(sourceDocumentPath).toString();
				origName += theExtension;

				var savePath = Files.makePathFromDirAndFile(theDir, theName);
				var origPath = Files.makePathFromDirAndFile(origDir, origName);

				if (Files.deleteFileIfExisting(savePath)) {
					theDoc.save(false);
					Files.copy(origPath, savePath);
				} else {
					// existing file could not be deleted for some reason
				}
			}
		}
	}

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

	function DoScale(theDoc, batchSettings)
	{
		if (batchSettings && (batchSettings.batchScaleParms != null)) {
			if (batchSettings.batchScaleParms.crop) {
				// CROP
				var cropRect;
				cropRect.left = batchSettings.batchScaleParms.cropLeft;
				cropRect.top = batchSettings.batchScaleParms.cropTop;
				cropRect.right = batchSettings.batchScaleParms.cropRight;
				cropRect.bottom = batchSettings.batchScaleParms.cropBottom;
				theDoc.setDocumentCanvasSize(cropRect);
			}
			else if (batchSettings.batchScaleParms.applyScale) {
				// SCALE
				var newWidth = theDoc.width;
				var newHeight = theDoc.height;
				var applyPercentage = true;
				var onlyScaleDown = false;
				if (batchSettings.batchScaleParms.onlyScaleDown != undefined) {
					onlyScaleDown = batchSettings.batchScaleParms.onlyScaleDown;
				}
				var scalePct = 1.0;

					if (batchSettings.batchScaleParms.useScale) { // use percentage
					scalePct = batchSettings.batchScaleParms.percentScale * 0.01;
					onlyScaleDown = false;
				} 
				else if (batchSettings.batchScaleParms.xSize < 0) {
							// scaling to fit
					var xPct = - (batchSettings.batchScaleParms.xSize / theDoc.width);
					var yPct = - (batchSettings.batchScaleParms.ySize / theDoc.height);
					// choose the smaller scale
							if (xPct <= yPct) {
								scalePct = xPct;
							} else {
								scalePct = yPct;
							}
				}
				else if (batchSettings.batchScaleParms.xSize == 0) {
					if (batchSettings.batchScaleParms.ySize == 0) {
								// this is illegal, but let it go
								scalePct = 1.0;
					} else {
								// xScale is zero, use yScale
						scalePct = batchSettings.batchScaleParms.ySize / theDoc.height;
					}
				}
				else if (batchSettings.batchScaleParms.ySize == 0) {
								// yScale is zero, use xScale
					scalePct = batchSettings.batchScaleParms.xSize / theDoc.width;
				} else {
					// scaling to size 
					newWidth = batchSettings.batchScaleParms.xSize;
					newHeight = batchSettings.batchScaleParms.ySize;
					applyPercentage = false;
							}

				if (applyPercentage) {
							// make sure scalePct is positive
							if (scalePct < 0) {
						scalePct = -scalePct;
					}
					if (onlyScaleDown && scalePct >= 1.0) {
						// skip docs that are already small enough
						writeLog("Not scaling: document already small enough.");
						return;
					}
					newWidth = theDoc.width * scalePct;
					newHeight = theDoc.height * scalePct;
							}
														
				writeLog("Scale: " + theDoc.width + " x " + theDoc.height + " ==> " + newWidth + " x " + newHeight);
				var newDocRect = {
					left:0, top:0, right:newWidth, bottom:newHeight
				};
					var newDocResolution = {
						pixelsPerUnit:theDoc.resolution,
						units:theDoc.resolutionUnits,
					};

					theDoc.setDocumentImageSize(newDocRect, newDocResolution);
				
			}
		}
	}

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

	function DoFindAndReplace(theDoc, sourceDocumentPath, batchSettings)
	{
		if (batchSettings && (batchSettings.findAndReplaceParms != null)) {
			var theFinder = theDoc.makeFind(batchSettings.findAndReplaceParms);		
			var replacedAnything = theFinder.replaceAll();
			if (theDoc.filePathForSave == null) {
				theDoc.filePathForSave = Document.makeGoodNativeFilePath(sourceDocumentPath);
				if (theDoc.filePathForSave == null) {
					// This should never happen, but check, just in case.
					alert(Errors.EInternalError);
					return false;
				}
			}

			if (false == replacedAnything) {
				// Don't save the file ... we didn't do anything.
				// But, if we are doing backups, make a copy of the original file
				// (now located in the Original Files folder) back in the original spot.
				if (batchSettings.doBackupFiles && backupPath != null && sourceDocumentPath != null) {
					var errorString = SafeCopyFileTo(backupPath, sourceDocumentPath);
					if (errorString != null) {
						writeLog(errorString);
						alert(errorString);
						return false;
					}
				}
			}
			if (theDoc.filePathForSave == null) {
				// This should never happen, but check, just in case.
				alert(Errors.EInternalError);
				return false;
			}
		}
		return true;
	}
	
	// ----------------------------------------------------------

	function DoFillInCustomDestinationForSave(theDoc, sourceDocumentPath, batchSettings)
	{
		var theName = FileRenamer(batchSettings, sourceDocumentPath);

		theDoc.filePathForSave = Files.makePathFromDirAndFile(batchSettings.outputDir, theName);
	}

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

	function ProcessOneDocForOneBatch(theDoc, sourceDocumentPath, batchOperation, batchSettings, donelast)
	{
		var backupPath = null;

		writeLog(batchOperation);
		
		// chop the batchOperation string at the leftmost : character

		// if that == "operation:" then process it
		// else if that == "commandfile:" then run the script specified
		// note that the "operation:" and "commandfile:" prefixes, as
		// well as the operation names, must not be changed in this template
		var opString = "operation:";
		var commandString = "commandfile:";

		if (batchOperation.substring(0, opString.length) == opString) {

			var rightString = batchOperation.substring(opString.length, batchOperation.length);
			
			if (rightString == "rename") {

				donelast.doRename = true;

			} else if (rightString == "export") {

				donelast.doExport = true;

			} else if (rightString == "scale") {

				DoScale(theDoc, batchSettings);

			} else if (rightString == "findreplace") {

				DoFindAndReplace(theDoc, sourceDocumentPath, batchSettings);

			}

		} else if (batchOperation.substring(0, commandString.length) == commandString) {

			var rightCommandString = batchOperation.substring(commandString.length, batchOperation.length);

			// rightString is the commandfile URL
			fw.runScript(rightCommandString);

			// It would be nice to return a useful value. Maybe someday.

		}


		return true;
	}

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

	function UniquePathnameWithSameExtension(pathname)
	{
		if (Files.exists(pathname) == false) {
			return pathname;	// already unique
		}
		
		var filename = Files.getFilename(pathname).toString(); // make sure it's a string, not a number
		var extension = "";
		var curlength = filename.length;
		for (var i = 1; i < curlength; i++) {
			if (filename.charAt(curlength - i) == ".") {
				extension = filename.substr(curlength - i);
				filename = filename.substr(0, curlength - i);
				break;
			}
		}

		var newpathname = pathname;
		var newfilename = "";
		for (var j = 1; j < 10000; j++) {
			newfilename = filename + "-" + j + extension;
			newpathname = Files.setFilename(pathname, newfilename);
			if (Files.exists(newpathname) == false)
				return newpathname;
		}
		
		// We should never get here.
		return null;
	}

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

	function GetBackupDirectory(pathname)
	{
		if (Files.exists(pathname) == false) {
			return null;
		}
		
		var dir = Files.getDirectory(pathname);
		var dirName = App.getPref("OriginalFilesFolderName");
		var bkupDir = Files.makePathFromDirAndFile(dir, dirName);

		if (Files.exists(bkupDir) == false)
			Files.createDirectory(bkupDir);

		if (Files.exists(bkupDir) == false) {
			return null;
		}

		if (Files.isDirectory(bkupDir) == false) {
			return null;
		}
			
		return bkupDir;
	}
	
	// ----------------------------------------------------------

	function GetBackupFile(pathname, doIncrementalBackup)
	{
		var bkupDir = GetBackupDirectory(pathname);
		if (bkupDir == null)
			return null;
		var filename = Files.getFilename(pathname);
		var backupFile = Files.makePathFromDirAndFile(bkupDir, filename);

		if (doIncrementalBackup)
			backupFile = UniquePathnameWithSameExtension(backupFile);
			
		// If your on windows then call checkForPathLength
		if (App.platform != "mac") {
			backupFile = checkForPathLength(backupFile);
		}

		return backupFile;
	}

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

	function SafeCopyFileTo(sourcePath, destPath)
	{
		if (Files.deleteFileIfExisting(destPath) == false)
			return Files.getLastErrorString();

		if (Files.copy(sourcePath, destPath) == false)
			return Files.getLastErrorString();
		
		return null;
		
	}

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

	function SafeMoveFileTo(sourcePath, destPath)
	{
		if (Files.deleteFileIfExisting(destPath) == false)
			return Files.getLastErrorString();

		// Note: if destPath exists, the two files are swapped; if destPath
		// does not exist, sourcePath is moved to destPath. Either way,
		// both source and dest must point to the same volume, or the call
		// will fail.
		if (Files.swap(sourcePath, destPath) == false)
			return Files.getLastErrorString();
		
		return null;
	}

	// ----------------------------------------------------------
	
	function checkForPathLength(backupFile)
	{
		backupFile = backupFile .toString();
		if (backupFile.length  > 256){
			alert("This file path is too long:" + backupFile + ".  Windows requires the full path be less than 256 characters")
			backupFile = null;
		}
		return backupFile;
	}

	// ----------------------------------------------------------
	// Rename a file without opening it.
	function RenameOneDoc(batchSettings, docPathName)
	{
		App.batchStatusString = Files.getFilename(docPathName);
		var newName = FileRenamer(batchSettings, docPathName);
		
		var result = true;
		var outDir = batchSettings.outputDir;
		if (batchSettings.overwriteExstFiles == false && outDir != null) {
			// custom output directory, so copy the file.
			var copyPathName = Files.makePathFromDirAndFile(outDir, newName);
			result = Files.copy(docPathName, copyPathName);
			if (result == false) {
				writeLog("could not copy the file to " + copyPathName);
			}
		} else {
			// if destination is same directory, just rename
			result = Files.rename(docPathName, newName);
			if (result == false) {
				writeLog("could not rename the file to " + newName);
			}
		}
		
		return true;
	}

	// ----------------------------------------------------------
	
	function FileRenamer(batchSettings, thePath)
	{
		// Get the root filename
		var theName = Files.getFilename(thePath, true).toString();
		// Get the extension
		var theExtension = Files.getExtension(thePath).toString();

		if (batchSettings.batchRenameParms) {
			
			// replace first match of /[x][x][x]/ with yyy
			if (batchSettings.batchRenameParms.replaceString != null) {
				var replaceString = batchSettings.batchRenameParms.replaceString;
				if (replaceString.length > 0) {
					// build a pattern from the replace string
					var patternString = "";
					for (var i=0; i<replaceString.length; i++) {
						patternString = patternString + "[" + replaceString[i] + "]";
					}
					var pattern = new RegExp(patternString);
					// get the new string
					var withStr = "";
					if (batchSettings.batchRenameParms.withString != null) {
						withStr = batchSettings.batchRenameParms.withString;
					}
					// do the replacement
					theName = theName.replace(pattern, withStr); // replace first match
				}
			}
			
			// replace all blanks
			if (batchSettings.batchRenameParms.replaceBlanks) {
				var blanksStr = "";
				if (batchSettings.batchRenameParms.blanksString != null) {
					blanksStr = batchSettings.batchRenameParms.blanksString;
				}
				theName = theName.replace(/[ ]/g, blanksStr); // replace all blanks
			}

			// add prefix
			if (batchSettings.batchRenameParms.filenamePrefix != null) {
				theName = batchSettings.batchRenameParms.filenamePrefix + theName;
			}
			
			// add suffix
			if (batchSettings.batchRenameParms.filenameSuffix != null) {
				theName = theName + batchSettings.batchRenameParms.filenameSuffix;
			}
		}
		
		// check for empty name, or name beginning with a period
		if (theName.length == 0) {
			// replace empty name with underling character
			theName = "_";
		}
		else if (theName.charCodeAt(0) == 46) {
			// replace leading period with underline character
			theName = "_" + theName.substr(1, theName.length);
		}

		// re-add the original extension, if any. 
		theName += theExtension;
		writeLog("==> " + theName);
		return theName;
	}
