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


function Datastore.Get(datastore, key, scope)
	--- Sanity check
	if key == nil or datastore == nil then
		_L.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.Services.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
			_L.Print("Could not get key --- [bold]" .. key .. "[/bold]", 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
		_L.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.Services.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
			_L.Print("Failed to set key --- [bold]" .. key .. "[/bold]", 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
		_L.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.Services.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
			_L.Print("Failed to update key --- [bold]" .. key .. "[/bold]", true)
		end
	end
	
	--
	return success
end