/**
 * @author $Author: nachaina $
 * @date $DateTime: 2009/03/24 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.
*/

#include "../shared/reviewpanel.jsx"

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

// Replace imageType with the value 'jpg' if we want to switch to jpg previews. Currently the Illustrator team
// has asked us to use png. Date 09/28/2009
var imageType = "png";
var previewDifferentiator = 0;

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


//********************************************************************************************
// getEventsSupport.
//
// determines whether the application support events to notify of selection and document changes
//********************************************************************************************

var getEventsSupport = function()
{
	var eventsSupported = false;
	try { eventsSupported = app.contextChangeEvents; } catch(e) { eventsSupported = false; }
	var s = "<string><root><eventsSupported>" + (eventsSupported ? "true" : "false") + "</eventsSupported></root></string>";
	return s;
}

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

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

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

var scriptAlert = function(msg)
{
	alert(msg);
}

var getDocumentList = function () {
	return ReviewPanelUtilities.callMainFunction(_getDocumentList);
}
// Parse the documents currently open
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 IL can open don't have a GUID, so we use the full path of the document instead
			activeId = active.fullName; 
		}
		list.@activeDocument = activeId;
		
		// now iterate the document list. No need to iterate the entire list as we are interested only in the active document
		/*
		for(var i=0; i<count; i++) {
			var doc = app.documents[i];
			var document = new XML("<document />");
			var docId = _getGuid(doc);
			if(docId == null)
				docId = doc.fullName;
			document.@id = docId;
			document.@name = doc.name;
			list.appendChild(document);
		}
		*/
		// Notice that for Illustrator 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();
}

var getActiveDocument = function ()
{
	var result = new XML('<string />');
	
	if (app.documents.length > 0)
	{
		var doc = app.activeDocument;
		var document = new XML("<document />");
		document.@name = doc.name;
		var guid = getGuid(doc);
		//alert(guid);
		if(guid != null) {
			document.@id = guid;
		}
		result.appendChild(document);
	}
	
	return result.toXMLString();
}


//********************************************************************************************
// 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.XMPString);
		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 rootVolume = arguments.@rootVolumeName.toString();
	var isSameApp = arguments.@sameApp.toString();
	if(path == "NA" || isSameApp == "false") {
		retval = "<error/>";	
		if(isSameApp == "true" && instanceId != null && instanceId != "" && makeDocumentActive(instanceId)){
			retval = "<success />";
        }
	}
	else 
	{
		// Saving the old userInteractionLevel
		var oldInteractionLevel = app.userInteractionLevel;
		try 
		{
			//  Setting the interaction level to DO NOT DISPLAY ALERTS.
			app.userInteractionLevel = UserInteractionLevel.DONTDISPLAYALERTS;
			// Path fix is not needed on Illustrator.
	        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);
	             }
	        }
	        app.userInteractionLevel = oldInteractionLevel;
	    }
	    catch (e) {
	    	app.userInteractionLevel = oldInteractionLevel;
	    	retval = "<error/>";
	    }
	}
	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 DONE
//
// scans the history of the document and returns all the previous ids
//********************************************************************************************
function getPreviousIds(doc) 
{
	var metadata =new XML(doc.XMPString);
	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]);
				try {
					var id = data.descendants('stEvt:instanceID')[0].toString();
					id = id.split(':').pop();
					ids.push(id);
				}
				catch (error) {
					
				}
	            count++;
			}
			loopcount++;
		}
	}
	return ids;
}

//********************************************************************************************
// isIdInHistory  DONE
//
// 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  DONE
//
// 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. DONE
//
// 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  DONE
//
// 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;
}


// 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
	{
		if(doc.path == "")
			return "false";
		else
			return "true";
	}
	catch (e)
	{
		return "false";
	}
	return "true";
}

//********************************************************************************************
// getDocumentInfo
//
// returns information about the active document
//********************************************************************************************

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

var _getDocumentInfo = function () {

	function getArtboardRangeString(docu) {
		var start = 1;
		var end = docu.artboards.length;
        if (start == end) {
            return start;
        } else {
            return start + '-' + end;
		}
	}
	var docInfo = new XML('<docInfo><resolution /><all /><active /><hasFilePath /><isDirty /></docInfo>');
	var doc = app.activeDocument;
	if(doc != null && doc != undefined) {
		docInfo.resolution.setChildren(doc.rasterEffectSettings.resolution);
		docInfo.all.@count = doc.artboards.length;
		docInfo.all.setChildren(getArtboardRangeString(doc));
		docInfo.active.setChildren(doc.artboards.getActiveArtboardIndex() + 1);
		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';
    
    // notice that AI does not allow us to show the save as dialog, so we ignore the argument for the time being
    
    app.activeDocument.save();
}

//-----------------------------------------------------------------------------
//
// Utilities
//
//-----------------------------------------------------------------------------

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

//********************************************************************************************
// ReviewPanelUtilities.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;
}

// getArtboards takes in the artboard range and 
// converts it into an array of artboard indices. The range string will be in the form of 1,3-5,8. This 
// method will  return [1,3,4,5,8]
function getArtboards(artboardRange){
	var rangeArray = artboardRange.split(',');
	var selArtArray=new Array();
	var selIndex = 0;
	try{
		for(var count = 0; count < rangeArray.length; count++)
		{
				var range = rangeArray[count].split('-');
				if(range.length == 1)
				{
					selArtArray[selIndex++] = parseInt(range[0])-1;
				}
				else if(range.length == 2)
				{
					var startIndex = parseInt(range[0]);
					var endIndex = parseInt(range[1]);
					if(startIndex <= endIndex)
					{
						for(var iCount = startIndex; iCount <= endIndex; iCount++)
						{
							selArtArray[selIndex++] = iCount-1;	
						}
					}
				}
		}
	}
	catch(e)
	{
		return null;
	}
	return selArtArray;
}

//********************************************************************************************
// selectFrame
//
// select the frame with the given id
//********************************************************************************************

var selectFrame = function(id)
{
	alert("selectFrame called");
}


//********************************************************************************************
// selectText
//
// select the text
//********************************************************************************************

var selectText = function(args)
{
	alert("selectText called!");
}



//********************************************************************************************
// setCommentData
//
// displays the comments in the document
//********************************************************************************************

var setCommentData = function(xmlString)
{
	if (app.documents.length == 0) return;
	var xmlData = new XML(xmlString);
	app.activeDocument.suspendHistory ("Update Comments", "rebuildCommentsUsingEPS(xmlData)");
}

var documentSliced = false;
//********************************************************************************************
// 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);
}

//********************************************************************************************
// _generateContentsFromDocument
//
// generates contents, structure and previews of the whole document. This will now be a two step process
// Step 1 - Synchronously generate the entire meta-data except the previews.
// Step 2 - Use BridgeTalk and start the process of generating previews. Return after sending
// the bridgeTalk request
//********************************************************************************************
var _generateContentsFromDocument = function(args) {
	// Throw an error if currJob is not 0
	if(currJob != 0) {
        throw new Error("Pending job. Can't run two jobs at once.");
    }
    // start new job
    currJob = nextJobNum;
    nextJobNum++;
    previousJobResult="";
    // save the previewDifferentiator value before generating contents
	var startIndex = previewDifferentiator;
	//var generator = new ContentsGenerator();
	var arguments = new XML(args);
	var previewFolder = ReviewPanelUtilities.fixPathIfNeeded(arguments.@previewFolder, 0);	
	var guid = _getGuid(app.activeDocument);
	documentSliced = false;
	documentSliced = isDocumentSliced (app.activeDocument);
	if(guid == null) {
		guid = arguments.@docId;
	}
	var result = generateContentData(app.activeDocument,  previewFolder, guid,
									parseInt(arguments.@previewWidth.toString()), 
									parseInt(arguments.@previewHeight.toString()),  
									arguments.@progressTitle,
									arguments.@pagesRange,
									arguments.@docId, currJob);
	if(result != null) {
		
		/*createPreviews(app.activeDocument, generator.guid, previewFolder, generator.selectedArtboards, startIndex, parseInt(arguments.@previewWidth.toString()), 
																	parseInt(arguments.@previewHeight.toString()), 
																	80, "all", 1,
																	"generating snapshots");*/
		// Now start bridgetalk
		var bt = new BridgeTalk;
		bt.target = BridgeTalk.appSpecifier; // target ourselves
		var str = createPreviewsScript + "createPreviews(app.activeDocument,  '" + guid + "', '" + previewFolder + "' , '" + arguments.@pagesRange + "' ," + startIndex +	" ," + parseInt(arguments.@previewWidth.toString()) + ", " + parseInt(arguments.@previewHeight.toString()) + ", " + parseInt(arguments.@quality.toString()) + ",  '" + arguments.@format.toString() + 	"', '" + arguments.@progressTitle.toString()  + "',  '" + arguments.@progressCancelLabel.toString()+ "', '"+documentSliced.toString()+"');";
		bt.body = str;
			
		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();																			
	}
	else {
		previousJob = currJob;
	    currJob = 0;
	    var result = "<![CDATA[<error>InvalidPageRange</error>]]>";
	    previousJobResult = result;
		throw "InvalidPageRange";
	}
	return result.toXMLString();
}


//********************************************************************************************
// generateContentsOfDocument
//
// main function of the contents generator. 
//********************************************************************************************

function generateContentData(doc, previewPath, guid, maxWidth, maxHeight, progressTitle, artboardRange, docId, jobId) {
	var result = '';
	
	//selectedArtboards records the index numbers of the artboards which are to be included in the review. 
	var selectedArtboards=new Array();
	// If the user hasn't specified the artboard range then include all artboards
	if(artboardRange == null || artboardRange == '')
	{
		for(var index = 0; index < doc.artboards.length; index++)
			selectedArtboards[index] = index;
	}
	else if (artboardRange == 'AllArtboardsAsOne') // Add all artboards in one file
		selectedArtboards = null;
	else // If range is specified, then get the range string validated
		selectedArtboards = getArtboards(artboardRange);
		
	// Fix for Bug # 2465522
	/*if(artboardRange != 'AllArtboardsAsOne' && selectedArtboards == null)
		return null; 
	*/		
	result = new XML('<result documentId="' + guid + '" jobId="' + jobId +'" />');
	
	generateData(doc, previewPath, maxWidth, maxHeight, guid, selectedArtboards, result);

	return result;
}

function generateData(doc, previewPath, maxWidth, maxHeight, guid, selectedArtboards, result){
	var contents = new XML('<contents />');
	var parts = new XML('<parts />');
	generatePartData(doc, contents, parts, selectedArtboards, guid, maxWidth, maxHeight);
	result.appendChild(contents);
    result.appendChild(parts);
	var previews = generatePreviewsData(doc, previewPath, maxWidth, maxHeight, selectedArtboards, guid);
    result.appendChild(previews);
    var metadata = generateMetadata(doc);
    if(metadata != null) {
        result.appendChild(metadata);
    }
}

//********************************************************************************************
// generateImagesData
//
// generates the images element of the contents
//********************************************************************************************

function generatePartData(doc, contents, parts, selArts, guid, maxWidth, maxHeight) {
	// If selArts is null, user wants to take all artboards in one file
	if(selArts == null)
		contents.appendChild(generateImageData(doc, parts, guid, -1, maxWidth, maxHeight));
	else {
	    for(var artCount = 0; artCount < selArts.length; artCount++)
	        contents.appendChild(generateImageData(doc, parts, guid, selArts[artCount], maxWidth, maxHeight));
	}    
}


//********************************************************************************************
// generateImageData
//
// generates a single image element
//********************************************************************************************
const DEFAULT_EXPORT_RESOLUTION = 72;
function generateImageData(doc, parts, guid, index, maxWidth, maxHeight) {
	var partData = new XML('<part type="image" />');
	partData.@documentId = guid;
	
	/* The data-type of width and height in Photoshop is UnitValue while it is double in Illustrator
	 	April 2 2009 - Also doc.height and doc.width return the default height and width values of the document
					  These are set to 792 and 612 by default. Using these values for calculation leads to a 
					  wrong value of the aspect ratio. Hence I am no more using doc.height and doc.width. Instead,
					  I will use doc.geometricBounds - Naren
	*/
	var width;
	var height;
	if(index == -1) { // index == -1 implies user wants to add all artboards in a single file
		partData.@id = guid;
		width = doc.geometricBounds[2] - doc.geometricBounds[0]; 
		height = doc.geometricBounds[1] - doc.geometricBounds[3];
	}
	else {
		partData.@id = guid + index;
		// Using the artboard coordinates
		var artboardRect = doc.artboards[index].artboardRect;
		
		width = artboardRect[2] - artboardRect[0];
		height = artboardRect[1] - artboardRect[3];
		partData.@artboardName = doc.artboards[index].name;
	}
	
	var scale = 1;
	if(maxWidth > 0 && maxHeight > 0) {
        var widthRatio = maxWidth / width;
        var heightRatio = maxHeight / height;
        scale = Math.min(widthRatio, heightRatio);
    	// Illustrator enforces a limit. Cannot export a document as png/jpg with
    	// scale factor greater than 7.76    
        if(scale > 7.76)
        	scale = 7.76;
        
        // If the document is sliced, we use the javascript API doc.imageCapture. The valid
        // resolution range is [72....2400]. Therefore restrict the scaling to 1.
        if (documentSliced) {
        	scale = Math.max (1, scale);
        }
    }
    var docResolution = doc.rasterEffectSettings.resolution;
	// Bug # 2584196 - Jump To does not function correctly with uploads from Illustrator.
    // Store the original width and height in pixels instead of points. This is based on the 'Raster Resolution' value
    // associated with the document (It is 300 ppi for Print and 72 ppi for Web)    
	partData.@originalWidth = width * (docResolution / DEFAULT_EXPORT_RESOLUTION);
	partData.@originalHeight = height * (docResolution / DEFAULT_EXPORT_RESOLUTION);
	partData.@previewWidth = width * scale;
	partData.@previewHeight = height * scale;
	
	var imageData = new XML('<image />');
	if(index == -1)
		imageData.@id = guid;
	else
		imageData.@id = guid+index;
	
	// Original resolution equals the 'Raster Resolution' value associated with the document. We use this to decide
	// the intent of the document
	imageData.@originalResolution = docResolution;
	
	var colorMode=doc.documentColorSpace;
	switch(colorMode) {
		case DocumentColorSpace.RGB:
			imageData.@colorMode = "RGB";
		break;
		case DocumentColorSpace.CMYK:
			imageData.@colorMode = "CMYK";
		break;
		default: 
			imageData.@colorMode = "unknown";
		break;
	}

	parts.appendChild(imageData);
	return partData;
}

function isDocumentSliced(doc) {
	try {
		var items = doc.pageItems;
		var item = items.getByName ("<Slice>");
		if (item.sliced)
			return true;
	}
	catch (e) {
		return false;
	}
	return false;
}
function generatePreviewsData(doc, previewPath, maxWidth, maxHeight, selArts, guid) {
	(new Folder(previewPath)).create();
	var previewData = new XML('<previews />');
	var name = guid.substr(0, 7);
    var filePath = previewPath + "/preview_" + name;
    
    if(selArts == null) {
    	previewData.appendChild(new XML('<preview partId="' +  guid + '">' + filePath + '</preview>'));
    }
    else { 
	    for(var loopCount = 0; loopCount < selArts.length; loopCount++)
	    {
	        var index = selArts[loopCount];	
	     	var fullFilePath = filePath + previewDifferentiator;
	        previewDifferentiator ++;
	        previewData.appendChild(new XML('<preview partId="' +  guid+index+ '">' + fullFilePath + '</preview>'));
	    }
  	}
	return previewData;
}
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;
}

var createPreviewsScript = "\
function createPreviews(doc, guid, previewFolder, artboardRange, startIndex, maxWidth, maxHeight, quality, format, progressTitle, cancelLabel, documentSliced) {\
	var MAX_BEST_PNG_SIZE = 1024 * 1024;\
	var result = '<success />'\
    var pbar = createProgressBar(progressTitle, cancelLabel);\
    try {\
    	var selectedArtboards;\
    	if(artboardRange == null || artboardRange == '')\
		{\
			selectedArtboards = new Array();\
			for(var index = 0; index < doc.artboards.length; index++)\
			{\
					selectedArtboards[index] = index;\
			}\
		}\
		else if (artboardRange == 'AllArtboardsAsOne')\
		{\
			selectedArtboards = null;\
		}\
		else // If range is specified, then get the range string validated\
		{\
			selectedArtboards = getArtboardsArray(artboardRange);\
		}\
		\
        var progressBarIncrements = 10;\
        var currProgress = 5;\
        pbar.updateProgress(currProgress);\
        if(selectedArtboards != null && selectedArtboards.length > 0){\
        	var totalPreviews = format == 'all'?selectedArtboards.length*2:selectedArtboards.length;\
        	progressBarIncrements = 100/totalPreviews;\
        	var halfOfProgressBarIncrements = progressBarIncrements/2;\
        	for(var loopCount = 0; loopCount < selectedArtboards.length; loopCount++)\
	    	{\
	        	var index = selectedArtboards[loopCount];	\
	    		var scale = 1;\
	    		var resolution = 72;\
	        	if(maxWidth > 0 && maxHeight > 0) {\
		            var artboardRect = doc.artboards[index].artboardRect;\
		            var docWidth = artboardRect[2] - artboardRect[0];\
		            var docHeight = artboardRect[1] - artboardRect[3];\
	                var widthRatio = maxWidth / docWidth;\
	                var heightRatio = maxHeight / docHeight;\
	                scale = Math.min(widthRatio, heightRatio);\
		            if(scale > 7.76)\
		            	scale = 7.76;\
		            if (scale > 1)\
		            	resolution = 72 * scale;\
		        }\
	        	// form the file path\
	        	var name = guid.substr(0, 7) + startIndex;\
	        	startIndex ++;\
	        	\
	        	if (documentSliced == 'true') {\
	        		var fullFilePath = previewFolder + '/preview_' + name + '.png';\
	        		capturePreviewUsingImageCapture(doc, fullFilePath, index, resolution);\
	        		var pngFile = File (fullFilePath);\
	        		if(pngFile.exists && pngFile.length > MAX_BEST_PNG_SIZE){\
	        			var jpgFilePath = previewFolder + '/preview_' + name + '.jpg';\
	        			pngFile.copy(jpgFilePath);\
	        		}\
	        		currProgress += progressBarIncrements;\
		        	if(currProgress > 100)\
		        		currProgress = 99;\
		        	\
	        	}\
	        	else if(format == 'png' || format == 'all') {\
	        		var fullFilePath = previewFolder + '/preview_' + name + '.png';\
	        		createPreviewPNG(doc, fullFilePath, quality, scale, index);\
	        		var pngFile = File (fullFilePath);\
	        		currProgress += halfOfProgressBarIncrements;\
	        		if(currProgress > 100)\
		        		currProgress = 99;\
		        	pbar.updateProgress(currProgress);\
	        		if(pngFile.exists && pngFile.length > MAX_BEST_PNG_SIZE && format != 'all') {\
	        			var jpgFilePath = previewFolder + '/preview_' + name + '.jpg';\
	        			createPreviewJPEG(doc, jpgFilePath, quality, scale, index);\
	        		}\
	        		currProgress += halfOfProgressBarIncrements;\
		        	if(currProgress > 100)\
		        		currProgress = 99;\
		        	pbar.updateProgress(currProgress);\
	        	}\
	        	else if(format == 'jpg' || format == 'all') {\
	        		var fullFilePath = previewFolder + '/preview_' + name + '.jpg';\
	        		createPreviewJPEG(doc, fullFilePath, quality, scale, index);\
	        		currProgress += progressBarIncrements;\
		        	if(currProgress > 100)\
		        		currProgress = 99;\
		        	\
 					pbar.updateProgress(currProgress);\
	        	}\
	        }\
        }\
        else {\
        	var scale = 1;\
        	var resolution = 72;\
	    	if(maxWidth > 0 && maxHeight > 0) {\
	    		var docWidth = doc.geometricBounds[2] - doc.geometricBounds[0]; \
		    	var docHeight = doc.geometricBounds[1] - doc.geometricBounds[3];\
                var widthRatio = maxWidth / docWidth;\
                var heightRatio = maxHeight / docHeight;\
                scale = Math.min(widthRatio, heightRatio);\
	            if(scale > 7.76)\
	            	scale = 7.76;\
            	if (scale > 1)\
	            	resolution = 72 * scale;\
	    	}\
        	var name = guid.substr(0, 7);\
        	if (documentSliced == 'true') {\
        		var fullFilePath = previewFolder + '/preview_' + name + '.png';\
        		capturePreviewUsingImageCapture(doc, fullFilePath, -1, resolution);\
        		var pngFile = File (fullFilePath);\
        		if(pngFile.exists && pngFile.length > MAX_BEST_PNG_SIZE){\
        			var jpgFilePath = previewFolder + '/preview_' + name + '.jpg';\
        			pngFile.copy(jpgFilePath);\
        		}\
        		currProgress += progressBarIncrements;\
	        	if(currProgress > 100)\
	        		currProgress = 99;\
	        	\
        	}\
        	else if(format == 'png' || format == 'all') {\
        		var fullFilePath = previewFolder + '/preview_' + name + '.png';\
        		createPreviewPNG(doc, fullFilePath, quality, scale, -1);\
        		var pngFile = File (fullFilePath);\
        		pbar.updateProgress(50);\
        		if(pngFile.exists && pngFile.length > MAX_BEST_PNG_SIZE && format != 'all') {\
        			var jpgFilePath = previewFolder + '/preview_' + name + '.jpg';\
        			createPreviewJPEG(doc, jpgFilePath, quality, scale, -1);\
        		}\
        	}\
        	else if(format == 'jpg' || format == 'all') {\
        		var fullFilePath = previewFolder + '/preview_' + name + '.jpg';\
        		createPreviewJPEG(doc, fullFilePath, quality, scale, -1);\
        	}\
        }\
        pbar.updateProgress(100);\
    } catch (x) {\
        if(canceled) {\
            result = '<canceled />';\
        } else {\
            result = '<error><![CDATA[' + x +  ']]></error>';\
        }\
    } finally {\
        pbar.close();\
    }\
    return result;\
}\
\
\
createPreviewJPEG = function(doc, fullFilePath, quality, scale, index) {\
		var exportOptions = new ExportOptionsJPEG();\
		var type = ExportType.JPEG;\
		// Create a new file at the destination\
		var fileSpec = new File(fullFilePath);\
		exportOptions.antiAliasing = true;\
		if(index == -1) {\
			exportOptions.artBoardClipping = false;\
		}\
		else {\
			exportOptions.artBoardClipping = true;\
			doc.artboards.setActiveArtboardIndex(index);\
		}\
		exportOptions.blurAmount=0.0;\
		exportOptions.horizontalScale = scale * 100;\
		exportOptions.verticalScale = scale * 100;\
		exportOptions.matte = false;\
		\
		var newRGBColor = new RGBColor();\
		newRGBColor.red = 255;\
		newRGBColor.green = 255;\
		newRGBColor.blue = 255;\
		exportOptions.matteColor = newRGBColor;\
		exportOptions.optimization = true;\
		exportOptions.qualitySetting = quality;\
		exportOptions.saveAsHTML = false;\
		doc.exportFile( fileSpec, type, exportOptions );\
		// verify that the export File did not fail by checking if the preview file exists\
		if (!fileSpec.exists) {\
			if(index != -1 && !doc.saved){\
				app.undo();\
			}\
			canceled = true;\
			throw new Error('canceled');\
		}\
		// undoing the changes \
		if(!doc.saved){\
			app.undo();\
		}\
		if(index != -1 && !doc.saved){\
			app.undo();\
		}\
}\
\
createPreviewPNG = function(doc, fullFilePath, quality, scale, index) {\
		var exportOptions = new ExportOptionsPNG24();\
		var type = ExportType.PNG24;\
		// Create a new file at the destination\
		var fileSpec = new File(fullFilePath);\
		exportOptions.antiAliasing = true;\
		if(index == -1) {\
			exportOptions.artBoardClipping = false;\
		}\
		else {\
			exportOptions.artBoardClipping = true;\
			doc.artboards.setActiveArtboardIndex(index);\
		}\
		exportOptions.horizontalScale = scale * 100;\
		exportOptions.verticalScale = scale * 100;\
		exportOptions.matte = true;\
		\
		var newRGBColor = new RGBColor();\
		newRGBColor.red = 255;\
		newRGBColor.green = 255;\
		newRGBColor.blue = 255;\
		exportOptions.matteColor = newRGBColor;\
		exportOptions.transparency = false;\
		exportOptions.saveAsHTML = false;\
		doc.exportFile( fileSpec, type, exportOptions );\
		// verify that the export File did not fail by checking if the preview file exists\
		if (!fileSpec.exists) {\
			if(index != -1 && !doc.saved){\
				app.undo();\
			}\
			canceled = true;\
			throw new Error('canceled');\
		}\
		// undoing the changes \
		if(!doc.saved){\
			app.undo();\
		}\
		if(index != -1 && !doc.saved){\
			app.undo();\
		}\
\
}\
capturePreviewUsingImageCapture = function(doc, fullFilePath, index, resolution) {\
		var captureOptions = new ImageCaptureOptions();\
		// Create a new file at the destination\
		var fileSpec = new File(fullFilePath);\
		captureOptions.antiAliasing = true;\
		if(index >= 0) {\
			doc.artboards.setActiveArtboardIndex(index);\
		}\
		captureOptions.matte = true;\
		\
		var newRGBColor = new RGBColor();\
		newRGBColor.red = 255;\
		newRGBColor.green = 255;\
		newRGBColor.blue = 255;\
		captureOptions.matteColor = newRGBColor;\
		captureOptions.transparency = false;\
		captureOptions.resolution = resolution;\
		if (index >= 0)\
			doc.imageCapture(fileSpec, doc.artboards[index].artboardRect, captureOptions);\
		else\
			doc.imageCapture(fileSpec, doc.geometricBounds, captureOptions);\
		// verify that the export File did not fail by checking if the preview file exists\
		if (!fileSpec.exists) {\
			if(index != -1 && !doc.saved){\
				app.undo();\
			}\
			canceled = true;\
			throw new Error('canceled');\
		}\
		if(index >= 0 && !doc.saved){\
			app.undo();\
		}\
\
}\
var canceled = false;\
\
function createProgressBar(title, cancelLabel) {\
    var win = new Window('palette {properties:{closeButton:false}}', title);\
    canceled = false;\
    win.bar = win.add('progressbar', undefined, 0, 100);\
    win.bar.preferredSize = [300, 20];\
    win.message = win.add('statictext');\
    win.message.preferredSize.width = 300;\
    win.updateProgress = function(val) {\
        if(canceled) {\
            throw new Error('canceled');\
        }\
        var win = this;\
        win.bar.value = val;\
        win.show();\
    }\
    return win;\
}\
function getArtboardsArray(artboardRange){\
	var rangeArray = artboardRange.split(',');\
	var selArtArray=new Array();\
	var selIndex = 0;\
	try{\
		for(var count = 0; count < rangeArray.length; count++)\
		{\
				var range = rangeArray[count].split('-');\
				if(range.length == 1)\
				{\
					selArtArray[selIndex++] = range[0]-1;\
				}\
				else if(range.length == 2)\
				{\
					var startIndex = parseInt(range[0]);\
					var endIndex = parseInt(range[1]);\
					if(startIndex <= endIndex)\
					{\
						for(var iCount = startIndex; iCount <= endIndex; iCount++)\
						{\
							selArtArray[selIndex++] = iCount-1;	\
						}\
					}\
				}\
		}\
	}\
	catch(e)\
	{\
		//alert(e);\
		return null;\
	}\
	return selArtArray;\
}\
\
";


var validateArtboardRangeString = function (args) {
	return ReviewPanelUtilities.callMainFunction(_validateArtboardRangeString, args);
}
// validateArtboardRangeString takes in the artboard range and validates it 
function _validateArtboardRangeString(args){
		var arguments = new XML(args);
		var artboardRange = arguments.@artboardRange;
		var invalidRangeComment = arguments.@invalidRange;
		var rangeArray = artboardRange.split(",");
		var selArtArray=new Array();
		var selIndex = 0;
		try{
			for(var count = 0; count < rangeArray.length; count++)
			{
				var range = rangeArray[count].split("-");		
				if(!validEntry(range))
				{
						throw "InvalidArtboardRange";
				}
			}
		}
		catch(e)
		{
			throw "InvalidArtboardRange";
		}
		return "<success />";
	}
function validEntry(rangeArray)
{
	// A range may be a single number or a range i.e. "1" or "1-5". The elements of the range are passed in an
	// array to this function. 
	
	// FIRST TEST
	// The length of the array should be either 1 or 2.
	if(rangeArray == null || rangeArray.length > 2 || rangeArray.length <= 0)
		return false;
		
	// SECOND TEST
	// The value of the first element should-
	// 1) be a digit	
	// 2) not be less than 0
	// 3) not be greater than the number of artboards in the document
	else if(!regIsDigit(rangeArray[0]) || parseInt(rangeArray[0]) <= 0 || parseInt(rangeArray[0]) > app.activeDocument.artboards.length)
		return false;
		
	// THIRD TEST
	// If there is a second element, its value should-
	// 1) be a digit
	// 2) not be greater than the number of artboards in the document
	// 3) not be less than or equal to the first value
	else if(rangeArray.length == 2 && (!regIsDigit(rangeArray[1]) || (parseInt(rangeArray[1]) > app.activeDocument.artboards.length) || (parseInt(rangeArray[0]) >= parseInt(rangeArray[1]))))
		return false;
		
	return true;
}
function regIsDigit(fData)
{
     var reg = new RegExp("^[0-9]+$");
     return (reg.test(fData));
}

/*
var contentFile = new File('/Users/nachaina/Desktop/contentTestID.xml')
function writeToFile(data) {
	if(contentFile.open('w')) {
		contentFile.encoding = 'UTF-8';
		contentFile.write(data);
		contentFile.close();
	}
}*/


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

function openPProProjectSequence(path, sequenceId) {
	ppro = new BridgeTalk();
	ppro.target = "premierepro-5.0";
	ppro.body =
		"var myFile = File('" + path + "');" +
		"if (myFile.exists) {" +
		"	if (app.project.path != '" + path + "')" +
		"		app.openDocument('" + path + "');" +
		"	app.project.openSequence('" + sequenceId + "');" +
        "}";
	ppro.send();
}

