import { objEmpty, isFunction } from '../util/helpers';
const GLOBAL = 'GLOBAL';
const queue = {};
const isQueued = (eventName, uniqueId = GLOBAL) => queue.hasOwnProperty(eventName) && queue[eventName].hasOwnProperty(uniqueId);
const queueLength = (eventName, uniqueId = GLOBAL) => {
    if (!isQueued(eventName, uniqueId)) {
        return 0;
    }
    return queue[eventName][uniqueId].length;
};
const register = (eventName, callback, uniqueId = GLOBAL) => {
    if (!queue.hasOwnProperty(eventName)) {
        queue[eventName] = {};
    }
    if (!queue[eventName].hasOwnProperty(uniqueId)) {
        queue[eventName][uniqueId] = [];
    }
    queue[eventName][uniqueId].push(callback);
};
const registerOnce = (eventName, callback, uniqueId = GLOBAL) => {
    const cb = function (data) {
        deRegister(eventName, cb, uniqueId);
        callback(data);
    };
    cb.prototype.targetRef = callback;
    return register(eventName, cb, uniqueId);
};
const deRegister = (eventName, callback, uniqueId = GLOBAL) => {
    if (!isQueued(eventName, uniqueId)) {
        return false;
    }
    if (isFunction(callback)) {
        const len = queue[eventName][uniqueId].length;
        for (let i = len - 1; i >= 0; i--) {
            const fn = queue[eventName][uniqueId][i];
            if (callback === fn || (fn.prototype && callback === fn.prototype.targetRef)) {
                queue[eventName][uniqueId].splice(i, 1);
            }
        }
    }
    else {
        queue[eventName][uniqueId] = [];
    }
    if (queue[eventName][uniqueId].length === 0) {
        delete queue[eventName][uniqueId];
        if (objEmpty(queue[eventName])) {
            delete queue[eventName];
        }
    }
    return true;
};
const trigger = (eventName, data, uniqueId = GLOBAL, globalPropagation = true) => {
    const _propagate = globalPropagation && uniqueId !== GLOBAL;
    if (!isQueued(eventName, uniqueId)) {
        if (_propagate) {
            trigger(eventName, data);
        }
        return false;
    }
    const len = queue[eventName][uniqueId].length;
    if (!len) {
        if (_propagate) {
            trigger(eventName, data);
        }
        return false;
    }
    for (let i = len - 1; i >= 0; i--) {
        queue[eventName][uniqueId][i](data);
    }
    if (_propagate) {
        trigger(eventName, data);
    }
    return true;
};
const deRegisterAll = (eventName) => {
    delete queue[eventName];
};
export { trigger, register, registerOnce, deRegister, deRegisterAll, isQueued, queueLength };
