var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
    result["default"] = mod;
    return result;
};
define(["require", "exports", "jquery", "./log"], function (require, exports, jquery_1, log) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    jquery_1 = __importDefault(jquery_1);
    log = __importStar(log);
    /* tslint:disable:no-any */
    // tslint:disable-next-line:no-typeof-undefined
    const test = (typeof __WED_TESTING !== "undefined") && __WED_TESTING.testing;
    const $modal = jquery_1.default(`\
<div class="modal wed-fatal-modal" style="position: absolute" tabindex="1">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal"
aria-hidden="true">&times;</button>
        <h3>Fatal Error</h3>
      </div>
      <div class="modal-body">
        <div class="save-messages"></div>
        <div class="error-message"></div>
      </div>
      <div class="modal-footer">
        <a href="#" class="btn btn-primary" data-dismiss="modal">Reload</a>
      </div>
    </div>
  </div>
</div>`);
    let terminating = false;
    let terminationTimeout;
    let terminationWindow;
    // Normally onerror will be reset by reloading but when testing with mocha we
    // don't want reloading, so we export this function.
    function reset() {
        terminating = false;
        if (terminationTimeout !== undefined) {
            terminationWindow.clearTimeout(terminationTimeout);
            terminationTimeout = undefined;
        }
        $modal.off();
        $modal.modal("hide");
        $modal.remove();
    }
    /**
     * @returns True if the error handling code was triggered.
     */
    function isTerminating() {
        return terminating;
    }
    exports.isTerminating = isTerminating;
    /**
     * A structure used only for testing purposes.
     *
     * @private
     */
    // tslint:disable-next-line:variable-name
    exports.__test = test ? {
        $modal,
        reset,
    } : undefined;
    /**
     * An array into which wed editors register themselves at creation and
     * unregister themselves when destroyed.
     */
    exports.editors = [];
    const TERMINATION_TIMEOUT = 5000;
    // So that we can issue clearTimeout elsewhere.
    function showModal(saveMessages, errorMessage) {
        jquery_1.default(document.body).append($modal);
        // tslint:disable-next-line:no-inner-html
        $modal.find(".save-messages")[0].innerHTML = saveMessages;
        $modal.find(".error-message")[0].textContent = errorMessage;
        $modal.on("hide.bs.modal.modal", () => {
            $modal.remove();
            window.location.reload();
        });
        $modal.modal();
    }
    function eventToMessage(ev) {
        let msg = "";
        if (ev.type === "error") {
            const { message, filename, lineno, colno, error: err } = ev;
            if (err) {
                msg = err.stack;
            }
            else {
                msg = `${filename}:${lineno}`;
                if (colno) {
                    msg += `.${colno}`;
                }
                msg += `: ${message}`;
            }
        }
        else {
            msg += "Unhandled promise rejection!\n";
            const source = ev.promise ? ev : ev.detail;
            if (source) {
                const { reason, promise } = source;
                if (reason) {
                    msg += `Reason: ${reason.stack ? `\n${reason.stack}` : reason}`;
                }
                else if (promise) {
                    msg += `Promise: ${promise}`;
                }
            }
        }
        return msg;
    }
    /**
     * Converts a save operation result to a message.
     *
     * @param name The name of the editor instance.
     * @param result The result of the save operation.
     *
     * @returns The message.
     */
    function toMsg(name, result) {
        let ret = `\
<p>${name !== undefined ? name : "Your editor"} experienced a severe error.`;
        ret += result === true ?
            ` However, it successfully saved the latest state of your data to \
the server. Please reload.` :
            ` It was not able to save your data to the server before \
terminating.`;
        return `${ret}</p>`;
    }
    function _handler(ev) {
        ev.preventDefault();
        // This avoids an infinite loop.
        if (terminating) {
            return false;
        }
        terminating = true;
        const errorMessage = eventToMessage(ev);
        const total = exports.editors.length;
        const root = window;
        function terminate(results) {
            if (terminationTimeout !== undefined) {
                root.clearTimeout(terminationTimeout);
            }
            const messages = [];
            if (total === 1) {
                messages.push(toMsg(undefined, results.length !== 0 ? results[0][1] : undefined));
            }
            else {
                for (const result of results) {
                    messages.push(toMsg(result[0].name, result[1]));
                }
            }
            showModal(messages.join(""), errorMessage);
        }
        terminationTimeout = root.setTimeout(terminate, TERMINATION_TIMEOUT);
        terminationWindow = root;
        // tslint:disable-next-line:no-console
        console.error(errorMessage);
        log.error(errorMessage);
        // tslint:disable-next-line:no-floating-promises
        Promise.all(exports.editors
            .filter(editor => editor.saver !== undefined)
            .map(editor => (() => __awaiter(this, void 0, void 0, function* () {
            try {
                return [editor, yield editor.saver.recover()];
            }
            catch (_a) {
                return [editor, undefined];
            }
        }))()))
            .then(terminate);
        return false;
    }
    /**
     * This is the error handler meant to be used to trap wed errors.
     */
    function handler(ev) {
        try {
            try {
                _handler(ev);
            }
            catch (ex) {
                showModal("", `Error while trying to handle fatal error: ${ex.toString()}`);
            }
        }
        catch (ex) {
            // tslint:disable-next-line:no-console
            console.error("Error while trying to handle fatal error:");
            // tslint:disable-next-line:no-console
            console.error(ex);
        }
    }
    exports.handler = handler;
});
//  LocalWords:  clearTimeout unregister iframe RequireJS href MPL
//  LocalWords:  onerror Mangalam Dubeau validthis jshint btn jquery
//  LocalWords:  tabindex jQuery
//# sourceMappingURL=onerror.js.map