var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
(function (factory) {
    if (typeof module === "object" && typeof module.exports === "object") {
        var v = factory(require, exports);
        if (v !== undefined) module.exports = v;
    }
    else if (typeof define === "function" && define.amd) {
        define(["require", "exports", "@theintern/leadfoot/Session", "@dojo/core/async/Task"], factory);
    }
})(function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    var Session_1 = require("@theintern/leadfoot/Session");
    var Task_1 = require("@dojo/core/async/Task");
    /* istanbul ignore next: client-side code */
    function getCoverageData(coverageVariable) {
        var coverageData = (function () { return this; })()[coverageVariable];
        return coverageData && JSON.stringify(coverageData);
    }
    /**
     * A ProxiedSession object represents a WebDriver session that interacts with the Intern instrumenting server. It
     * collects code instrumentation data from pages and converts local filesystem paths into URLs for use with
     * {@link module:leadfoot/Session#get}.
     */
    var ProxiedSession = (function (_super) {
        __extends(ProxiedSession, _super);
        function ProxiedSession() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            /**
             * Indicate whether coverage data should be requested before performing a request.
             */
            _this.coverageEnabled = false;
            /**
             * The name of the global variable used to store coverage data.
             */
            _this.coverageVariable = '';
            /**
             * The number of characters that need to be truncated from the front of file paths to get a working path-part
             * for a URL.
             */
            _this.serverBasePathLength = 0;
            /**
             * The base URL of the server server in use.
             */
            _this.serverUrl = '';
            return _this;
        }
        /**
         * Navigates the browser to a new URL like {@link module:leadfoot/Session#get}, but retrieves any code coverage
         * data recorded by the browser prior to navigation.
         */
        ProxiedSession.prototype.get = function (url) {
            var _this = this;
            // At least two letters are required in the scheme to avoid Windows paths being misinterpreted as URLs
            if (!/^[A-Za-z][A-Za-z0-9+.-]+:/.test(url)) {
                if (url.indexOf(this.executor.config.basePath) === 0) {
                    url = url.slice(this.serverBasePathLength);
                }
                url = this.serverUrl + url;
            }
            if (!this.coverageEnabled) {
                return _super.prototype.get.call(this, url);
            }
            return this._getCoverage().finally(function () {
                return _super.prototype.get.call(_this, url);
            });
        };
        /**
         * Quits the browser like {@link module:leadfoot/Session#quit}, but retrieves any code coverage data recorded
         * by the browser prior to quitting.
         */
        ProxiedSession.prototype.quit = function () {
            var _this = this;
            this.executor.log('Quitting', this.sessionId);
            return this
                .setHeartbeatInterval(0)
                .then(function () {
                if (_this.coverageEnabled) {
                    return _this._getCoverage();
                }
            })
                .finally(function () { return _super.prototype.quit.call(_this); });
        };
        /**
         * Sets up a timer to send no-op commands to the remote server on an interval to prevent long-running unit tests
         * from causing the session to time out.
         *
         * @param delay Amount of time to wait between heartbeats. Setting the delay to 0 will disable heartbeats.
         */
        ProxiedSession.prototype.setHeartbeatInterval = function (delay) {
            var _this = this;
            this._heartbeatIntervalHandle && this._heartbeatIntervalHandle.remove();
            if (delay) {
                // A heartbeat command is sent immediately when the interval is set because it is unknown how long ago
                // the last command was sent and it simplifies the implementation by requiring only one call to
                // `setTimeout`
                var sendHeartbeat_1 = function () {
                    var timeoutId;
                    var cancelled = false;
                    var startTime = Date.now();
                    _this._heartbeatIntervalHandle = {
                        remove: function () {
                            cancelled = true;
                            clearTimeout(timeoutId);
                        }
                    };
                    _this.getCurrentUrl().then(function () {
                        if (!cancelled) {
                            timeoutId = setTimeout(sendHeartbeat_1, delay - (Date.now() - startTime));
                        }
                    }).catch(function (error) { return _this.executor.emit('error', error); });
                };
                sendHeartbeat_1();
            }
            return Task_1.default.resolve();
        };
        ProxiedSession.prototype._getCoverage = function () {
            var _this = this;
            var shouldGetPromise;
            // At least Safari 9 will not inject user scripts for non http/https URLs, so we can't get coverage data.
            if (this.capabilities.brokenExecuteForNonHttpUrl) {
                shouldGetPromise = Task_1.default.resolve(this.getCurrentUrl().then(function (url) { return (/^https?:/i).test(url); }));
            }
            else {
                shouldGetPromise = Task_1.default.resolve(true);
            }
            return shouldGetPromise.then(function (shouldGetCoverage) {
                if (shouldGetCoverage) {
                    return _this.execute(getCoverageData, [_this.coverageVariable]).then(function (coverageData) {
                        // Emit coverage retrieved from a remote session
                        _this.executor.log('Got coverage data for', _this.sessionId);
                        if (coverageData) {
                            return _this.executor.emit('coverage', {
                                sessionId: _this.sessionId,
                                source: 'remote session',
                                coverage: JSON.parse(coverageData)
                            });
                        }
                    });
                }
            });
        };
        return ProxiedSession;
    }(Session_1.default));
    exports.default = ProxiedSession;
});
//# sourceMappingURL=ProxiedSession.js.map