-- METHODS

function Tracker:_preventMultiFrameUpdates(methodName, ...)
	-- This prevents the funtion being called twice within a single frame
	-- If called more than once, the function will initally be delayed again until the next frame, then all others cancelled
	self._preventMultiDetails = self._preventMultiDetails or {}
	local detail = self._preventMultiDetails[methodName]
	if not detail then
		detail = {
			calling = false,
			callsThisFrame = 0,
			updatedThisFrame = false,
		}
		self._preventMultiDetails[methodName] = detail
	end

	detail.callsThisFrame += 1
	if detail.callsThisFrame == 1 then
		local args = table.pack(...)
		task.defer(function()
			local newCallsThisFrame = detail.callsThisFrame
			detail.callsThisFrame = 0
			if newCallsThisFrame > 1 then
				self[methodName](self, unpack(args))
			end
		end)
		return false
	end
	return true
end

function Tracker:update()
	if self:_preventMultiFrameUpdates("update") then
		return
	end
	
	self.totalVolume = 0
	self.parts = {}
	self.partToItem = {}
	self.items = {}
	
	-- This tracks the bodyparts of a character
	for character, _ in pairs(self.characters) do
		local charSize = Tracker.getCharacterSize(character)
		if not charSize then
			continue
		end
		local rSize = charSize
		local charVolume = rSize.X*rSize.Y*rSize.Z
		self.totalVolume += charVolume
		
		local characterJanitor = self.janitor:add(Janitor.new(), "destroy", "trackCharacterParts-"..self.name)
		local function updateTrackerOnParentChanged(instance)
			characterJanitor:add(instance.AncestryChanged:Connect(function()
				if not instance:IsDescendantOf(game) then
					if instance.Parent == nil and characterJanitor ~= nil then
						characterJanitor:destroy()
						characterJanitor = nil
						self:update()
					end
				end
			end), "Disconnect")
		end

		for _, part in pairs(character:GetChildren()) do
			if part:IsA("BasePart") and not Tracker.bodyPartsToIgnore[part.Name] then
				self.partToItem[part] = character
				table.insert(self.parts, part)
				updateTrackerOnParentChanged(part)
			end
		end
		updateTrackerOnParentChanged(character)
		table.insert(self.items, character)
	end

	-- This tracks any additional baseParts
	for additionalPart, _ in pairs(self.baseParts) do
		local rSize = additionalPart.Size
		local partVolume = rSize.X*rSize.Y*rSize.Z
		self.totalVolume += partVolume
		self.partToItem[additionalPart] = additionalPart
		table.insert(self.parts, additionalPart)
		table.insert(self.items, additionalPart)
	end
	
	-- This creates the whitelist so that
	self.whitelistParams = OverlapParams.new()
	self.whitelistParams.FilterType = Enum.RaycastFilterType.Whitelist
	self.whitelistParams.MaxParts = #self.parts
	self.whitelistParams.FilterDescendantsInstances = self.parts
end



return Tracker
