'use strict';


/**
 * A typesafe interface for functions declared in the After Effects **Domain Object Model** scope
 */
const Host = (function()
{
    // Defining AE plugin scope
    const _scope = "PE_BENCH";


    /**
     * A hash table of converter functions for easier conversions
     * @private
     */
    var converters = {
        "string": function(arg) {return String(arg)},
        "boolean": function(arg) {return Boolean(arg)},
        "number": function(arg) {return Number(arg)},
        "array": function(arg) {return arg.split(/,|, /g)},
    }


    /**
     * Performs `window.__adobe_cep__.evalScript` passing in a callback and handling the return type
     * @private
     * @param {string} script 
     * @param {function} [callback] 
     * @param {"string"|"number"|"boolean"|"array"} [type] 
     */
    function executeScript(script, callback, type)
    {
        console.log("Executing Script:\n" + script);

        // Call the `evalScript` function
        window.__adobe_cep__.evalScript(script, (arg) => {
            // Returning if no callback has been passed as it's optional
            if(callback === undefined) { return; }

            // converting the function type, if specified
            if(type != undefined) {
                arg = converters[type](arg);
            }

            callback(arg);
        });
    }



    /**
     * Set the private extensionRoot variable based on the URI path of this extensions, "index.html"
     * @public
     * @param {string} indexPath The URI encoded path to "index.html"
     */
    function setRoot(indexPath)
    {
        var script = _scope + ".setRoot(\"" + indexPath + "\");";
        executeScript(script);
    }

    /**
     * @callback getSpecsCallback
     * @param {array} specs The array of specifications
     */
    /**
     * Gets the specifications of the local machine
     * @public
     * @param {getSpecsCallback} callback The function that will be called and passed the results of the host function
     */
    function getSpecs(callback)
    {
        var script = `${_scope}.getSpecs('${location}');`;
        executeScript(script, callback, "array");
    }

    /**
     * @callback checkRequirementsCallback
     * @param {boolean[]} requirements A list of booleans for each requirement (currently only one)
     */
    /**
     * Checks the requirements to make sure the app is valid to run  
     * Currently only checks if the Benchmark plugin is installed
     * @public
     * @param {checkRequirementsCallback} callback The function that will be called and passed the results of the host function
     */
    function checkRequirements(callback)
    {
        var script = `${_scope}.checkRequirements();`;
        executeScript(script, callback, "array");
    }

    
    /**
     * @callback pingCallback
     */
    /**
     * Simply pings After Effects to make sure the connection is working
     * @public
     * @param {pingCallback} callback The function that will be called and passed the results of the host function
     */
    function ping(callback)
    {
        var script = `${_scope}.ping();`;
        executeScript(script, callback);
    }


    /**
     * @callback mainCallback
     * @param {[number, number, number] | ["ERROR"]} scores An array of 3 numbers representing scores, `[Singlethreading, Multithreading, GPU]`, or `["ERROR"]` if something goes wrong
     */

    /**
     * Executes the main function which runs the tests, passing the score of each test to the callback function
     * @public
     * @param {boolean} debug Specifies whether we're running in debug mode or not
     * @param {mainCallback} callback The function that will be called and passed the results of the host function
     */
    function main(debug, callback)
    {
        var script = `${_scope}.main(${debug})`;
        executeScript(script, callback, "array");
    }



    // PUBLIC
    return {
        setRoot: setRoot,
        getSpecs: getSpecs,
        checkRequirements: checkRequirements,
        ping: ping,
        main: main
    };
})();


