/**
 * @author $Author: rhorns $
 * @date $DateTime: 2009/03/06 11:12:40 $
 * @version	$Revision: #2 $
 * 
 * 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"

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

function ReviewPanelUtilities() {
}

ReviewPanelUtilities.convertErrorMessage = function(errorMessage) {
    var pagesRangeErrorPattern = /([\D]*)pagesrange([\D]*)generateDocContent|([\D]*)generateDocContent([\D]*)pagesrange/;
    if(pagesRangeErrorPattern.test(errorMessage)) {
         // the end of this error message has varying content which makes it impossible to use it as a localization key
         // we simply return a shortened version of it
         return "InvalidPageRange"; 
    }
    return errorMessage;
}

// 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>" + ReviewPanelUtilities.convertErrorMessage(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
//
// This is Mac specific. Extendscript has a limitation where, if the name of the local directory
// under the root volume is the same as one of the mounted volumes, then there is no way to 
// uniquely specify the path to a file inside the local directory.
//
// i.e. Assume there is local directory called Transfer under the root volume and it contains
// a file named Illustrator.jsx. Also, there is mounted volume called Transfer. Due to the limitation
// there is no way to create a File object which points to /Transfer/Illustrator.jsx under the
// root volume. ExtendScript always gives priority to the mounted volume if there is a name clash
// and will try to find the file Illustrator.jsx under the mounted volume 'Transfer'.
//
// The fix here is to catch such cases and change the file name such that ExtendScript points 
// to the file on the local file system.
//
// We catch such cases by looking for the file path in the extendScript File object and the file
// path we got from ActionScript.
//
// eg. filePath from AS = file:///Transfer/Illustrator.jsx and
//	   filePath in ES = /Volumes/Transfer/Illustrator.jsx
//
// Here we can see that the filePath in ES was wrongly redirected to the remote file system. The
// way we fix this is by inserting the name of the root volume in between. So if the name
// of the root volume is MacintoshHD, then the returned path will be
// /Volumes/MacintoshHD/Transfer/Illustrator.jsx
//
// It is also possible that user actually referred to the file on the mounted file system. In those cases,
// the file url from ActionScript should be file:///Volumes/... We detect this in the second if loop,
// and prevent any changes to the filePath in ES in such cases.
//
// This shouldn't be a problem on Windows as each remote volume is identified by a separate alphabet.
//********************************************************************************************

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

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

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

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



//********************************************************************************************
// getDocumentList
//
// returns an XML snippet that contains information on the open documents
//********************************************************************************************

var getDocumentList = function () {
	return ReviewPanelUtilities.callMainFunction(_getDocumentList);
}

var _getDocumentList = function () {
	return app.getDocumentsIds();
}

// 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 () {
     function getPageName(page) {
         return page.appliedSection.includeSectionPrefix ? page.name : (page.appliedSection.sectionPrefix + page.name);
     }
 
    function getPageRangeString(start, end) {
        if (start == end) {
            return getPageName(start);
        } else {
            return getPageName(start) + '-' + getPageName(end);
        }
     }
 
	var docInfo = new XML('<docInfo><intent /><all /><active count="0"/><hasFilePath /><isDirty /></docInfo>');
    var doc = app.activeDocument;
	if(doc != null && doc != undefined) {
        docInfo.intent.setChildren(doc.documentPreferences.intent == DocumentIntentOptions.WEB_INTENT ? "web" : "print" );
        docInfo.all.@count = doc.pages.length;
        docInfo.all.setChildren(getPageRangeString(doc.pages.firstItem(), doc.pages.lastItem()));
        if(doc.layoutWindows.length > 0) {
            var activeSpread = app.activeDocument.layoutWindows[0].activeSpread;
            if(!(activeSpread instanceof MasterSpread)) {
                docInfo.active.@count = activeSpread.pages.length;
               docInfo.active.setChildren(getPageRangeString(activeSpread.pages.firstItem(), activeSpread.pages.lastItem()));
           }
		}
		docInfo.hasFilePath.setChildren(_isDocumentSaved(doc));
		docInfo.isDirty.setChildren(doc.modified ? 'true' : 'false');
	}
	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) {
        // we have to invoke the Save As menu action
        const saveAsKey = '$ID/Save &As...';
        var localizedActionName = app.translateKeyString(saveAsKey);
        var action = app.menuActions.itemByName(localizedActionName);
        action.invoke();
    } else {
        // we can simply call save
        app.activeDocument.save();
     }
}

//********************************************************************************************
// jumpToComment
//
// brings the document to front, goes to the spread and centers the comment in the window
//********************************************************************************************

var jumpToComment = function (args) {
	return ReviewPanelUtilities.callMainFunction(_jumpToComment, args);
}

var _jumpToComment = function (args) {
	var arguments = new XML(args);
	app.jumpToComment(arguments.@documentId.toString(), arguments.@comment.toString());
	return "<success />";
}

//********************************************************************************************
// 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();
	// Check if the path is NA - this means the user had not saved the document before adding this part
	// OR the part was created from some other app.
	if(path == "NA" || isSameApp == "false") 
	{
		retval = "<error/>";	
		// TO DO
		// Additional parameter sameApp is present in arguments
		// If set to true, scan through the set of documents currently open and see if the latest instance id matches with the id passed.
		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 openDoc = app.open (myFile, false);
			var list = getPreviousIds(openDoc);
			if(isIdInHistory(list, instanceId))
			{
				if(myFile.exists)
					myFile.execute();
			}
			else
			{
				retval = "<error/>";
			}
	}
	return retval;
}

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 doc = app.open (myFile, false);
    var instanceId = doc.metadataPreferences.getProperty('http://ns.adobe.com/xap/1.0/mm/', 'InstanceID');
    instanceId = instanceId.split(':').pop();
    var original = new XML('<instance id="'+instanceId+'"/>');
    retval.appendChild(original);
	return retval;
}

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 {
        // try to open the file using the url
        retval = "<error/>";
    }
	return retval;
}

function getPreviousIds(doc) {
	var oldIds = [];
	if(doc != null) {
		// Adding the instance id
		var historyCount = doc.metadataPreferences.countContainer('http://ns.adobe.com/xap/1.0/mm/', 'History');
		for( var loop = 1; loop <= historyCount; loop++) {
				var oldId = doc.metadataPreferences.getProperty('http://ns.adobe.com/xap/1.0/mm/', 'History/['+loop+']/stEvt:instanceID').split(':').pop();
				oldIds.push(oldId);
		}
	}
	return oldIds;
}

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

function makeDocumentActive(instanceId) {
	var documents = app.documents;
	for(var i = 0; i < documents.length; i++) {
		var doc = documents.item(i);
		var curId = doc.metadataPreferences.getProperty('http://ns.adobe.com/xap/1.0/mm/', 'InstanceID');
		if(curId != null)
			curId = curId.split(':').pop();
		if(curId != null && instanceId == curId)
		{
			app.activeDocument = doc;
			return true;
		}		
	}
	return false;
}

//********************************************************************************************
// cancelTask
//
// cancels the task identified by taskId
//********************************************************************************************

var cancelTask = function(args) {
	return ReviewPanelUtilities.callMainFunction(_cancelTask, args);
}

var _cancelTask = function(args) {
	var arguments = new XML(args);
    var taskId = parseInt(arguments.@taskId.toString());
    var task = app.backgroundTasks.itemByID(taskId);
    task.cancelTask();
    return "<success />";
}

//********************************************************************************************
// generateContentsFromDocument
//
// generates contents, structure and previews of the whole document
//********************************************************************************************

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

var _generateContentsFromDocument = function(args) {
	var generator = new ContentsGenerator();
	var arguments = new XML(args);
	var result = generator.generateContentsOfDocument(app.activeDocument,  
                                                                                 ReviewPanelUtilities.fixPathIfNeeded(arguments.@previewFolder.toString(), 0), 
																		parseInt(arguments.@jobId.toString()), 
																		arguments.@taskTitle.toString(), 
																		arguments.@reviewTitle.toString(), 
																		parseInt(arguments.@previewWidth.toString()), 
																		parseInt(arguments.@previewHeight.toString()), 
																		arguments.@quality.toString(), 
																		arguments.@format.toString(), 
																		arguments.@overprintPreview.toString() == "true", 
																		(arguments.attribute("pagesRange") == null) ? null : arguments.@pagesRange.toString());
	return "" + result + "";
}

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

var setCommentData = function(xmlString) {
	return ReviewPanelUtilities.callMainFunction(_setCommentData, xmlString);
}

var _setCommentData = function(xmlString) {
	if (app.activeDocument) {
		app.activeDocument.switchbackCommentData = xmlString;
	}
	return "<success />";
}

//********************************************************************************************
// ContentsGenerator
//
// Generates the contents.xml file for a document
//********************************************************************************************

function ContentsGenerator() {
}

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

ContentsGenerator.prototype.generateContentsOfDocument = function(doc, previewPath, jobId, taskTitle, reviewTitle, previewWidth, previewHeight, quality, format, overprintPreview, pagesRange) {
    var result = doc.generateDocContent(taskTitle, reviewTitle, jobId, previewPath, previewWidth, previewHeight, format, quality, overprintPreview, pagesRange);

	// Append the file-path and original document id to result
	result = this.appendMetadata(result, doc);

	// Hack until InDesign supports asynchronous content generation and jobId is part of result.
	var jobId = new XML('<job id="87" />');
	result.appendChild (jobId);
    
	return result;
}

ContentsGenerator.prototype.appendMetadata = function(data, doc) {
    var result = new XML(data);
    var metadata = new XML('<metadata />');
    try {
	    var instanceId = doc.metadataPreferences.getProperty('http://ns.adobe.com/xap/1.0/mm/', 'InstanceID');
	    if(instanceId != null && instanceId.length > 0)
	        instanceId = instanceId.split(':').pop();
	    var instanceDetails = new XML('<instanceIdAtReview id="'+instanceId+'"/>');
	    
	    var filePath = "NA";
	    if(doc.saved)
	    {
	    	//1.0 Bug 2530112: We need to specify encoding for the file name.
	    	doc.fullName.encoding = "UTF-8";
	        filePath = doc.fullName.fsName;
	        filePath = escapeFilePath(filePath);
	    }
	    var path = new XML('<filePath path="'+filePath+'"/>');
	
	    metadata.appendChild (instanceDetails);
	    metadata.appendChild (path);
	    
	    result.appendChild (metadata);
    }
    catch (e) {
    	return result;
    }
	return result;
}


// debug
//setCommentData ('<comment_data>\\n  <display_comments>0</display_comments>\\n  <comments/>\\n</comment_data>');
//generateContentsFromDocument('<args previewFolder="file:///Users/kirkmattson/Desktop/" previewWidth="800" previewHeight="800" progressTitle="progress" docId="foo" />')
/*
var contentFile = new File('/Users/rhorns/Desktop/test/contentTestID.xml')
if(contentFile.open('w')) {
	contentFile.encoding = 'UTF-8';
	contentFile.write(generateContentsFromDocument('<args previewFolder="/Users/rhorns/Desktop/test" quality="medium" format="all" overprintPreview="false" previewWidth="1800" previewHeight="1800" progressTitle="progress" docId="foo" />'));
	contentFile.close();
}
*/


