import { generateId, createLinkedList, } from "@intelligentgraphics/ig.utilities";
import BaseLogger from "../Logger";
const Logger = BaseLogger.createSubLogger("NotificationCenter");
const ALL_NOTIFICATIONS_TOKEN = "ALL_NOTIFICATIONS_*[]*";
export const createNotificationCenter = () => {
    const listeners = createLinkedList();
    const createSubscription = (data) => {
        const id = data.id === undefined ? generateId() : data.id;
        return {
            id,
            send: (event, data) => send(id, event, data),
            destroy: () => unsubscribe(id),
        };
    };
    const any = (callback, options = {}) => {
        const subscription = createSubscription(options);
        listeners.push({
            id: subscription.id,
            callback,
            event: ALL_NOTIFICATIONS_TOKEN,
        });
        return subscription;
    };
    const on = (event, callback, options = {}) => {
        Logger.info("subscribing", { event, options });
        const subscription = createSubscription(options);
        listeners.push({
            id: subscription.id,
            callback,
            event,
        });
        return subscription;
    };
    const subscribe = (on, options = {}) => {
        Logger.info("subscribing", { options, on });
        const subscription = createSubscription(options);
        for (const event in on) {
            listeners.push({
                id: subscription.id,
                event: event,
                callback: on[event],
            });
        }
        return subscription;
    };
    const unsubscribe = (subscriber, notification) => {
        Logger.info("Unsubscribe", { subscriber, notification });
        listeners.consumeAll(item => {
            if (notification === undefined) {
                return item.id === subscriber;
            }
            return item.id === subscriber && item.event === notification;
        });
    };
    const send = (sender, notification, data) => {
        Logger.info("sending", {
            type: notification,
            data: data,
            sender: sender,
        });
        let eventData;
        listeners.forEach(({ id, callback, event }) => {
            if (
            // do not notify the sender itself
            sender === id ||
                (event !== ALL_NOTIFICATIONS_TOKEN && event !== notification)) {
                return;
            }
            if (eventData === undefined) {
                eventData = typeof data === "function" ? data() : data;
            }
            if (event === ALL_NOTIFICATIONS_TOKEN) {
                try {
                    callback({
                        event: notification,
                        data,
                        sender,
                    });
                }
                catch (err) {
                    Logger.error(err);
                }
                return;
            }
            try {
                callback(eventData, sender);
            }
            catch (err) {
                Logger.error(err);
            }
        });
    };
    const destroy = () => {
        listeners.clear();
    };
    return {
        destroy,
        any,
        on,
        subscribe,
        unsubscribe,
        send,
    };
};
export * from "./Subscription";
