/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
*/

/**
 * Creates a gap bridge iframe used to notify the native code about queued
 * commands.
 */
var cordova = require('cordova'),
    channel = require('cordova/channel'),
    utils = require('cordova/utils'),
    base64 = require('cordova/base64'),
    // XHR mode does not work on iOS 4.2.
    // XHR mode's main advantage is working around a bug in -webkit-scroll, which
    // doesn't exist only on iOS 5.x devices.
    // IFRAME_NAV is the fastest.
    // IFRAME_HASH could be made to enable synchronous bridge calls if we wanted this feature.
    jsToNativeModes = {
        IFRAME_NAV: 0, // Default. Uses a new iframe for each poke.
        // XHR bridge appears to be flaky sometimes: CB-3900, CB-3359, CB-5457, CB-4970, CB-4998, CB-5134
        XHR_NO_PAYLOAD: 1, // About the same speed as IFRAME_NAV. Performance not about the same as IFRAME_NAV, but more variable.
        XHR_WITH_PAYLOAD: 2, // Flakey, and not as performant
        XHR_OPTIONAL_PAYLOAD: 3, // Flakey, and not as performant
        IFRAME_HASH_NO_PAYLOAD: 4, // Not fully baked. A bit faster than IFRAME_NAV, but risks jank since poke happens synchronously.
        IFRAME_HASH_WITH_PAYLOAD: 5, // Slower than no payload. Maybe since it has to be URI encoded / decoded.
        WK_WEBVIEW_BINDING: 6 // Only way that works for WKWebView :)
    },
    bridgeMode,
    execIframe,
    execHashIframe,
    hashToggle = 1,
    execXhr,
    requestCount = 0,
    vcHeaderValue = null,
    commandQueue = [], // Contains pending JS->Native messages.
    isInContextOfEvalJs = 0,
    failSafeTimerId = 0;

function shouldBundleCommandJson() {
    if (bridgeMode === jsToNativeModes.XHR_WITH_PAYLOAD) {
        return true;
    }
    if (bridgeMode === jsToNativeModes.XHR_OPTIONAL_PAYLOAD) {
        var payloadLength = 0;
        for (var i = 0; i < commandQueue.length; ++i) {
            payloadLength += commandQueue[i].length;
        }
        // The value here was determined using the benchmark within CordovaLibApp on an iPad 3.
        return payloadLength < 4500;
    }
    return false;
}

function massageArgsJsToNative(args) {
    if (!args || utils.typeName(args) != 'Array') {
        return args;
    }
    var ret = [];
    args.forEach(function(arg, i) {
        if (utils.typeName(arg) == 'ArrayBuffer') {
            ret.push({
                'CDVType': 'ArrayBuffer',
                'data': base64.fromArrayBuffer(arg)
            });
        } else {
            ret.push(arg);
        }
    });
    return ret;
}

function massageMessageNativeToJs(message) {
    if (message.CDVType == 'ArrayBuffer') {
        var stringToArrayBuffer = function(str) {
            var ret = new Uint8Array(str.length);
            for (var i = 0; i < str.length; i++) {
                ret[i] = str.charCodeAt(i);
            }
            return ret.buffer;
        };
        var base64ToArrayBuffer = function(b64) {
            return stringToArrayBuffer(atob(b64));
        };
        message = base64ToArrayBuffer(message.data);
    }
    return message;
}

function convertMessageToArgsNativeToJs(message) {
    var args = [];
    if (!message || !message.hasOwnProperty('CDVType')) {
        args.push(message);
    } else if (message.CDVType == 'MultiPart') {
        message.messages.forEach(function(e) {
            args.push(massageMessageNativeToJs(e));
        });
    } else {
        args.push(massageMessageNativeToJs(message));
    }
    return args;
}

function iOSExec() {
    if (bridgeMode === undefined) {
        bridgeMode = jsToNativeModes.IFRAME_NAV;
    }

    if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.cordova && window.webkit.messageHandlers.cordova.postMessage) {
        bridgeMode = jsToNativeModes.WK_WEBVIEW_BINDING;
    }

    var successCallback, failCallback, service, action, actionArgs, splitCommand;
    var callbackId = null;
    if (typeof arguments[0] !== "string") {
        // FORMAT ONE
        successCallback = arguments[0];
        failCallback = arguments[1];
        service = arguments[2];
        action = arguments[3];
        actionArgs = arguments[4];

        // Since we need to maintain backwards compatibility, we have to pass
        // an invalid callbackId even if no callback was provided since plugins
        // will be expecting it. The Cordova.exec() implementation allocates
        // an invalid callbackId and passes it even if no callbacks were given.
        callbackId = 'INVALID';
    } else {
        // FORMAT TWO, REMOVED
        try {
            splitCommand = arguments[0].split(".");
            action = splitCommand.pop();
            service = splitCommand.join(".");
            actionArgs = Array.prototype.splice.call(arguments, 1);

            console.log('The old format of this exec call has been removed (deprecated since 2.1). Change to: ' +
                       "cordova.exec(null, null, \"" + service + "\", \"" + action + "\"," + JSON.stringify(actionArgs) + ");"
            );
            return;
        } catch (e) {}
    }

    // If actionArgs is not provided, default to an empty array
    actionArgs = actionArgs || [];

    // Register the callbacks and add the callbackId to the positional
    // arguments if given.
    if (successCallback || failCallback) {
        callbackId = service + cordova.callbackId++;
        cordova.callbacks[callbackId] =
            {success:successCallback, fail:failCallback};
    }

    actionArgs = massageArgsJsToNative(actionArgs);

    var command = [callbackId, service, action, actionArgs];

    if (bridgeMode === jsToNativeModes.WK_WEBVIEW_BINDING) {
        window.webkit.messageHandlers.cordova.postMessage(command);
    } else {
        // Stringify and queue the command. We stringify to command now to
        // effectively clone the command arguments in case they are mutated before
        // the command is executed.
        commandQueue.push(JSON.stringify(command));
    
        // If we're in the context of a stringByEvaluatingJavaScriptFromString call,
        // then the queue will be flushed when it returns; no need for a poke.
        // Also, if there is already a command in the queue, then we've already
        // poked the native side, so there is no reason to do so again.
        if (!isInContextOfEvalJs && commandQueue.length == 1) {
            pokeNative();
        }
    }
}

function pokeNative() {
    switch (bridgeMode) {
    case jsToNativeModes.XHR_NO_PAYLOAD:
    case jsToNativeModes.XHR_WITH_PAYLOAD:
    case jsToNativeModes.XHR_OPTIONAL_PAYLOAD:
        pokeNativeViaXhr();
        break;
    default: // iframe-based.
        pokeNativeViaIframe();
    }
}

function pokeNativeViaXhr() {
    // This prevents sending an XHR when there is already one being sent.
    // This should happen only in rare circumstances (refer to unit tests).
    if (execXhr && execXhr.readyState != 4) {
        execXhr = null;
    }
    // Re-using the XHR improves exec() performance by about 10%.
    execXhr = execXhr || new XMLHttpRequest();
    // Changing this to a GET will make the XHR reach the URIProtocol on 4.2.
    // For some reason it still doesn't work though...
    // Add a timestamp to the query param to prevent caching.
    execXhr.open('HEAD', "/!gap_exec?" + (+new Date()), true);
    if (!vcHeaderValue) {
        vcHeaderValue = /.*\((.*)\)$/.exec(navigator.userAgent)[1];
    }
    execXhr.setRequestHeader('vc', vcHeaderValue);
    execXhr.setRequestHeader('rc', ++requestCount);
    if (shouldBundleCommandJson()) {
        execXhr.setRequestHeader('cmds', iOSExec.nativeFetchMessages());
    }
    execXhr.send(null);
}

function pokeNativeViaIframe() {
    // CB-5488 - Don't attempt to create iframe before document.body is available.
    if (!document.body) {
        setTimeout(pokeNativeViaIframe);
        return;
    }
    if (bridgeMode === jsToNativeModes.IFRAME_HASH_NO_PAYLOAD || bridgeMode === jsToNativeModes.IFRAME_HASH_WITH_PAYLOAD) {
        // TODO: This bridge mode doesn't properly support being removed from the DOM (CB-7735)
        if (!execHashIframe) {
            execHashIframe = document.createElement('iframe');
            execHashIframe.style.display = 'none';
            document.body.appendChild(execHashIframe);
            // Hash changes don't work on about:blank, so switch it to file:///.
            execHashIframe.contentWindow.history.replaceState(null, null, 'file:///#');
        }
        // The delegate method is called only when the hash changes, so toggle it back and forth.
        hashToggle = hashToggle ^ 3;
        var hashValue = '%0' + hashToggle;
        if (bridgeMode === jsToNativeModes.IFRAME_HASH_WITH_PAYLOAD) {
            hashValue += iOSExec.nativeFetchMessages();
        }
        execHashIframe.contentWindow.location.hash = hashValue;
    } else {
        // Check if they've removed it from the DOM, and put it back if so.
        if (execIframe && execIframe.contentWindow) {
            execIframe.contentWindow.location = 'gap://ready';
        } else {
            execIframe = document.createElement('iframe');
            execIframe.style.display = 'none';
            execIframe.src = 'gap://ready';
            document.body.appendChild(execIframe);
        }
        // Use a timer to protect against iframe being unloaded during the poke (CB-7735).
        // This makes the bridge ~ 7% slower, but works around the poke getting lost
        // when the iframe is removed from the DOM.
        // An onunload listener could be used in the case where the iframe has just been
        // created, but since unload events fire only once, it doesn't work in the normal
        // case of iframe reuse (where unload will have already fired due to the attempted
        // navigation of the page).
        failSafeTimerId = setTimeout(function() {
            if (commandQueue.length) {
                pokeNative();
            }
        }, 50); // Making this > 0 improves performance (marginally) in the normal case (where it doesn't fire).
    }
}

iOSExec.jsToNativeModes = jsToNativeModes;

iOSExec.setJsToNativeBridgeMode = function(mode) {
    // Remove the iFrame since it may be no longer required, and its existence
    // can trigger browser bugs.
    // https://issues.apache.org/jira/browse/CB-593
    if (execIframe) {
        if (execIframe.parentNode) {
            execIframe.parentNode.removeChild(execIframe);
        }
        execIframe = null;
    }
    bridgeMode = mode;
};

iOSExec.nativeFetchMessages = function() {
    // Stop listing for window detatch once native side confirms poke.
    if (failSafeTimerId) {
        clearTimeout(failSafeTimerId);
        failSafeTimerId = 0;
    }
    // Each entry in commandQueue is a JSON string already.
    if (!commandQueue.length) {
        return '';
    }
    var json = '[' + commandQueue.join(',') + ']';
    commandQueue.length = 0;
    return json;
};

iOSExec.nativeCallback = function(callbackId, status, message, keepCallback) {
    return iOSExec.nativeEvalAndFetch(function() {
        var success = status === 0 || status === 1;
        var args = convertMessageToArgsNativeToJs(message);
        cordova.callbackFromNative(callbackId, success, status, args, keepCallback);
    });
};

iOSExec.nativeEvalAndFetch = function(func) {
    // This shouldn't be nested, but better to be safe.
    isInContextOfEvalJs++;
    try {
        func();
        return iOSExec.nativeFetchMessages();
    } finally {
        isInContextOfEvalJs--;
    }
};

module.exports = iOSExec;
