--[[
	A limited, simple implementation of a Signal.

	Handlers are fired in order, and (dis)connections are properly handled when
	executing an event.

	Signal uses Immutable to avoid invalidating the 'Fire' loop iteration.
]]

local Immutable = require(script.Parent.Immutable)

local Signal = {}

Signal.__index = Signal

function Signal.new()
	local self = {
		_listeners = {}
	}

	setmetatable(self, Signal)

	return self
end

function Signal:connect(callback)
	local listener = {
		callback = callback,
		isConnected = true,
	}
	self._listeners = Immutable.Append(self._listeners, listener)

	local function disconnect()
		listener.isConnected = false
		self._listeners = Immutable.RemoveValueFromList(self._listeners, listener)
	end

	return {
		Disconnect = function()
			warn(string.format(
				"Connection:Disconnect() has been deprecated, use Connection:disconnect()\n%s]",
				debug.traceback()
			))
			disconnect()
		end,
		disconnect = disconnect,
	}
end

function Signal:fire(...)
	for _, listener in ipairs(self._listeners) do
		if listener.isConnected then
			listener.callback(...)
		end
	end
end

function Signal:Connect(...)
	warn(string.format(
		"Signal:Connect() has been deprecated, use Signal:connect()\n%s]",
		debug.traceback()
	))
	return self:connect(...)
end

function Signal:Fire(...)
	warn(string.format(
		"Signal:Fire() has been deprecated, use Signal:fire()\n%s]",
		debug.traceback()
	))
	self:fire(...)
end


return Signal