var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        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 extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
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 });
    var App_1 = require("../App");
    var AtomUri_1 = require("../core/AtomUri");
    var RegisterSingleton_1 = require("../di/RegisterSingleton");
    var AtomWindowViewModel_1 = require("../view-model/AtomWindowViewModel");
    var NavigationService_1 = require("./NavigationService");
    var MockConfirmViewModel = /** @class */ (function (_super) {
        __extends(MockConfirmViewModel, _super);
        function MockConfirmViewModel() {
            return _super !== null && _super.apply(this, arguments) || this;
        }
        return MockConfirmViewModel;
    }(AtomWindowViewModel_1.AtomWindowViewModel));
    exports.MockConfirmViewModel = MockConfirmViewModel;
    /**
     * Mock of WindowService for unit tests
     * @export
     * @class MockWindowService
     * @extends {WindowService}
     */
    var MockNavigationService = /** @class */ (function (_super) {
        __extends(MockNavigationService, _super);
        function MockNavigationService(app) {
            var _this = _super.call(this, app) || this;
            _this.windowStack = [];
            _this.history = [];
            _this.mLocation = new AtomUri_1.AtomUri("");
            return _this;
        }
        Object.defineProperty(MockNavigationService.prototype, "location", {
            /**
             * 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: function () {
                return this.mLocation;
            },
            set: function (v) {
                if (JSON.stringify(this.location) === JSON.stringify(v)) {
                    return;
                }
                this.history.push(this.mLocation);
                this.mLocation = v;
            },
            enumerable: true,
            configurable: true
        });
        MockNavigationService.prototype.refresh = function () {
            // nothing
        };
        /**
         * Navigate current browser to given url.
         * @param {string} url
         * @memberof BrowserService
         */
        MockNavigationService.prototype.navigate = function (url) {
            this.location = new AtomUri_1.AtomUri(url);
        };
        MockNavigationService.prototype.back = function () {
            if (this.history.length) {
                var top_1 = this.history.pop();
                this.location = top_1;
                this.history.pop();
            }
        };
        /**
         * Internal usage
         * @param {string} msg
         * @param {string} [title]
         * @returns {Promise<any>}
         * @memberof MockWindowService
         */
        MockNavigationService.prototype.alert = function (msg, title) {
            return this.openTestWindow("__AlertWindow_" + msg, { message: msg, title: title });
        };
        /**
         * Internal usage
         * @param {string} msg
         * @param {string} [title]
         * @returns {Promise<boolean>}
         * @memberof MockWindowService
         */
        MockNavigationService.prototype.confirm = function (msg, title) {
            return this.openTestWindow("__ConfirmWindow_" + msg, { message: msg, title: title });
        };
        MockNavigationService.prototype.openPage = function (pageName, p) {
            return this.openTestWindow(pageName, p);
        };
        MockNavigationService.prototype.notify = function (message, title) {
            var url = "__AlertNotification_" + message;
            var w = this.windowStack.find(function (x) { return 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
         */
        MockNavigationService.prototype.openTestWindow = function (c, p) {
            var _this = this;
            var url = c instanceof AtomUri_1.AtomUri ? c : new AtomUri_1.AtomUri(c);
            if (p) {
                for (var key in p) {
                    if (p.hasOwnProperty(key)) {
                        var element = p[key];
                        url.query[key] = element;
                    }
                }
            }
            return new Promise(function (resolve, reject) {
                var w = _this.windowStack.find(function (x) { return x.windowType === url.path; });
                if (!w) {
                    var ex = new Error("No window registered for \"" + c + " with " + (p ? JSON.stringify(p, undefined, 2) : "") + "\"");
                    reject(ex);
                    return;
                }
                setTimeout(function () {
                    try {
                        var vm = new AtomWindowViewModel_1.AtomWindowViewModel(_this.app);
                        for (var key in url.query) {
                            if (url.query.hasOwnProperty(key)) {
                                var 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
         */
        MockNavigationService.prototype.expectAlert = function (msg) {
            return this.expectWindow("__AlertWindow_" + msg, function (vm) { return 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
         */
        MockNavigationService.prototype.expectNotification = function (msg) {
            return this.expectWindow("__AlertNotification_" + msg, function (vm) { return 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
         */
        MockNavigationService.prototype.expectConfirm = function (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
         */
        MockNavigationService.prototype.expectPopup = function (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
         */
        MockNavigationService.prototype.expectWindow = function (windowType, windowAction) {
            var _this = this;
            var registration = { windowType: windowType, action: windowAction };
            registration.action = function (vm) {
                _this.removeRegistration(registration);
                return windowAction(vm);
            };
            this.windowStack.push(registration);
            return {
                dispose: function () {
                    _this.removeRegistration(registration);
                }
            };
        };
        MockNavigationService.prototype.removeRegistration = function (r) {
            this.windowStack = this.windowStack.filter(function (x) { return x !== r; });
        };
        MockNavigationService.prototype.assert = function () {
            if (!this.windowStack.length) {
                return;
            }
            throw new Error("Expected windows did not open " + this.windowStack.map(function (x) { return "\"" + x.windowType + "\""; }).join(","));
        };
        MockNavigationService.prototype.registerForPopup = function () {
            // nothing
        };
        MockNavigationService.prototype.forceRemove = function (view) {
            throw new Error("Method not implemented.");
        };
        MockNavigationService.prototype.openWindow = function (url) {
            return this.openTestWindow(url);
        };
        MockNavigationService = __decorate([
            RegisterSingleton_1.RegisterSingleton,
            __metadata("design:paramtypes", [App_1.App])
        ], MockNavigationService);
        return MockNavigationService;
    }(NavigationService_1.NavigationService));
    exports.MockNavigationService = MockNavigationService;
});
//# sourceMappingURL=MockNavigationService.js.map