local X=require(script.Parent.Promise)local Y={}Y.ClassName="\077\097\105\100"function Y.new()local X=setmetatable({_tasks={}},Y)return X end function Y.__index(w,X)if Y[X]then return Y[X]else return w._tasks[X]end end function Y.__newindex(e,w,A)if Y[w]~=nil then error(("\'\037\115\' \105\115 \114\101\115\101\114\118\101\100"):format(tostring(w)),2)end local J=e._tasks local P=J[w]J[w]=A if P then if type(P)=="\102\117\110\099\116\105\111\110"then P()elseif typeof(P)=="\082\066\088\083\099\114\105\112\116\067\111\110\110\101\099\116\105\111\110"then P:Disconnect()elseif P.Destroy then P:Destroy()elseif X.Is(P)then P:Cancel()end end end function Y.GiveTask(w,Y)assert(Y,"\084\097\115\107 \099\097\110\110\111\116 \098\101 \102\097\108\115\101 \111\114 \110\105\108")local A=#w._tasks+1 w[A]=Y if type(Y)=="\116\097\098\108\101"and(not Y.Destroy and not X.Is(Y))then warn("\091\077\097\105\100\046\071\105\118\101\084\097\115\107\093 - \071\097\118\101 \116\097\098\108\101 \116\097\115\107 \119\105\116\104\111\117\116 \046\068\101\115\116\114\111\121\n\n"..debug.traceback())end return A end function Y.GivePromise(w,Y)assert(X.Is(Y),"\069\120\112\101\099\116\101\100 \112\114\111\109\105\115\101")if Y:GetStatus()~=X.Status.Started then return Y end local A=X.Resolve(Y)local e=w:GiveTask(A)A:Finally(function()w[e]=nil end)return A end function Y.DoCleaning(Y)local w=Y._tasks for X,Y in pairs(w)do if typeof(Y)=="\082\066\088\083\099\114\105\112\116\067\111\110\110\101\099\116\105\111\110"then w[X]=nil Y:Disconnect()end end local A,e=next(w)while e~=nil do w[A]=nil if type(e)=="\102\117\110\099\116\105\111\110"then e()elseif typeof(e)=="\082\066\088\083\099\114\105\112\116\067\111\110\110\101\099\116\105\111\110"then e:Disconnect()elseif e.Destroy then e:Destroy()elseif X.Is(e)then e:Cancel()end A,e=next(w)end end Y.Destroy=Y.DoCleaning return Y
-- Maid
-- Author: Quenty
-- Source: https://github.com/Quenty/NevermoreEngine/blob/version2/Modules/Shared/Events/Maid.lua
-- License: MIT (https://github.com/Quenty/NevermoreEngine/blob/version2/LICENSE.md)
-- This module has been modified for use in AeroGameFramework

--[[

	maid = Maid.new()

	maid:GiveTask(task)
		> task is an event connection, function, or instance/table with a 'Destroy' method

	maid:GivePromise(promise)
		> Give the maid a promise as a task, which will call 'promise:Cancel()' on cleanup

	maid:DoCleaning()
		> Alias for Destroy

	maid:Destroy()
		> Goes through each task & disconnects events, destroys instances, and calls functions

--]]

local Promise = require(script.Parent.Promise)


local Maid = {}
Maid.ClassName = "Maid"


function Maid.new()
	local self = setmetatable({
		_tasks = {};
	}, Maid)
	return self
end


--- Returns Maid[key] if not part of Maid metatable
-- @return Maid[key] value
function Maid:__index(index)
	if (Maid[index]) then
		return Maid[index]
	else
		return self._tasks[index]
	end
end


--- Add a task to clean up
-- @usage
-- Maid[key] = (function)         Adds a task to perform
-- Maid[key] = (event connection) Manages an event connection
-- Maid[key] = (Maid)             Maids can act as an event connection, allowing a Maid to have other maids to clean up.
-- Maid[key] = (Object)           Maids can cleanup objects with a `Destroy` method
-- Maid[key] = nil                Removes a named task. If the task is an event, it is disconnected. If it is an object,
--                                it is destroyed.
function Maid:__newindex(index, newTask)
	if (Maid[index] ~= nil) then
		error(("'%s' is reserved"):format(tostring(index)), 2)
	end

	local tasks = self._tasks
	local oldTask = tasks[index]
	tasks[index] = newTask

	if (oldTask) then
		if (type(oldTask) == "function") then
			oldTask()
		elseif (typeof(oldTask) == "RBXScriptConnection") then
			oldTask:Disconnect()
		elseif (oldTask.Destroy) then
			oldTask:Destroy()
		elseif (Promise.Is(oldTask)) then
			oldTask:Cancel()
		end
	end
end


--- Same as indexing, but uses an incremented number as a key.
-- @param task An item to clean
-- @treturn number taskId
function Maid:GiveTask(task)
	assert(task, "Task cannot be false or nil")

	local taskId = (#self._tasks + 1)
	self[taskId] = task

	if (type(task) == "table" and (not task.Destroy) and (not Promise.Is(task))) then
		warn("[Maid.GiveTask] - Gave table task without .Destroy\n\n" .. debug.traceback())
	end

	return taskId
end


function Maid:GivePromise(promise)
	assert(Promise.Is(promise), "Expected promise")
	if (promise:GetStatus() ~= Promise.Status.Started) then
		return promise
	end
	local newPromise = Promise.Resolve(promise)
	local id = self:GiveTask(newPromise)
	newPromise:Finally(function()
		self[id] = nil
	end)
	return newPromise
end


--- Cleans up all tasks.
-- @alias Destroy
function Maid:DoCleaning()
	local tasks = self._tasks

	-- Disconnect all events first as we know this is safe
	for index, task in pairs(tasks) do
		if (typeof(task) == "RBXScriptConnection") then
			tasks[index] = nil
			task:Disconnect()
		end
	end

	-- Clear out tasks table completely, even if clean up tasks add more tasks to the maid
	local index, task = next(tasks)
	while (task ~= nil) do
		tasks[index] = nil
		if (type(task) == "function") then
			task()
		elseif (typeof(task) == "RBXScriptConnection") then
			task:Disconnect()
		elseif (task.Destroy) then
			task:Destroy()
		elseif (Promise.Is(task)) then
			task:Cancel()
		end
		index, task = next(tasks)
	end
end


--- Alias for DoCleaning()
-- @function Destroy
Maid.Destroy = Maid.DoCleaning

return Maid