

SIGNALS = {}

-- allows you to optionally make your own eventbus instead of using the global one
-- this is good if you only want to signal locally and don't need to allow external access
-- this copies the entire object, so uh, maybe don't make too many of these
-- this isn't OOP after all...
function SIGNALS.new(insert_in_table)
    local object = insert_in_table or {}
    object._register = {}
    object._values = {}
    -- listen to an event, return `"_cancel"` to cancel the rest of the callbacks
    object.LISTEN = function(tag, callback)
        if object._register[tag] == nil then object._register[tag] = {} end
        table.insert(object._register[tag], callback)
    end
    -- signal an event, and cancel if returns `"_cancel"`
    object.SIGNAL = function(tag, ...)
        tag = object._register[tag]
        if not tag then return end
        for i, callback in ipairs(tag) do
            local val = callback(...)
            if val == "_cancel" then
                return "_cancel"
            end
        end
    end
    -- returns bool from all listeners, such that ==false forces false, and no true return is false
    object.CONDITIONAL = function(tag, ...)
        tag = object._register[tag]
        if not tag then return end
        local had_true = false
        for i, callback in ipairs(tag) do
            local val = callback(...)
            if val == "_cancel" then
                return had_true
            elseif val == true then
                had_true = true
            elseif val == false then
                return val
            end
        end
        return had_true
    end
    return object
end

-- make the globally accessible one
SIGNALS.global = SIGNALS.new()
LISTEN = SIGNALS.global.LISTEN
SIGNAL = SIGNALS.global.SIGNAL
CONDITIONAL = SIGNALS.global.CONDITIONAL
