/**
 * @author $Author: mburbidg $
 * @date $DateTime: 2009/02/11 08:02:48 $
 * @version	$Revision: #1 $
 * 
 * ADOBE CONFIDENTIAL
 *
 * Copyright 1997-2007 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 may be covered by U.S. and Foreign Patents,
 * patents in process, 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.
*/

//-----------------------------------------------------------------------------
//--------  BEGIN   BUG  2334616     -------------------------------------
//-----------------------------------------------------------------------------
//
//
//
// #include "../shared/reviewpanel.jsx"
//
//
//  As per bug#2334616, we can't yet use #include in CSXS, so instead 
//    the contents of it is duplicated below. If you have to change this
//    code before the bug is fixed, please also change reviewpanel-shared.jsx
//    as well as the other apps' scripts
//

function ReviewPanelUtilities() {
}


// this is a wrapper that takes care of logging, handling exceptions and return values
ReviewPanelUtilities.callMainFunction = function(entryPointFunction) {
	try {
		// construct a new argument array for the function
		var args = [];
		for(var i = 1; i<arguments.length; i++) {
			args.push (arguments[i]);
		}
	
		// call the entry point function with the remaining arguments
		var result = entryPointFunction.apply(undefined, args);
			
	} catch (x1) {
		return "<string><![CDATA[<error>" + x1 +  "</error>]]></string>";
	}
	return "<string><![CDATA[" + result +  "]]></string>";
}


//********************************************************************************************
// Utils.fixPathIfNeeded
//
// Windows-specific file path fix
//********************************************************************************************

ReviewPanelUtilities.fixPathIfNeeded = function(pathIn, checkForWindowsOS)
{
	var path = pathIn;
	var validOS = true;
	if(checkForWindowsOS) {
		if(File.fs == 'Windows') 
			validOS = true;
		else
			validOS = false;
	}
	if (RegExp("^file:///").test(path) && validOS) 
	{
		// On Windows, paths of the form 'file:///c:/etc' will fail -- it's that third
		// slash that throws it off. So replace the /// with //. -MJP
		// enabling this code for Mac -roey
		
		// Test if the path is in the form of file:////*. This will happen when file is on an
		// unmapped network drive on Windows. 
		if (RegExp("^file:////").test(path)) {
			path = path.substr(7); // Convert the file path from file:////* to //* so that javascript can understand
		}
		else {
			path = path.substr(0,7) + path.substr(8);
		}
	}
	return path;
}

//********************************************************************************************
// ReviewPanelUtilities.fixVolumeIfNeeded
//
// Refer to reviewpanel-id.jsx for an explanation of this function.
//
//********************************************************************************************

ReviewPanelUtilities.fixVolumeIfNeeded = function (path, rootVolumeName) 
{
    var fileAtPath = File (path);
    // 1) We have rootVolumeName. This will be null on windows
    // 2) Check if the ExtenScript path includes a /Volumes in the beginning. If not, then we can ignore
    if (rootVolumeName != 'null' && RegExp("^/Volumes").test(fileAtPath.fsName)) {
    	
    	// Check if the path is in the form of url. This will happen when the path is formed in ActionScript.
    	if (RegExp("^file:///").test(path)) {
	                
	        // Now decide which location should get preference. The remote volume or the local directory under the root volume
	        // If the ActionScript path starts with file:///Volumes, then remote volume should get the preference.
	        if (RegExp("^file:///Volumes").test(path)) {
	             return path;
	        }
	        else {
	              // The user intended to access the local volume
	              // Try to construct a local path
	              var newPath = "/Volumes/"+rootVolumeName+fileAtPath.fullName;
	              // Check if the file exists at that location
	              var newFile = File (newPath);
	              // This is just to be safe.
	              if (newFile.exists)
	              	return newPath;
	        }
	    }
    }
    return path;
}


//-----------------------------------------------------------------------------
//--------  END   BUG  2334616     -------------------------------------
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
//
// Globals
//
//-----------------------------------------------------------------------------

var previewDifferentiator = 0;

// job management
var currJob=0;
var nextJobNum=1;
var previousJob=0;
var previousJobResult="";

//-----------------------------------------------------------------------------
//
// Entry Points
//
//-----------------------------------------------------------------------------


var getDocumentPath = function(doc)
{
	try {
    	//1.0 Bug 2530112: We need to specify encoding for the file name.
    	doc.fullName.encoding = "UTF-8";
		var path = doc.fullName.fsName;
		return path;
	}
	catch(e) {
		return "NA";
	}
}

//********************************************************************************************
// scriptAlert
//
// shows an alert
//********************************************************************************************

var scriptAlert = function(msg)
{
	return ReviewPanelUtilities.callMainFunction(_scriptAlert, msg);
}

var _scriptAlert = function(msg)
{
	alert(msg);
	return "<success />";
}



//********************************************************************************************
// getActiveDocument
//
// returns an XML snippet that contains information on the currently active document
//********************************************************************************************

var getActiveDocument = function ()
{
	return ReviewPanelUtilities.callMainFunction(_getActiveDocument);
}
var _getActiveDocument = function ()
{
	if (app.documents.length > 0)
	{
		var doc = app.activeDocument;
		var document = new XML("<document />");
		document.@name = doc.name;
		var guid = _getGuid(doc);
		if(guid != null) {
			document.@id = guid;
		}
        return document.toXMLString();
	}
    else 
    {
        return "";
    }
	
}

//********************************************************************************************
// getDocumentList
//
// returns an XML snippet that contains information on the open documents
//
// Notice that for Photoshop we currently don't list all open documents since we are only interested in the active one
//********************************************************************************************

var getDocumentList = function () {
	return ReviewPanelUtilities.callMainFunction(_getDocumentList);
}
var _getDocumentList = function () {
	var list = new XML('<documents />');
	var count = app.documents.length;
	if (count > 0) {
		// find active document
		var active = app.activeDocument;
		var activeId = _getGuid(active);
		if(activeId == null) {
			// some document that PS can open don't have a GUID, so we use the full path of the document instead
			activeId = active.name; 
		}
		list.@activeDocument = activeId;
		
		// now iterate the document list
		/*
		for(var i=0; i<count; i++) {
			var doc = app.documents[i];
			var document = new XML("<document />");
			document.@id = (doc == active ? activeId : getGuid(doc));
			document.@name = doc.name;
			list.appendChild(document);
		}
		*/
		// Notice that for Photoshop we currently don't list all open documents since we are only interested in the active one
		var document = new XML("<document />");
		document.@id = activeId;
		document.@name = active.name;
		list.appendChild(document);
	}
	
	return list.toXMLString();
}

// This method determines whether the document has an associated file-name
// If not, it returns an error
var isDocumentSaved = function(doc)
{
	return ReviewPanelUtilities.callMainFunction(_isDocumentSaved, doc);
}
var _isDocumentSaved = function(doc)
{
	try
	{
		var name = doc.fullName;
	}
	catch (e)
	{
		return "false";
	}
	return "true";
}
//********************************************************************************************
// getDocumentInfo
//
// returns information about the active document
//********************************************************************************************

var getDocumentInfo = function () {
	return ReviewPanelUtilities.callMainFunction(_getDocumentInfo);
}

var _getDocumentInfo = function () {
	var docInfo = new XML('<docInfo><resolution /><width /><height /><hasFilePath /><isDirty /></docInfo>');
    var doc = app.activeDocument;
	if(doc != null && doc != undefined) {
        docInfo.resolution.setChildren(doc.resolution);
        docInfo.width.setChildren(doc.width.as('px'));
        docInfo.height.setChildren(doc.height.as('px'));
        docInfo.hasFilePath.setChildren(_isDocumentSaved(doc));
        docInfo.isDirty.setChildren(doc.saved ? 'false' : 'true');
	}
	return docInfo.toXMLString();
}
// Saves the document at the location specified in the argument
var saveDocument = function(args)
{
	return ReviewPanelUtilities.callMainFunction(_saveDocument, args);
}
var _saveDocument = function(args)
{
    var arguments = new XML(args);
    var showSaveAsDialog = arguments.@showSaveAsDialog.toString() == 'true';
    
    if(showSaveAsDialog) {
        var idsave = charIDToTypeID( "save" );
        executeAction( idsave, undefined, DialogModes.ALL );
    } else {
        app.activeDocument.save();
    }
}

//********************************************************************************************
// generateContentsFromDocument
//
// generates contents, structure and previews of the whole document (using BridgeTalk to do the latter
// so that this is done asynchronously)
//********************************************************************************************

var generateContentsFromDocument = function(args) {
	return ReviewPanelUtilities.callMainFunction(_generateContentsFromDocument, args);
}

var _generateContentsFromDocument = function(args) {
    if(currJob != 0) {
        throw new Error("Pending job. Can't run two jobs at once.");
    }

    // start new job
    currJob = nextJobNum;
    nextJobNum++;
    previousJobResult="";
    
	var arguments = new XML(args);
    
    // collect data
    var result = generateContentData(app.activeDocument, ReviewPanelUtilities.fixPathIfNeeded(arguments.@previewFolder, 1),
                                                        parseInt(arguments.@previewWidth.toString()), parseInt(arguments.@previewHeight.toString()),
                                                        arguments.@docId.toString(), currJob);
    
    // schedule the preview generation
    var bt = new BridgeTalk;
    bt.target = BridgeTalk.appSpecifier; // target ourselves
    
    // createPreviews(doc, outputFile, previewWidth, previewHeight, quality, format, progressTitle) 
    bt.body = createPreviewsScript + 
                    "createPreviews(app.activeDocument,  '" + result.previews.preview.toString() +
                     "', " + result.contents.part.@previewWidth.toString() + ", " + result.contents.part.@previewHeight.toString() + ", " + 
                     parseInt(arguments.@quality.toString()) + ",  '" + arguments.@format.toString() + "',  '" + arguments.@progressTitle.toString()
                      + "',  '" + arguments.@progressCancelLabel.toString()+ "');";
    
    bt.onResult = function(msg) {
        previousJob = currJob;
        currJob = 0;
        previousJobResult =  msg.body;
    }

    bt.onError = function(msg) {
        previousJob = currJob;
        currJob = 0;
        previousJobResult = "<![CDATA[<error>" + msg.body +  "</error>]]>"
    }
    
    bt.send();
    
	return result.toXMLString();
}


//********************************************************************************************
// getPartGenerationStatus
//********************************************************************************************

var getPartGenerationStatus = function(jobId) {
	return ReviewPanelUtilities.callMainFunction(_getPartGenerationStatus, jobId);
}

var _getPartGenerationStatus = function(jobId) {
    if(currJob == jobId) {
        // job is still pending
        return '<pending jobId="' + currJob + '" />';
    } else if(currJob == 0 && previousJob == jobId) {
        // job has finished
        return previousJobResult;
     } else {
         throw new Error('unknown jobId ' + jobId);
     }
}

//********************************************************************************************
// getGuid
//
// gets the GUID from the document.
//********************************************************************************************

var getGuid = function(doc) {
	return ReviewPanelUtilities.callMainFunction(_getGuid, doc);
}

var _getGuid = function(doc) {
	try {
		var metadata = new XML(doc.xmpMetadata.rawData);
		var id = metadata.descendants('xmpMM:InstanceID')[0].toString();
		return id.split(':').pop();
	} catch(x) {
		return null;
	}
}



//********************************************************************************************
// openFile
//
// brings the document to front if open, or opens up the file
//********************************************************************************************

var openFile = function (args) {
	return ReviewPanelUtilities.callMainFunction(_openFile, args);
}

var _openFile = function (args) {
	var arguments = new XML(args);
	var retval = "<success />";
	
	// open the file
	var path = arguments.@filePath.toString();
	var instanceId = arguments.@instanceId.toString();
	var isSameApp = arguments.@sameApp.toString();
	var rootVolume = arguments.@rootVolumeName.toString();
	if(path == "NA" || isSameApp == "false") {
		retval = "<error/>";	
		if(isSameApp == "true" && instanceId != null && instanceId != "" && makeDocumentActive(instanceId))
			retval = "<success />";
	}
	else 
	{
        path = ReviewPanelUtilities.fixPathIfNeeded(path, 1);
        path = ReviewPanelUtilities.fixVolumeIfNeeded(path, rootVolume);
        var myFile = File(path);
        var documents = getOpenDocuments();
        var openDoc = app.open (myFile);
        var list = getPreviousIds(openDoc);
        
        if(isIdInHistory(list, instanceId))
        {
            // NO NEED to call execute on myFile as it should already be open
            //openDoc.close(SaveOptions.SAVECHANGES);
        }
        else
        {
            retval = "<error/>";
            if(!wasDocumentOpen(documents, openDoc))
                openDoc.close(SaveOptions.DONOTSAVECHANGES);
        }
	}
	return retval;
}
//********************************************************************************************
// getDocumentId
//
// returns the instance id of the document at the path
//********************************************************************************************


var getDocumentId = function (args) {
	return ReviewPanelUtilities.callMainFunction(_getDocumentId, args);
}

var _getDocumentId = function (args) 
{
    var retval = new XML('<success />');
    var arguments = new XML(args);
    var path = arguments.@filePath.toString();
    var rootVolume = arguments.@rootVolumeName.toString();
    path = ReviewPanelUtilities.fixPathIfNeeded(path, 1);
    path = ReviewPanelUtilities.fixVolumeIfNeeded(path, rootVolume);
    var myFile = File(path);
    var documents = getOpenDocuments();
    var doc = app.open (myFile);
    var id = _getGuid(doc);
    if (id != null) {
    	var original = new XML('<instance id="'+id+'"/>');
    	retval.appendChild(original);
    }
    else {
    	retval = new XML('<error />');
    }
    if(!wasDocumentOpen(documents, doc))
        doc.close(SaveOptions.DONOTSAVECHANGES);
    return retval;
}

//********************************************************************************************
// openFileAtPath
//
// opens the file at the given path without any sanity checks
//********************************************************************************************
var openFileAtPath = function (args) {
	return ReviewPanelUtilities.callMainFunction(_openFileAtPath, args);
}

var _openFileAtPath = function (args) {
	var arguments = new XML(args);
	var retval = "<success />";
    var path = arguments.@filePath.toString();
    var rootVolume = arguments.@rootVolumeName.toString();
    path = ReviewPanelUtilities.fixPathIfNeeded(path, 1);
    path = ReviewPanelUtilities.fixVolumeIfNeeded(path, rootVolume);
    var myFile = File(path);
    var isSameApp = arguments.@sameApp.toString();
    var appName = arguments.@application.toString();
    var instanceId = arguments.@instanceId.toString();
    
    if(myFile.exists) {
    	if(isSameApp == "true") {
	    	try {
	    		app.open (myFile);
	    		return retval;
	    	}
	    	catch(e) {
	    		
	    	}
	    }
	    if (appName == "PP" && checkPPStatus()) {
	    	if(!openPProProjectSequence(path, instanceId))
	    		return ("<error>CannotOpenFile</error>");
	    } else {
	        if(!myFile.execute()) {
	        	return ("<error>CannotOpenFile</error>"); 
	        }
		}
    }
    else {
        retval = "<error/>";
    }
	return retval;
}


//********************************************************************************************
// getPreviousIds
//
// scans the history of the document and returns all the previous ids
//********************************************************************************************
function getPreviousIds(doc) 
{
	var metadata =new XML(doc.xmpMetadata.rawData);
	var ids = [];
	
	// First add the current instance id to the array
	var origid = _getGuid(doc);
	if(origid != null)
		ids.push(origid);
	
	var historyXML = new XMLList(metadata.descendants('xmpMM:History'));

	if(historyXML != null && historyXML.length() > 0) 
	{	
	    var loopcount = 0;  
	    while(loopcount < historyXML.length())
	    {
	        var element = historyXML[loopcount];
	        var seqElement = element.descendants('rdf:Seq')[0];
		 
	        var liElement = new XMLList(seqElement.descendants('rdf:li'));
		 
	        var count = 0;
	        while(count <  liElement.length()) {
				var data = new XML(liElement[count]);
				// Fix for bug #2409216 Adding a try-catch block. Not all history elements have an instance id 
				try {
					var id = data.descendants('stEvt:instanceID')[0].toString();
	            	id = id.split(':').pop();
					ids.push(id);
				}
				catch(error) {
				
				}
	            count++;
			}
			loopcount++;
		}
	}
	return ids;
}

//********************************************************************************************
// isIdInHistory
//
// checks if the given id is in the history list
//********************************************************************************************
function isIdInHistory(list, id) {
	var retval = false;
	if(list.length > 0)
	{
		for(var i = 0; i < list.length; i++)
		{
			if(list[i] == id)
			{
				retval = true;
				break;
			}
		}	
	}
	return retval;
}

//********************************************************************************************
// wasDocumentOpen
//
// documents - array of document objects which were open before the current document was opened
// doc - object of the current document
//********************************************************************************************
function wasDocumentOpen(documents, doc) {
	var retval = false;
	var count = 0;
	while (count < documents.length) {
		if(doc == documents[count]){
			retval = true;
			break;
		}
		count++;
	}
	return retval;
}

//********************************************************************************************
// makeDocumentActive
//
// makes the document with the given instanceId active
//********************************************************************************************
function makeDocumentActive(instanceId) {
	var documents = app.documents;
	for(var i = 0; i < documents.length; i++) {
		var curId = _getGuid(documents[i]);
		if(curId != null && instanceId == curId)
		{
			app.activeDocument = documents[i];
			return true;
		}		
	}
	return false;
}

//********************************************************************************************
// getOpenDocuments
//
// returns an array of documents currently open
//********************************************************************************************
function getOpenDocuments()
{
	var documents = app.documents;
	var array = new Array();
	var count = 0;
	while(count < documents.length)
	{
		array.push(documents[count++]);
	}
	return array;
}

//-----------------------------------------------------------------------------
//
// Generate Contents
//
// This is a script that gets send as part of a BridgeTalk request to
// Photoshop in order to support asynchronous content generation.
//
//-----------------------------------------------------------------------------

function generateContentData(doc, previewPath, maxWidth, maxHeight, docId, jobId) {
    var guid = _getGuid(doc);
    if(guid == null) {
        guid = docId;
    }
    var result = new XML('<result documentId="' + guid + '" jobId="' + jobId + '"/>');
    generateData(doc, previewPath, maxWidth, maxHeight, guid, result);

    return result;
}

 function generateData(doc, previewPath, maxWidth, maxHeight, guid, result) {
    // figure out the preview dimensions
    var previewWidth = doc.width.as('px');
    var previewHeight = doc.height.as('px');
    if(previewWidth > maxWidth || previewHeight > maxHeight) {
        var docRatio = previewWidth/previewHeight;
        var maxRatio = maxWidth/maxHeight;
        if(docRatio >  maxRatio) {
            previewWidth = maxWidth ;
            previewHeight = Math.round(maxWidth / docRatio);
        } else {
            previewHeight = maxHeight ;
            previewWidth = Math.round(maxHeight * docRatio);
        }
    }
     
    var contents = new XML('<contents />');
    var parts = new XML('<parts />');
     // for now PS only generates one part
    generatePartData(doc, contents, parts, previewWidth, previewHeight, guid);
    result.appendChild(contents);
    result.appendChild(parts);
    
    var previews = generatePreviewsData(doc, previewPath, previewWidth, previewHeight, guid);
    result.appendChild(previews);
    
    var metadata = generateMetadata(doc);
    if(metadata != null) {
        result.appendChild(metadata);
    }
 }

function generatePartData(doc, contents, parts, previewWidth, previewHeight, guid) {
        var partData = new XML('<part type=\"image\" />');
        partData.@id = guid;
        partData.@documentId = guid;
        partData.@originalHeight = doc.height.as('px');
        partData.@originalWidth = doc.width.as('px');
        partData.@previewHeight = previewHeight;
        partData.@previewWidth = previewWidth;
        contents.appendChild(partData);
        var imageData = new XML('<image />');
        imageData.@id = guid;
        imageData.@originalResolution = doc.resolution;
        parts.appendChild(imageData);
 }

/**
 * escapeFilePath enters escape sequences for &, <, "
 * We cannot use these strings as attribute values
 */
function escapeFilePath(filePath) {
	try {
		filePath = filePath.replace(/&/g, "&amp;");
		filePath = filePath.replace(/"/g, "&quot;");
		filePath = filePath.replace(/</g, "&lt;");
		return filePath;
	}
	catch (e) {
		return filePath;	
	}
}


function generateMetadata(doc) {
    var metadata = null;
    try {
        metadata = new XML('<metadata />');
        var instanceId = _getGuid(doc);
        if(instanceId == null && doc.saved) {
            instanceId = doc.fullName;
        }
        var instanceDetails = new XML('<instanceIdAtReview id=\"'+instanceId+'\"/>');
        var filePath = getDocumentPath(doc);
        filePath = escapeFilePath(filePath);
        var path = new XML('<filePath path=\"'+filePath+'\"/>');
        metadata.appendChild (instanceDetails);
        metadata.appendChild (path);
    }
    catch(e) {
        metadata = null;
    }
    return metadata;
}

function generatePreviewsData(doc, previewPath, previewWidth, previewHeight, guid) {
    // make sure that output folder exists
    (new Folder(previewPath)).create();
    var appendSlash='/';
    if(previewPath != '' && previewPath.lastIndexOf('/') == previewPath.length-1) {
        appendSlash='';
    }
    
    var previewData = new XML('<previews />');
    var name = guid.substr(0, 7) + previewDifferentiator;
    previewDifferentiator = previewDifferentiator + 1;
    var fullFilePath = previewPath + appendSlash + 'preview_' + name;
    previewData.appendChild(new XML('<preview partId=\"' +  guid + '\">' + fullFilePath + '</preview>'));
    return previewData;
}

var createPreviewsScript = "\
    function createPreviews(doc, outputFile, previewWidth, previewHeight, quality, format, progressTitle, progressCancelLabel) {\
        var result = '<success />'\
        var pbar = createProgressBar(progressTitle, progressCancelLabel);\
        try {\
            createPreview(doc, previewWidth, previewHeight, quality, format, outputFile, pbar);\
            pbar.updateProgress(100);\
        } catch (x) {\
            if(canceled) {\
                result = '<canceled />';\
            } else {\
                result = '<error><![CDATA[' + x +  ']]></error>';\
            }\
        } finally {\
            pbar.close();\
        }\
        return result;\
    }\
    \
    var canceled = false;\
    function createProgressBar(title, cancelLabel) {\
        var win = new Window('palette {properties:{closeButton:false}}', title);\
        canceled = false;\
        win.orientation = 'row';\
        win.bar = win.add('progressbar', undefined, 0, 100);\
        win.bar.preferredSize = [300, 15];\
        win.cancel = win.add('button', undefined, cancelLabel);\
        win.cancel.onClick = function() {\
            canceled = true;\
        }\
        win.updateProgress = function(val) {\
            if(canceled) {\
                throw new Error('canceled');\
            }\
            var win = this;\
            win.bar.value = val;\
            win.show();\
        }\
        return win;\
    }\
    \
    function createPreview(doc, previewWidth, previewHeight, quality, format, fullFilePath, pbar) {\
        pbar.updateProgress(5);\
        var copy = doc.duplicate('temp', true);\
        try {\
            pbar.updateProgress(33);\
            if(copy.mode != DocumentMode.RGB) {\
                copy.changeMode(ChangeMode.RGB);\
                pbar.updateProgress(35);\
            }\
            if(copy.bitsPerChannel != BitsPerChannelType.EIGHT) {\
                copy.bitsPerChannel = BitsPerChannelType.EIGHT;\
                pbar.updateProgress(40);\
             }\
            var width = copy.width.as('px');\
            var height = copy.height.as('px');\
            if(width > previewWidth || height > previewHeight) {\
                copy.resizeImage(UnitValue(previewWidth, 'px'), UnitValue(previewHeight, 'px'), copy.resolution, ResampleMethod.BICUBICSHARPER);\
                pbar.updateProgress(60);\
            }\
            try{\
                var desiredProfileName = 'sRGB IEC61966-2.1';\
                if(copy.colorProfileName != desiredProfileName) {\
                    copy.convertProfile(desiredProfileName,  Intent.PERCEPTUAL, true, true);\
                    pbar.updateProgress(65);\
                }\
            } catch (x) {\
                // image doesn't have a source profile\
                // we leave its colors untouched assuming that it is sRGB\
             }\
            copy.flatten();\
            pbar.updateProgress(75);\
            if(format == 'png' || format == 'all') {\
                var pngOptions = new PNGSaveOptions();\
                pngOptions.interlaced = false;\
                copy.saveAs(new File(fullFilePath+'.png'), pngOptions, true);\
                pbar.updateProgress(90);\
            }\
            if(format == 'jpg' || format == 'all') {\
                var jpgOptions = new JPEGSaveOptions();\
                jpgOptions.embedColorProfile = false;\
                jpgOptions.formatOptions = FormatOptions.STANDARDBASELINE;\
                jpgOptions.quality = quality;\
                copy.saveAs(new File(fullFilePath+'.jpg'), jpgOptions, true);\
            }\
            pbar.updateProgress(99);\
        } finally {\
            copy.close(SaveOptions.DONOTSAVECHANGES);\
        }\
    }\
    \
";



// DEBUG
/*
_generateContentsFromDocument('<arguments previewFolder="/Users/rhorns/Desktop/test" previewWidth="1200" previewHeight="800" docId="foo" progressTitle="do it" progressCancelLabel="Cancel" quality="5" format="all"/>');
*/


// Constants and variables for handling remote repairs
var INDESIGN = "ID";
var PHOTOSHOP = "PS";
var ILLUSTRATOR = "IL";
var PREMIEREPRO = "PP";
var DREAMWEAVER = "DW";
var TIME_TO_WAIT = 100;
var PARTIAL_SUCCESS_RETVAL = 'partialSuccess';
var FAILURE_RETVAL = 'failure';

var callSourceApplicationToRepair = function(args) {
    return ReviewPanelUtilities.callMainFunction(_callSourceApplicationToRepair, args);
}

var _callSourceApplicationToRepair = function(args) {
	var retval = '<error />'; 
	var arguments = new XML(args);
    // Store the passed arguments
    var sourceApp = arguments.@appName.toString();
    var docId = arguments.@documentId;
    var fileURL = arguments.@filePath.toString();
    var rootVolume = arguments.@rootVolumeName.toString();
    fileURL = ReviewPanelUtilities.fixPathIfNeeded(fileURL, 1);
    fileURL = ReviewPanelUtilities.fixVolumeIfNeeded(fileURL, rootVolume);
    // Fetch the application specifier for the source app
    var appSpecifier = BridgeTalk.getSpecifier(appNames[sourceApp]);
    
    // Check if the application specifier is valid
    if (appSpecifier != null && appSpecifier != 'undefined') {
    	// Get the status of the host application
        var status = BridgeTalk.getStatus (appSpecifier);
        if (status != 'ISNOTINSTALLED' && status != 'BUSY' && status != 'UNDEFINED') {
        	// The valid status's are - ISNOTRUNNING, IDLE, PUMPING.
        	// Create a bridgetalk object aimed at the necessary app
            var bt = new BridgeTalk;
            bt.target = appSpecifier;
            
            // DreamWeaver has its own custom code to fix the url
		    if (sourceApp == DREAMWEAVER) {
		    	var tempFile = File (fileURL);
		    	bt.body = appScripts[sourceApp] + " repairAssociation('"+fileURL+"', '"+tempFile.fsName+"', '"+PARTIAL_SUCCESS_RETVAL+"', '"+FAILURE_RETVAL+"', '"+docId+"');";
		    }
		    else
            	bt.body = appScripts[sourceApp] + " repairAssociation('"+fileURL+"', '"+PARTIAL_SUCCESS_RETVAL+"', '"+FAILURE_RETVAL+"', '"+docId+"');";
            
            bt.onResult = function(msg) {
            	// Repair worked :)
                var btResult = msg.body;
                if (btResult != FAILURE_RETVAL)
                {
            		if (btResult != PARTIAL_SUCCESS_RETVAL) {
            			retval = new XML('<success />');
		                var returnId = new XML('<instance id="'+btResult+'"/>');        
		                retval.appendChild(returnId);
	                }
	                else {
	                	retval = '<success />'; 
	                }
            	}
            }
            bt.onReceived = function (msg) {
               // alert ("received");
            }
            bt.onError = function(msg) {
                // alert ("error "+msg.body);
            }
            bt.onTimeout = function (msg) {
                // not sure what to do here. The request can time out because the app took a while to launch.
                // This doesn't necessarily mean that the request won't complete.
                // A solution will be to increase the value of TIME_TO_WAIT so that we do not get false negatives. 
          		// TO-DO.
                // alert ("time out");
            }
            bt.send(TIME_TO_WAIT);
        }
	}
    
    return retval;
}

function checkPPStatus() {
	var appSpecifier = BridgeTalk.getSpecifier(appNames[PREMIEREPRO]);
	// Check if the application specifier is valid
    if (appSpecifier != null && appSpecifier != 'undefined') {
    	// Get the status of the host application
        var status = BridgeTalk.getStatus (appSpecifier);
        if (status == 'ISNOTRUNNING' || status != 'IDLE' || status != 'PUMPING') {
        	// The valid status's are - ISNOTRUNNING, IDLE, PUMPING.
        	return true;
    	}
    }
    return false;
}

// openPProProjectSequence: open specified project and sequence using premiere pro

function openPProProjectSequence(path, sequenceId) {
	ppro = new BridgeTalk();
	var appSpecifier = BridgeTalk.getSpecifier(appNames[PREMIEREPRO]);
	ppro.target = appSpecifier;
	ppro.body = appScripts[PREMIEREPRO] + " repairAssociation('"+path+"', '"+PARTIAL_SUCCESS_RETVAL+"', '"+FAILURE_RETVAL+"', '"+sequenceId+"');";
    ppro.onResult = function(msg) {
        var btResult = msg.body;
        if (btResult == FAILURE_RETVAL)
        {
    		return false;
    	}
    }
    ppro.onError = function(msg) {
        // alert ("error "+msg.body);
        return false;
    }
    ppro.onTimeout = function (msg) {
        //return false;
    }
    ppro.send(TIME_TO_WAIT);
	return true;
}

var repairScriptID = "\
    function repairAssociation(fileURL, partialSuccessMessage, failureMessage) {\
	    var retval = failureMessage;\
	    var output;\
	    var doc = null;\
		var myFile = File(fileURL);\
		try {\
			doc = app.open (myFile);\
		}\
		catch (e) {\
		    if(myFile.execute())\
		    	retval = partialSuccessMessage;\
			else\
				retval = failureMessage;\
		}\
	    if (doc != null) {\
	    	try {\
	        	var instanceId = doc.metadataPreferences.getProperty('http://ns.adobe.com/xap/1.0/mm/', 'InstanceID');\
	        	instanceId = instanceId.split(':').pop();\
	        	retval = instanceId;\
	    	}\
	    	catch (innerE) {\
	    		//  just ensuring that we do not go out\
	    		retval = partialSuccessMessage;\
	    	}\
	    }\
	    return retval;\
    }\
";

var repairScriptPS = "\
    function repairAssociation(fileURL, partialSuccessMessage, failureMessage) {\
	    var retval = failureMessage;\
	    var output;\
	    var doc = null;\
		var myFile = File(fileURL);\
		try {\
			doc = app.open (myFile);\
		}\
		catch (e) {\
		    if(myFile.execute())\
		    	retval = partialSuccessMessage;\
			else\
				retval = failureMessage;\
		}\
	    if (doc != null) {\
	    	try {\
	    		var metadata = new XML(doc.xmpMetadata.rawData);\
				var id = metadata.descendants('xmpMM:InstanceID')[0].toString();\
				retval = id.split(':').pop();\
	    	}\
	    	catch (innerE) {\
	    		//  just ensuring that we do not go out\
	    		retval = partialSuccessMessage;\
	    	}\
	    }\
	    return retval;\
    }\
";

var repairScriptIL = "\
    function repairAssociation(fileURL, partialSuccessMessage, failureMessage) {\
	    var retval = failureMessage;\
	    var output;\
	    var doc = null;\
		var myFile = File(fileURL);\
		try {\
			doc = app.open (myFile);\
		}\
		catch (e) {\
		    if(myFile.execute())\
		    	retval = partialSuccessMessage;\
			else\
				retval = failureMessage;\
		}\
	    if (doc != null) {\
	    	try {\
	    		var metadata = new XML(doc.XMPString);\
				var id = metadata.descendants('xmpMM:InstanceID')[0].toString();\
				retval = id.split(':').pop();\
	    	}\
	    	catch (innerE) {\
	    		//  just ensuring that we do not go out\
	    		retval = partialSuccessMessage;\
	    	}\
	    }\
	    return retval;\
    }\
";

var repairScriptPP = "\
	function fixProjectPath(path) {\
		if(File.fs == 'Windows')\
		{\
			path = path.replace (/\\/g, '/');\
			if(path.indexOf('//?/') == 0) {\
				path = path.substring(4);\
				if (path.indexOf('UNC') == 0) {\
					path = '/' + path.substring(3);\
				}\
			}\
		}\
		return path;\
	}\
	function isProjectOpen(path) {\
		try {\
		var projPath = app.project.path;\
		projPath = fixProjectPath(projPath);\
		var pFile = File(projPath);\
		var nFile = File(path);\
		if(pFile.exists && nFile.exists && pFile.fsName == nFile.fsName)\
			return true;\
		}\
		catch(e) {\
		\
		}\
		return false;\
	}\
    function repairAssociation(fileURL, partialSuccessMessage, failureMessage, docId) {\
	    var retval = failureMessage;\
	    var output;\
		var myFile = File(fileURL);\
		try {\
			if (!isProjectOpen(fileURL)){\
				if (!app.openDocument(myFile.fsName)){\
					if(myFile.execute())\
				    	retval = partialSuccessMessage;\
					else\
						retval = failureMessage;\
				}else{\
					app.project.openSequence(docId);\
				}\
			}\
			else {\
				app.project.openSequence(docId);\
			}\
		}\
		catch (e) {\
		    if(myFile.execute())\
		    	retval = partialSuccessMessage;\
			else\
				retval = failureMessage;\
		}\
        retval = docId;\
	    return retval;\
    }\
";

var repairScriptDW = "\
	function repairAssociation(fileURL, dwURL, partialSuccessMessage, failureMessage, docId) {\
		var retval = failureMessage;\
		if (DWfile.exists(dwURL)) {\
			var doc = dreamweaver.openDocument(dw.convertURIToFilePath(dwURL));\
			if (doc == null || doc == undefined) {\
				if(dreamweaver.openFileInOSDefaultApp(fileURL)) {\
	        		retval = partialSuccessMessage;\
	        	}\
				else {\
					retval = failureMessage;\
				}\
			}\
			else {\
				try {\
					retval = doc.getOpenPathName();\
				} catch (e) {\
					retval = partialSuccessMessage;\
				}\
			}\
		}\
		// return is not supported in DW.\
		//return 'abc';\
	}\
";


// Maintain an array for the app names
var appNames = new Array();
appNames[INDESIGN] = "indesign";
appNames[PHOTOSHOP] = "photoshop";
appNames[ILLUSTRATOR] = "illustrator";
appNames[PREMIEREPRO] = "premierepro";
appNames[DREAMWEAVER] = "dreamweaver";

// Maintain an array for the script which should be executed for a particular product
var appScripts = new Array();
appScripts[INDESIGN] = repairScriptID;
appScripts[PHOTOSHOP] = repairScriptPS;
appScripts[PREMIEREPRO] = repairScriptPP;
appScripts[ILLUSTRATOR] = repairScriptIL;
appScripts[DREAMWEAVER] = repairScriptDW;
