------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


function Datastore.Get(datastore, key, scope)
	--- Sanity check
	if key == nil or datastore == nil then
		print("Key or datastore nil", true)
		return
	end

	--- If datastore argument is not a datastore obj - find it, and cache it to save memory
	if type(datastore) == "string" then
		if not datastoresCache[datastore] then
			datastoresCache[datastore] = {}
		end
		if not datastoresCache[datastore][scope] then
			datastoresCache[datastore][scope] = _L.DataStoreService:GetDataStore(datastore, scope)
		end
		datastore = datastoresCache[datastore][scope]
	end

	--- Attempt it
	local attempts = 0
	local success = false
	local returnedValue
	--
	while (attempts < maxGetAttempts and returnedValue == nil) do
		attempts = attempts + 1
		success = pcall(function()
			returnedValue = datastore:GetAsync(key)
		end)
		if not success then
			wait(.5)
		end
	end

	--- Debug prints
	if Debug then
		if attempts >= maxGetAttempts or returnedValue == nil then
			print("Could not get key --- " .. key .. "", true)
		end
	end

	--
	return returnedValue, success
end


function Datastore.Set(datastore, key, value, scope)
	--- Sanity check
	if key == nil or value == nil or datastore == nil then
		print("Key, value, or datastore nil", true)
		return false
	end

	--- If datastore argument is not a datastore obj - find it, and cache it to save memory
	if type(datastore) == "string" then
		if not datastoresCache[datastore] then
			datastoresCache[datastore] = {}
		end
		if not datastoresCache[datastore][scope] then
			datastoresCache[datastore][scope] = _L.DataStoreService:GetDataStore(datastore, scope)
		end
		datastore = datastoresCache[datastore][scope]
	end

	--- Attempt it
	local attempts = 0
	local success = false
	--
	repeat
		attempts = attempts + 1
		success = pcall(function()
			datastore:SetAsync(key, value)
		end)
		if not success then
			wait(.5)
		end
	until success or attempts >= maxSetAttempts

	--- Debug prints
	if Debug then
		if attempts >= maxSetAttempts then
			print("Failed to set key --- " .. key .. "", true)
		end
	end

	--
	return success
end


function Datastore.Update(datastore, key, updateFunction, scope)
	--- Sanity check
	if key == nil or updateFunction == nil or datastore == nil then
		print("Key, function, or datastore nil", true)
		return false
	end

	--- If datastore argument is not a datastore obj - find it, and cache it to save memory
	if type(datastore) == "string" then
		if not datastoresCache[datastore] then
			datastoresCache[datastore] = {}
		end
		if not datastoresCache[datastore][scope] then
			datastoresCache[datastore][scope] = _L.DataStoreService:GetDataStore(datastore, scope)
		end
		datastore = datastoresCache[datastore][scope]
	end

	--- Attempt it
	local attempts = 0
	local success = false
	--
	repeat
		attempts = attempts + 1
		success = pcall(function()
			datastore:UpdateAsync(key, updateFunction)
		end)
		if not success then
			wait(.5)
		end
	until success or attempts >= maxUpdateAttempts

	--- Debug prints
	if Debug then
		if attempts >= maxUpdateAttempts then
			print("Failed to update key --- " .. key .. "", true)
		end
	end

	--
	return success
end