--[[
	Cache results of a function such that subsequent calls return the cached result rather than
	call the function again.

	By default, a cached result is stored for each separate combination of serialized input args.
	Optionally memoize takes a serializeArgs function which should return a key that the result
	should be cached with for a given call signature. Return nil to avoid caching the result.
]]

function FunctionUtils.memoize(fn, serializeArgs)
	assert(type(fn) == "function")
	serializeArgs = serializeArgs or FunctionUtils.defaultSerializeArgs
	assert(type(serializeArgs) == "function")
	local cache = {}
	local proxyFunction = function(...)
		local proxyArgs = {...}
		local cacheKey = serializeArgs(proxyArgs)
		if cacheKey == nil then
			return fn(...)
		else
			if cache[cacheKey] == nil then
				cache[cacheKey] = fn(...)
			end
			return cache[cacheKey]
		end
	end
	return proxyFunction
end

function FunctionUtils.setTimeout(fn, secondsDelay)
	local cleared = false
	local timeout
	delay(
		secondsDelay,
		function()
			if not cleared then
				fn(timeout)
			end
		end
	)
	timeout = {
		clear = function()
			cleared = true
		end
	}
	return timeout
end

function FunctionUtils.setInterval(fn, secondsDelay)
	local timeout
	local callTimeout
	callTimeout = function()
		timeout =
			FunctionUtils.setTimeout(
			function()
				callTimeout()
				fn(timeout)
			end,
			secondsDelay
		)
	end
	callTimeout()

	return {
		clear = function()
			timeout:clear()
		end
	}
end
