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", "./core/AtomBinder", "./core/AtomDispatcher", "./di/RegisterSingleton", "./di/ServiceProvider", "./services/BusyIndicatorService"], factory);
    }
})(function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.App = exports.AtomMessageAction = void 0;
    var AtomBinder_1 = require("./core/AtomBinder");
    var AtomDispatcher_1 = require("./core/AtomDispatcher");
    var RegisterSingleton_1 = require("./di/RegisterSingleton");
    var ServiceProvider_1 = require("./di/ServiceProvider");
    var BusyIndicatorService_1 = require("./services/BusyIndicatorService");
    var AtomHandler = /** @class */ (function () {
        function AtomHandler(message) {
            this.message = message;
            this.list = new Array();
        }
        return AtomHandler;
    }());
    var AtomMessageAction = /** @class */ (function () {
        function AtomMessageAction(msg, a) {
            this.message = msg;
            this.action = a;
        }
        return AtomMessageAction;
    }());
    exports.AtomMessageAction = AtomMessageAction;
    var App = /** @class */ (function (_super) {
        __extends(App, _super);
        function App() {
            var _this = _super.call(this, null) || this;
            /**
             * This must be set explicitly as it can be used outside to detect
             * if app is ready. This will not be set automatically by framework.
             */
            _this.appReady = false;
            _this.busyIndicators = [];
            // tslint:disable-next-line:ban-types
            _this.readyHandlers = [];
            _this.onError = function (error) {
                // tslint:disable-next-line:no-console
                console.log(error);
            };
            _this.screen = {};
            _this.bag = {};
            _this.put(App_1, _this);
            _this.dispatcher = new AtomDispatcher_1.AtomDispatcher();
            _this.dispatcher.start();
            _this.put(AtomDispatcher_1.AtomDispatcher, _this.dispatcher);
            setTimeout(function () {
                _this.invokeReady();
            }, 5);
            return _this;
        }
        App_1 = App;
        Object.defineProperty(App.prototype, "url", {
            get: function () {
                return this.mUrl;
            },
            set: function (v) {
                this.mUrl = v;
                AtomBinder_1.AtomBinder.refreshValue(this, "url");
            },
            enumerable: false,
            configurable: true
        });
        Object.defineProperty(App.prototype, "contextId", {
            get: function () {
                return "none";
            },
            enumerable: false,
            configurable: true
        });
        App.prototype.createBusyIndicator = function () {
            this.busyIndicatorService = this.busyIndicatorService
                || this.resolve(BusyIndicatorService_1.BusyIndicatorService);
            return this.busyIndicatorService.createIndicator();
        };
        App.prototype.syncUrl = function () {
            // must be implemented by platform specific app
        };
        App.prototype.callLater = function (f) {
            this.dispatcher.callLater(f);
        };
        App.prototype.updateDefaultStyle = function (content) {
            throw new Error("Platform does not support StyleSheets");
        };
        App.prototype.waitForPendingCalls = function () {
            return this.dispatcher.waitForAll();
        };
        /**
         * This method will run any asynchronous method
         * and it will display an error if it will fail
         * asynchronously
         *
         * @template T
         * @param {() => Promise<T>} tf
         * @memberof AtomDevice
         */
        App.prototype.runAsync = function (tf) {
            var _this = this;
            try {
                var p = tf();
                if (p && p.then && p.catch) {
                    p.catch(function (error) {
                        _this.onError("runAsync");
                        _this.onError(error);
                    });
                }
            }
            catch (e) {
                this.onError("runAsync");
                this.onError(e);
            }
        };
        /**
         * Broadcast given data to channel, only within the current window.
         *
         * @param {string} channel
         * @param {*} data
         * @returns
         * @memberof AtomDevice
         */
        App.prototype.broadcast = function (channel, data) {
            var ary = this.bag[channel];
            if (!ary) {
                return;
            }
            for (var _i = 0, _a = ary.list; _i < _a.length; _i++) {
                var entry = _a[_i];
                entry.call(this, channel, data);
            }
        };
        /**
         * Subscribe for given channel with action that will be
         * executed when anyone will broadcast (this only works within the
         * current browser window)
         *
         * This method returns a disposable, when you call `.dispose()` it will
         * unsubscribe for current subscription
         *
         * @param {string} channel
         * @param {AtomAction} action
         * @returns {AtomDisposable} Disposable that supports removal of subscription
         * @memberof AtomDevice
         */
        App.prototype.subscribe = function (channel, action) {
            var _this = this;
            var ary = this.bag[channel];
            if (!ary) {
                ary = new AtomHandler(channel);
                this.bag[channel] = ary;
            }
            ary.list.push(action);
            return {
                dispose: function () {
                    ary.list = ary.list.filter(function (a) { return a !== action; });
                    if (!ary.list.length) {
                        _this.bag[channel] = null;
                    }
                }
            };
        };
        App.prototype.main = function () {
            // load app here..
        };
        // tslint:disable-next-line:no-empty
        App.prototype.onReady = function (f) {
            if (this.readyHandlers) {
                this.readyHandlers.push(f);
            }
            else {
                this.invokeReadyHandler(f);
            }
        };
        App.prototype.invokeReady = function () {
            for (var _i = 0, _a = this.readyHandlers; _i < _a.length; _i++) {
                var iterator = _a[_i];
                this.invokeReadyHandler(iterator);
            }
            this.readyHandlers = null;
        };
        // tslint:disable-next-line:ban-types
        App.prototype.invokeReadyHandler = function (f) {
            var indicator = this.createBusyIndicator();
            var a = f();
            if (a && a.then && a.catch) {
                a.then(function (r) {
                    // do nothing
                    indicator.dispose();
                });
                a.catch(function (e) {
                    indicator.dispose();
                    // tslint:disable-next-line:no-console
                    // console.error("XFApp.onReady");
                    // tslint:disable-next-line:no-console
                    console.error(typeof e === "string" ? e : JSON.stringify(e));
                });
            }
        };
        var App_1;
        App = App_1 = __decorate([
            RegisterSingleton_1.RegisterSingleton,
            __metadata("design:paramtypes", [])
        ], App);
        return App;
    }(ServiceProvider_1.ServiceProvider));
    exports.App = App;
});
//# sourceMappingURL=App.js.map