/**************************************************************************************************

*

* ADOBE SYSTEMS INCORPORATED

* Copyright 2013 Adobe Systems Incorporated

* All Rights Reserved.

*

* NOTICE:  Adobe permits you to use, modify, and distribute this file in accordance with the

* terms of the Adobe license agreement accompanying it.  If you have received this file from a

* source other than Adobe, then your use, modification, or distribution of it requires the prior

* written permission of Adobe.

*

**************************************************************************************************/



/** Vulcan - v5.0.0 */



/**

 * @class Vulcan

 *

 * The singleton instance, <tt>VulcanInterface</tt>, provides an interface

 * to the Vulcan. Allows you to launch CC applications

 * and discover information about them.

 */

function Vulcan()

{

};



/**

 * Gets all available application specifiers on the local machine.

 *

 * @return The array of all available application specifiers.

 */

Vulcan.prototype.getTargetSpecifiers = function()

{	

	var params = {};

	return JSON.parse(window.__adobe_cep__.invokeSync("vulcanGetTargetSpecifiers", JSON.stringify(params)));

};



/**

 * Launches a CC application on the local machine, if it is not already running.

 *

 * @param targetSpecifier The application specifier; for example "indesign".

 *

 *        Note: In Windows 7 64-bit or Windows 8 64-bit system, some target applications (like Photoshop and Illustrator) have both 32-bit version

 *        and 64-bit version. Therefore, we need to specify the version by this parameter with "photoshop-70.032" or "photoshop-70.064". If you

 *        installed Photoshop 32-bit and 64-bit on one Windows 64-bit system and invoke this interface with parameter "photoshop-70.032", you may

 *        receive wrong result.

 *        The specifiers for Illustrator is "illustrator-17.032", "illustrator-17.064", "illustrator-17" and "illustrator".

 *

 *        In other platforms there is no such issue, so we can use "photoshop" or "photoshop-70" as specifier.

 * @param focus           True to launch in foreground, or false to launch in the background.

 * @param cmdLine         Optional, command-line parameters to supply to the launch command.

 * @return True if the app can be launched, false otherwise.

 */

Vulcan.prototype.launchApp = function(targetSpecifier, focus, cmdLine)

{

    if(!requiredParamsValid(targetSpecifier) )

    {

        return false;

    }

	

	var params = {};

	params.targetSpecifier = targetSpecifier;

	params.focus = focus ? "true" : "false";

	params.cmdLine = (cmdLine == undefined || cmdLine == null) ? "" : cmdLine;

	

	return JSON.parse(window.__adobe_cep__.invokeSync("vulcanLaunchApp", JSON.stringify(params))).result;

};



/**

 * Checks whether a CC application is running on the local machine.

 *

 * @param targetSpecifier The application specifier; for example "indesign".

 *

 *        Note: In Windows 7 64-bit or Windows 8 64-bit system, some target applications (like Photoshop and Illustrator) have both 32-bit version

 *        and 64-bit version. Therefore, we need to specify the version by this parameter with "photoshop-70.032" or "photoshop-70.064". If you

 *        installed Photoshop 32-bit and 64-bit on one Windows 64-bit system and invoke this interface with parameter "photoshop-70.032", you may

 *        receive wrong result.

 *        The specifiers for Illustrator is "illustrator-17.032", "illustrator-17.064", "illustrator-17" and "illustrator".

 *

 *        In other platforms there is no such issue, so we can use "photoshop" or "photoshop-70" as specifier.

 * @return True if the app is running, false otherwise.

 */

Vulcan.prototype.isAppRunning = function(targetSpecifier)

{

    if(!requiredParamsValid(targetSpecifier) )

    {

        return false;

    }

	

	var params = {};

	params.targetSpecifier = targetSpecifier;

	

	return JSON.parse(window.__adobe_cep__.invokeSync("vulcanIsAppRunning", JSON.stringify(params))).result;

};



/**

 * Checks whether a CC application is installed on the local machine.

 *

 * @param targetSpecifier The application specifier; for example "indesign".

 *

 *        Note: In Windows 7 64-bit or Windows 8 64-bit system, some target applications (like Photoshop and Illustrator) have both 32-bit version

 *        and 64-bit version. Therefore, we need to specify the version by this parameter with "photoshop-70.032" or "photoshop-70.064". If you

 *        installed Photoshop 32-bit and 64-bit on one Windows 64-bit system and invoke this interface with parameter "photoshop-70.032", you may

 *        receive wrong result.

 *        The specifiers for Illustrator is "illustrator-17.032", "illustrator-17.064", "illustrator-17" and "illustrator".

 *

 *        In other platforms there is no such issue, so we can use "photoshop" or "photoshop-70" as specifier.

 * @return True if the app is installed, false otherwise.

 */

Vulcan.prototype.isAppInstalled = function(targetSpecifier)

{

    if(!requiredParamsValid(targetSpecifier) )

    {

        return false;

    }

	

	var params = {};

	params.targetSpecifier = targetSpecifier;

	

	return JSON.parse(window.__adobe_cep__.invokeSync("vulcanIsAppInstalled", JSON.stringify(params))).result;

};



/**

 * Retrieves the local install path of a CC application.

 *

 * @param targetSpecifier The application specifier; for example "indesign".

 *

 *        Note: In Windows 7 64-bit or Windows 8 64-bit system, some target applications (like Photoshop and Illustrator) have both 32-bit version

 *        and 64-bit version. Therefore, we need to specify the version by this parameter with "photoshop-70.032" or "photoshop-70.064". If you

 *        installed Photoshop 32-bit and 64-bit on one Windows 64-bit system and invoke this interface with parameter "photoshop-70.032", you may

 *        receive wrong result.

 *        The specifiers for Illustrator is "illustrator-17.032", "illustrator-17.064", "illustrator-17" and "illustrator".

 *

 *        In other platforms there is no such issue, so we can use "photoshop" or "photoshop-70" as specifier.

 * @return The path string if the application is found, "" otherwise.

 */

Vulcan.prototype.getAppPath = function(targetSpecifier)

{

    if(!requiredParamsValid(targetSpecifier) )

    {

        return "";

    }

	

	var params = {};

	params.targetSpecifier = targetSpecifier;

	

	return JSON.parse(window.__adobe_cep__.invokeSync("vulcanGetAppPath", JSON.stringify(params))).result;

};



/**

 * Registers a message listener callback function for a Vulcan message.

 *

 * @param type            The message type.

 * @param callback        The callback function that handles the message.

 *            Takes one argument, the message object.

 * @param obj             Optional, the object containing the callback method, if any.

 *            Default is null.

 */

Vulcan.prototype.addMessageListener = function(type, callback, obj)

{

    if(!requiredParamsValid(type, callback) || !strStartsWith(type, VulcanMessage.TYPE_PREFIX))

    {

        return;

    }



	var params = {};

	params.type = type;

	

	window.__adobe_cep__.invokeAsync("vulcanAddMessageListener", JSON.stringify(params), callback, obj);

};



/**

 * Removes a registered message listener callback function for a Vulcan message.

 *

 * @param type            The message type.

 * @param callback        The callback function that was registered.

 *            Takes one argument, the message object.

 * @param obj             Optional, the object containing the callback method, if any.

 *            Default is null.

 */

Vulcan.prototype.removeMessageListener = function(type, callback, obj)

{

    if(!requiredParamsValid(type, callback) || !strStartsWith(type, VulcanMessage.TYPE_PREFIX))

    {

        return;

    }

	

    var params = {};

    params.type = type;

	

    window.__adobe_cep__.invokeAsync("vulcanRemoveMessageListener", JSON.stringify(params), callback, obj);

};



/**

 * Dispatches a Vulcan message.

 *

 * @param vulcanMessage   The message object.

 */

Vulcan.prototype.dispatchMessage = function(vulcanMessage)

{

    if(!requiredParamsValid(vulcanMessage) || !strStartsWith(vulcanMessage.type, VulcanMessage.TYPE_PREFIX))

    {

        return;

    }



	var params = {};

	var message = new VulcanMessage(vulcanMessage.type);

	message.initialize(vulcanMessage);

	params.vulcanMessage = message;

	

	window.__adobe_cep__.invokeSync("vulcanDispatchMessage", JSON.stringify(params));

};



/**

 * Retrieves the message payload of a Vulcan message for the registered message listener callback function.

 *

 * @param vulcanMessage   The message object.

 * @return                A string containing the message payload.

 */

Vulcan.prototype.getPayload = function(vulcanMessage)

{

    if(!requiredParamsValid(vulcanMessage) || !strStartsWith(vulcanMessage.type, VulcanMessage.TYPE_PREFIX))

    {

        return null;

    }



	var message = new VulcanMessage(vulcanMessage.type);

	message.initialize(vulcanMessage);

	return message.getPayload();

};



/** Singleton instance of Vulcan **/

var VulcanInterface = new Vulcan();



//--------------------------------- Vulcan Message ------------------------------



/**

 * @class VulcanMessage

 * Message type for sending messages between host applications.

 * A message of this type can be broadcast to all running

 * Vulcan-enabled apps.

 *

 * To send a message between extensions running within one

 * application, use the <code>CSEvent</code> type in CSInterface.js.

 *

 * @param type            The message type.

 *

 */

function VulcanMessage(type)

{

    this.type = type;

    this.scope = VulcanMessage.SCOPE_SUITE;

    this.appId = VulcanMessage.DEFAULT_APP_ID;

	this.appVersion = VulcanMessage.DEFAULT_APP_VERSION;

    this.data = VulcanMessage.DEFAULT_DATA;

};



VulcanMessage.TYPE_PREFIX    = "vulcan.SuiteMessage.";

VulcanMessage.SCOPE_SUITE    = "GLOBAL";

VulcanMessage.DEFAULT_APP_ID = "UNKNOWN";

VulcanMessage.DEFAULT_APP_VERSION = "UNKNOWN";

VulcanMessage.DEFAULT_DATA = "<data><payload></payload></data>";

VulcanMessage.dataTemplate = "<data>{0}</data>";

VulcanMessage.payloadTemplate = "<payload>{0}</payload>";



/**

 * Initializes this message instance.

 *

 * @param message         A \c message instance to use for initialization.

 */

VulcanMessage.prototype.initialize = function(message)

{

    this.type = message.type;

    this.scope = message.scope;

    this.appId = message.appId;

    this.appVersion = message.appVersion;

    this.data = message.data;

};



/**

 * Retrieve the message data.

 *

 * @return A data string in XML format.

 */

VulcanMessage.prototype.xmlData = function ()

{

    if(this.data == undefined)

    {

        var str = "";

		str = String.format(VulcanMessage.payloadTemplate, str);

		this.data = String.format(VulcanMessage.dataTemplate, str);

    }

    return this.data;

};



/**

 * Sets the message payload of this message.

 *

 * @param payload         A string containing the message payload.

 */

VulcanMessage.prototype.setPayload = function(payload)

{

    var str = cep.encoding.convertion.utf8_to_b64(payload);

    str = String.format(VulcanMessage.payloadTemplate, str);

    this.data = String.format(VulcanMessage.dataTemplate, str);

};



/**

 * Retrieves the message payload of this message.

 *

 * @return                A string containing the message payload.

 */

VulcanMessage.prototype.getPayload = function()

{

    var str = GetValueByKey(this.data, "payload");

    if(str != null)

    {

        return cep.encoding.convertion.b64_to_utf8(str);

    }



    return null;

};



/**

 * Converts the properties of this instance to a string.

 *

 * @return The string version of this instance.

 */

VulcanMessage.prototype.toString = function()

{

    var str = "type=" + this.type;

    str += ", scope=" + this.scope;

    str += ", appId=" + this.appId;

    str += ", appVersion=" + this.appVersion;

    str += ", data=" + this.xmlData();

    return str;

};



//--------------------------------------- Util --------------------------------



/**

 * Formats a string based on a template.

 *

 * @param src The format template.

 *

 * @return The formatted string

 */

String.format = function(src)

{

    if (arguments.length == 0)

    {

        return null;

    }



    var args = Array.prototype.slice.call(arguments, 1);

    return src.replace(/\{(\d+)\}/g, function(m, i){

        return args[i];

  });

};



/**

 * Retrieves the content of an XML element.

 *

 * @param xmlStr    The XML string.

 * @param key       The name of the tag.

 *

 * @return          The content of the tag, or the empty string if such tag is found

 *          or the tag has no content.

 */

function GetValueByKey(xmlStr, key)

{

    if(window.DOMParser)

    {

        var parser = new window.DOMParser();

        try

        {

            var xmlDoc = parser.parseFromString(xmlStr, "text/xml");

            var node = xmlDoc.getElementsByTagName(key)[0];

            if(node && node.childNodes[0])

            {

                return node.childNodes[0].nodeValue;

            }

        }

        catch(e)

        {

            //log the error

        }

    }

    return "";

};



/**

 * Reports whether required parameters are valid.

 *

 * @return    True if all required parameters are valid,

 *            false if any of the required parameters are invalid.

 */

function requiredParamsValid()

{

    for(var i = 0; i< arguments.length; i++)

    {

        var argument = arguments[i];

        if(argument == undefined || argument == null)

        {

            return false;

        }

    }



    return true;

};



/**

 * Reports whether a string has a given prefix.

 *

 * @param str       The target string.

 * @param prefix    The specific prefix string.

 *

 * @return          True if the string has the prefix, false if not.

 */

function strStartsWith(str, prefix)

{

    if(typeof str != "string")

    {

        return false;

    }

    return str.indexOf(prefix) === 0;

};

