var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    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) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
(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", "../core/AtomComponent", "../core/AtomUri", "../core/FormattedString", "../core/types", "./ReferenceService"], factory);
    }
})(function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.NavigationService = exports.NotifyType = void 0;
    const AtomComponent_1 = require("../core/AtomComponent");
    const AtomUri_1 = require("../core/AtomUri");
    const FormattedString_1 = require("../core/FormattedString");
    const types_1 = require("../core/types");
    const ReferenceService_1 = require("./ReferenceService");
    // export interface ILocation {
    //     href?: string;
    //     hash?: INameValues;
    //     host?: string;
    //     hostName?: string;
    //     port?: string;
    //     protocol?: string;
    // }
    var NotifyType;
    (function (NotifyType) {
        NotifyType["Information"] = "info";
        NotifyType["Warning"] = "warn";
        NotifyType["Error"] = "error";
    })(NotifyType = exports.NotifyType || (exports.NotifyType = {}));
    const nameSymbol = UMD.nameSymbol;
    function hasPageUrl(target) {
        const url = target[nameSymbol];
        if (!url) {
            return false;
        }
        const baseClass = Object.getPrototypeOf(target);
        if (!baseClass) {
            // this is not possible...
            return false;
        }
        return baseClass[nameSymbol] !== url;
    }
    class NavigationService {
        constructor(app) {
            this.app = app;
            this.callbacks = [];
        }
        /**
         *
         * @param pageName node style package url or a class
         * @param viewModelParameters key value pair that will be injected on ViewModel when created
         * @param options {@link IPageOptions}
         */
        openPage(pageName, viewModelParameters, options) {
            options = options || {};
            if (typeof pageName !== "string") {
                if (hasPageUrl(pageName)) {
                    pageName = pageName[nameSymbol];
                }
                else {
                    const rs = this.app.resolve(ReferenceService_1.default);
                    const host = pageName instanceof AtomComponent_1.AtomComponent ? "reference" : "class";
                    const r = rs.put(pageName);
                    pageName = `ref://${host}/${r.key}`;
                }
            }
            const url = new AtomUri_1.AtomUri(pageName);
            if (viewModelParameters) {
                for (const key in viewModelParameters) {
                    if (viewModelParameters.hasOwnProperty(key)) {
                        const element = viewModelParameters[key];
                        if (element === undefined) {
                            continue;
                        }
                        if (element === null) {
                            url.query["json:" + key] = "null";
                            continue;
                        }
                        if (key.startsWith("ref:") || element instanceof FormattedString_1.default) {
                            const r = element instanceof ReferenceService_1.ObjectReference ?
                                element :
                                this.app.resolve(ReferenceService_1.default).put(element);
                            url.query[key.startsWith("ref:") ? key : `ref:${key}`] =
                                r.key;
                            continue;
                        }
                        if (typeof element !== "string" &&
                            (typeof element === "object" || Array.isArray(element))) {
                            url.query["json:" + key] = JSON.stringify(element);
                        }
                        else {
                            url.query[key] = element;
                        }
                    }
                }
            }
            for (const iterator of this.callbacks) {
                const r = iterator(url, options);
                if (r) {
                    return r;
                }
            }
            return this.openWindow(url, options);
        }
        /**
         * Sends signal to remove window/popup/frame, it will not immediately remove, because
         * it will identify whether it can remove or not by displaying cancellation warning. Only
         * if there is no cancellation warning or user chooses to force close, it will not remove.
         * @param id id of an element
         * @returns true if view was removed successfully
         */
        remove(view, force) {
            return __awaiter(this, void 0, void 0, function* () {
                if (force) {
                    this.app.broadcast(`atom-window-cancel:${view.id}`, "cancelled");
                    return true;
                }
                const vm = view.viewModel;
                if (vm && vm.cancel) {
                    const a = yield vm.cancel();
                    return a;
                }
                this.app.broadcast(`atom-window-cancel:${view.id}`, "cancelled");
                return true;
            });
        }
        registerNavigationHook(callback) {
            this.callbacks.push(callback);
            return {
                dispose: () => {
                    types_1.ArrayHelper.remove(this.callbacks, (a) => a === callback);
                }
            };
        }
    }
    exports.NavigationService = NavigationService;
});
// Do not mock Navigation unless you want it in design time..
// Mock.mock(NavigationService, "MockNavigationService");
//# sourceMappingURL=NavigationService.js.map