/*
 * Copyright (c) Jupyter Development Team.
 * Distributed under the terms of the Modified BSD License.
 */
var __rest = (this && this.__rest) || function (s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                t[p[i]] = s[p[i]];
        }
    return t;
};
import { UUID } from '@lumino/coreutils';
import { Signal } from '@lumino/signaling';
/**
 * Notification manager
 */
export class NotificationManager {
    constructor() {
        this._isDisposed = false;
        this._queue = [];
        this._changed = new Signal(this);
    }
    /**
     * Signal emitted whenever a notification changes.
     */
    get changed() {
        return this._changed;
    }
    /**
     * Total number of notifications.
     */
    get count() {
        return this._queue.length;
    }
    /**
     * Whether the manager is disposed or not.
     */
    get isDisposed() {
        return this._isDisposed;
    }
    /**
     * The list of notifications.
     */
    get notifications() {
        return this._queue.slice();
    }
    /**
     * Dismiss one notification (specified by its id) or all if no id provided.
     *
     * @param id Notification id
     */
    dismiss(id) {
        if (typeof id === 'undefined') {
            const q = this._queue.slice();
            this._queue.length = 0;
            for (const notification of q) {
                this._changed.emit({
                    type: 'removed',
                    notification
                });
            }
        }
        else {
            const notificationIndex = this._queue.findIndex(n => n.id === id);
            if (notificationIndex > -1) {
                const notification = this._queue.splice(notificationIndex, 1)[0];
                this._changed.emit({
                    type: 'removed',
                    notification
                });
            }
        }
    }
    /**
     * Dispose the manager.
     */
    dispose() {
        if (this._isDisposed) {
            return;
        }
        this._isDisposed = true;
        Signal.clearData(this);
    }
    /**
     * Test whether a notification exists or not.
     *
     * @param id Notification id
     * @returns Notification status
     */
    has(id) {
        return this._queue.findIndex(n => n.id === id) > -1;
    }
    /**
     * Add a new notification.
     *
     * This will trigger the `changed` signal with an `added` event.
     *
     * @param message Notification message
     * @param type Notification type
     * @param options Notification option
     * @returns Notification unique id
     */
    notify(message, type, options) {
        const now = Date.now();
        const { progress } = options, othersOptions = __rest(options, ["progress"]);
        const notification = Object.freeze({
            id: UUID.uuid4(),
            createdAt: now,
            modifiedAt: now,
            message,
            type,
            options: Object.assign({ 
                // By default notification will be silent
                autoClose: 0, progress: typeof progress === 'number'
                    ? Math.min(Math.max(0, progress), 1)
                    : progress }, othersOptions)
        });
        this._queue.unshift(notification);
        this._changed.emit({
            type: 'added',
            notification
        });
        return notification.id;
    }
    /**
     * Update an existing notification.
     *
     * If the notification does not exists this won't do anything.
     *
     * Once updated the notification will be moved at the begin
     * of the notification stack.
     *
     * @param args Update options
     * @returns Whether the update was successful or not.
     */
    update(args) {
        const { id, message, actions, autoClose, data, progress, type } = args;
        const newProgress = typeof progress === 'number'
            ? Math.min(Math.max(0, progress), 1)
            : progress;
        const notificationIndex = this._queue.findIndex(n => n.id === id);
        if (notificationIndex > -1) {
            const oldNotification = this._queue[notificationIndex];
            // We need to create a new object as notification are frozen; i.e. cannot be edited
            const notification = Object.freeze(Object.assign(Object.assign({}, oldNotification), { message: message !== null && message !== void 0 ? message : oldNotification.message, type: type !== null && type !== void 0 ? type : oldNotification.type, options: {
                    actions: actions !== null && actions !== void 0 ? actions : oldNotification.options.actions,
                    autoClose: autoClose !== null && autoClose !== void 0 ? autoClose : oldNotification.options.autoClose,
                    data: data !== null && data !== void 0 ? data : oldNotification.options.data,
                    progress: newProgress !== null && newProgress !== void 0 ? newProgress : oldNotification.options.progress
                }, modifiedAt: Date.now() }));
            this._queue.splice(notificationIndex, 1);
            this._queue.unshift(notification);
            this._changed.emit({
                type: 'updated',
                notification
            });
            return true;
        }
        return false;
    }
}
/**
 * Notification namespace
 */
export var Notification;
(function (Notification) {
    /**
     * The global notification manager.
     */
    Notification.manager = new NotificationManager();
    /**
     * Dismiss one notification (specified by its id) or all if no id provided
     *
     * @param id notification id
     */
    function dismiss(id) {
        Notification.manager.dismiss(id);
    }
    Notification.dismiss = dismiss;
    /**
     * Helper function to emit a notification.
     *
     * #### Notes
     * The message will be truncated if longer than 140 characters.
     *
     * @param message Notification message
     * @param type Notification type
     * @param options Options for the error notification
     * @returns Notification unique id
     */
    function emit(message, type = 'default', options = {}) {
        return Notification.manager.notify(message, type, options);
    }
    Notification.emit = emit;
    /**
     * Helper function to emit an error notification.
     *
     * #### Notes
     * The message will be truncated if longer than 140 characters.
     *
     * @param message Notification message
     * @param options Options for the error notification
     * @returns Notification unique id
     */
    function error(message, options = {}) {
        return Notification.manager.notify(message, 'error', options);
    }
    Notification.error = error;
    /**
     * Helper function to emit an info notification.
     *
     * #### Notes
     * The message will be truncated if longer than 140 characters.
     *
     * @param message Notification message
     * @param options Options for the info notification
     * @returns Notification unique id
     */
    function info(message, options = {}) {
        return Notification.manager.notify(message, 'info', options);
    }
    Notification.info = info;
    /**
     * Helper function to show an in-progress notification.
     *
     * #### Notes
     * The message will be truncated if longer than 140 characters.
     *
     * @param promise Promise to wait for
     * @param options Options for the in-progress notification
     * @returns Notification unique id
     */
    function promise(promise, options) {
        var _a;
        const { pending, error, success } = options;
        const id = Notification.manager.notify(pending.message, 'in-progress', (_a = pending.options) !== null && _a !== void 0 ? _a : {});
        promise
            .then(result => {
            var _a, _b, _c;
            Notification.manager.update(Object.assign(Object.assign({ id, message: success.message(result, (_a = success.options) === null || _a === void 0 ? void 0 : _a.data), type: 'success' }, success.options), { data: (_c = (_b = success.options) === null || _b === void 0 ? void 0 : _b.data) !== null && _c !== void 0 ? _c : result }));
        })
            .catch(reason => {
            var _a, _b, _c;
            Notification.manager.update(Object.assign(Object.assign({ id, message: error.message(reason, (_a = error.options) === null || _a === void 0 ? void 0 : _a.data), type: 'error' }, error.options), { data: (_c = (_b = error.options) === null || _b === void 0 ? void 0 : _b.data) !== null && _c !== void 0 ? _c : reason }));
        });
        return id;
    }
    Notification.promise = promise;
    /**
     * Helper function to emit a success notification.
     *
     * #### Notes
     * The message will be truncated if longer than 140 characters.
     *
     * @param message Notification message
     * @param options Options for the success notification
     * @returns Notification unique id
     */
    function success(message, options = {}) {
        return Notification.manager.notify(message, 'success', options);
    }
    Notification.success = success;
    /**
     * Helper function to update a notification.
     *
     * If the notification does not exists, nothing will happen.
     *
     * Once updated the notification will be moved at the begin
     * of the notification stack.
     *
     * #### Notes
     * The message will be truncated if longer than 140 characters.
     *
     * @param args Update options
     * @returns Whether the update was successful or not.
     */
    function update(args) {
        return Notification.manager.update(args);
    }
    Notification.update = update;
    /**
     * Helper function to emit a warning notification.
     *
     * #### Notes
     * The message will be truncated if longer than 140 characters.
     *
     * @param message Notification message
     * @param options Options for the warning notification
     * @returns Notification unique id
     */
    function warning(message, options = {}) {
        return Notification.manager.notify(message, 'warning', options);
    }
    Notification.warning = warning;
})(Notification || (Notification = {}));
//# sourceMappingURL=notification.js.map