var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
(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", "../App", "../core/AtomUri", "../di/RegisterSingleton", "../view-model/AtomWindowViewModel", "./NavigationService"], factory);
    }
})(function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.MockNavigationService = exports.MockConfirmViewModel = void 0;
    const App_1 = require("../App");
    const AtomUri_1 = require("../core/AtomUri");
    const RegisterSingleton_1 = require("../di/RegisterSingleton");
    const AtomWindowViewModel_1 = require("../view-model/AtomWindowViewModel");
    const NavigationService_1 = require("./NavigationService");
    class MockConfirmViewModel extends AtomWindowViewModel_1.AtomWindowViewModel {
    }
    exports.MockConfirmViewModel = MockConfirmViewModel;
    /**
     * Mock of WindowService for unit tests
     * @export
     * @class MockWindowService
     * @extends {WindowService}
     */
    let MockNavigationService = class MockNavigationService extends NavigationService_1.NavigationService {
        constructor(app) {
            super(app);
            this.windowStack = [];
            this.history = [];
            this.mLocation = new AtomUri_1.AtomUri("");
        }
        /**
         * Gets current location of browser, this does not return
         * actual location but it returns values of browser location.
         * This is done to provide mocking behavior for unit testing.
         *
         * @readonly
         * @type {AtomLocation}
         * @memberof BrowserService
         */
        get location() {
            return this.mLocation;
        }
        set location(v) {
            if (JSON.stringify(this.location) === JSON.stringify(v)) {
                return;
            }
            this.history.push(this.mLocation);
            this.mLocation = v;
        }
        refresh() {
            // nothing
        }
        /**
         * Navigate current browser to given url.
         * @param {string} url
         * @memberof BrowserService
         */
        navigate(url) {
            this.location = new AtomUri_1.AtomUri(url);
        }
        back() {
            if (this.history.length) {
                const top = this.history.pop();
                this.location = top;
                this.history.pop();
            }
        }
        /**
         * Internal usage
         * @param {string} msg
         * @param {string} [title]
         * @returns {Promise<any>}
         * @memberof MockWindowService
         */
        alert(msg, title) {
            return this.openTestWindow(`__AlertWindow_${msg}`, { message: msg, title });
        }
        /**
         * Internal usage
         * @param {string} msg
         * @param {string} [title]
         * @returns {Promise<boolean>}
         * @memberof MockWindowService
         */
        confirm(msg, title) {
            return this.openTestWindow(`__ConfirmWindow_${msg}`, { message: msg, title });
        }
        openPage(pageName, p) {
            return this.openTestWindow(pageName, p);
        }
        notify(message, title) {
            const url = `__AlertNotification_${message}`;
            const w = this.windowStack.find((x) => x.windowType === message);
            if (!w) {
                throw new Error(`No notification registered for "${message}"`);
            }
            w.action({});
        }
        /**
         * Internal usage
         * @template T
         * @param {string} c
         * @param {AtomViewModel} vm
         * @returns {Promise<T>}
         * @memberof MockWindowService
         */
        openTestWindow(c, p) {
            const url = c instanceof AtomUri_1.AtomUri ? c : new AtomUri_1.AtomUri(c);
            if (p) {
                for (const key in p) {
                    if (p.hasOwnProperty(key)) {
                        const element = p[key];
                        url.query[key] = element;
                    }
                }
            }
            return new Promise((resolve, reject) => {
                const w = this.windowStack.find((x) => x.windowType === url.path);
                if (!w) {
                    const ex = new Error(`No window registered for "${c} with ${(p ? JSON.stringify(p, undefined, 2) : "")}"`);
                    reject(ex);
                    return;
                }
                setTimeout(() => {
                    try {
                        const vm = new AtomWindowViewModel_1.AtomWindowViewModel(this.app);
                        for (const key in url.query) {
                            if (url.query.hasOwnProperty(key)) {
                                const element = url.query[key];
                                vm[key] = element;
                            }
                        }
                        resolve(w.action(vm));
                    }
                    catch (e) {
                        reject(e);
                    }
                }, 5);
            });
        }
        /**
         * Call this method before any method that should expect an alert.
         * You can add many alerts, but each expected alert will only be called
         * once.
         * @param {string} msg
         * @returns {IDisposable}
         * @memberof MockWindowService
         */
        expectAlert(msg) {
            return this.expectWindow(`__AlertWindow_${msg}`, (vm) => true);
        }
        /**
         * Call this method before any method that should expect a notification.
         * You can add many alerts, but each expected alert will only be called
         * once.
         * @param {string} msg
         * @returns {IDisposable}
         * @memberof MockWindowService
         */
        expectNotification(msg) {
            return this.expectWindow(`__AlertNotification_${msg}`, (vm) => true);
        }
        /**
         * Call this method before any method that should expect a confirm.
         * You can add many confirms, but each expected confirm will only be called
         * once.
         * @param {string} msg
         * @param {(vm:MockConfirmViewModel) => boolean} action
         * @returns {IDisposable}
         * @memberof MockWindowService
         */
        expectConfirm(msg, action) {
            return this.expectWindow(`__ConfirmWindow_${msg}`, action);
        }
        /**
         * Call this method before any method that should expect a window of given type.
         * Each window will only be used once and return value in windowAction will be
         * resolved in promise created by openWindow call.
         * @template TViewModel
         * @param {string} windowType
         * @param {(vm:TViewModel) => any} windowAction
         * @param {number} [maxDelay=10000]
         * @returns {IDisposable}
         * @memberof MockWindowService
         */
        expectPopup(popupType, windowAction) {
            return this.expectWindow(popupType, windowAction);
        }
        /**
         * Call this method before any method that should expect a window of given type.
         * Each window will only be used once and return value in windowAction will be
         * resolved in promise created by openWindow call.
         * @template TViewModel
         * @param {string} windowType
         * @param {(vm:TViewModel) => any} windowAction
         * @param {number} [maxDelay=10000]
         * @returns {IDisposable}
         * @memberof MockWindowService
         */
        expectWindow(windowType, windowAction) {
            const registration = { windowType, action: windowAction };
            registration.action = (vm) => {
                this.removeRegistration(registration);
                return windowAction(vm);
            };
            this.windowStack.push(registration);
            return {
                dispose: () => {
                    this.removeRegistration(registration);
                }
            };
        }
        removeRegistration(r) {
            this.windowStack = this.windowStack.filter((x) => x !== r);
        }
        assert() {
            if (!this.windowStack.length) {
                return;
            }
            throw new Error(`Expected windows did not open ${this.windowStack.map((x) => `"${x.windowType}"`).join(",")}`);
        }
        registerForPopup() {
            // nothing
        }
        forceRemove(view) {
            throw new Error("Method not implemented.");
        }
        openWindow(url) {
            return this.openTestWindow(url);
        }
    };
    MockNavigationService = __decorate([
        RegisterSingleton_1.RegisterSingleton,
        __metadata("design:paramtypes", [App_1.App])
    ], MockNavigationService);
    exports.MockNavigationService = MockNavigationService;
});
//# sourceMappingURL=MockNavigationService.js.map