local Y=require((game:GetService("\082\101\112\108\105\099\097\116\101\100\083\116\111\114\097\103\101")):WaitForChild("\078\101\118\101\114\109\111\114\101"))local w=Y("\066\097\115\101\079\098\106\101\099\116")local T=Y("\084\097\098\108\101")local t=Y("\068\097\116\097\083\116\111\114\101\087\114\105\116\101\114")local M=Y("\068\097\116\097\083\116\111\114\101\068\101\108\101\116\101\084\111\107\101\110")local p=setmetatable({},w)p.ClassName="\068\097\116\097\083\116\111\114\101\083\116\097\103\101"p.__index=p function p.new(Y,T)local t=setmetatable(w.new(),p)t._loadName=Y t._loadParent=T t._takenKeys={}t._stores={}return t end function p.Load(T,Y,w)if not T._loadParent then error("\091\068\097\116\097\083\116\111\114\101\083\116\097\103\101\046\076\111\097\100\093 - \070\097\105\108\101\100 \116\111 \108\111\097\100\044 \110\111 \108\111\097\100\080\097\114\101\110\116\033")end if not T._loadName then error("\091\068\097\116\097\083\116\111\114\101\083\116\097\103\101\046\076\111\097\100\093 - \070\097\105\108\101\100 \116\111 \108\111\097\100\044 \110\111 \108\111\097\100\078\097\109\101\033")end return(T._loadParent:Load(T._loadName,{})):Then(function(T)if T[Y]==nil then return w else return T[Y]end end)end function p.Delete(w,Y)if w._takenKeys[Y]then error(("\091\068\097\116\097\083\116\111\114\101\083\116\097\103\101\093 - \065\108\114\101\097\100\121 \104\097\118\101 \097 \119\114\105\116\101\114 \102\111\114 \037\113"):format(Y))end w:_doStore(Y,nil)end function p.Store(T,Y,w)if T._takenKeys[Y]then error(("\091\068\097\116\097\083\116\111\114\101\083\116\097\103\101\093 - \065\108\114\101\097\100\121 \104\097\118\101 \097 \119\114\105\116\101\114 \102\111\114 \037\113"):format(Y))end if w==nil then w=M end T:_doStore(Y,w)end function p.GetSubStore(w,Y)assert(type(Y)=="\115\116\114\105\110\103")if w._stores[Y]then return w._stores[Y]end if w._takenKeys[Y]then error(("\091\068\097\116\097\083\116\111\114\101\083\116\097\103\101\046\071\101\116\083\117\098\083\116\111\114\101\093 - \065\108\114\101\097\100\121 \104\097\118\101 \097 \119\114\105\116\101\114 \102\111\114 \037\113"):format(Y))end local T=p.new(Y,w)w._takenKeys[Y]=true w._maid:GiveTask(T)w._stores[Y]=T return T end function p.StoreOnValueChange(T,Y,w)assert(type(Y)=="\115\116\114\105\110\103")assert(typeof(w)=="\073\110\115\116\097\110\099\101")if T._takenKeys[Y]then error(("\091\068\097\116\097\083\116\111\114\101\083\116\097\103\101\093 - \065\108\114\101\097\100\121 \104\097\118\101 \097 \119\114\105\116\101\114 \102\111\114 \037\113"):format(Y))end T._takenKeys[Y]=true local t=w.Changed:Connect(function()T:_doStore(Y,w.Value)end)T._maid:GiveTask(t)return t end function p.HasWritableData(Y)if Y._dataToSave then return true end for Y,w in pairs(Y._stores)do if w:HasWritableData()then return true end end return false end function p.GetNewWriter(Y)local w=t.new()if Y._dataToSave then w:SetRawData(Y._dataToSave)end for Y,T in pairs(Y._stores)do if T:HasWritableData()then w:AddWriter(Y,T:GetNewWriter())end end return w end function p._doStore(t,Y,w)assert(type(Y)=="\115\116\114\105\110\103")assert(w~=nil)local p if w==M then p=M elseif type(w)=="\084\097\098\108\101"then p=T.DeepCopy(w)else p=w end if not t._dataToSave then t._dataToSave={}end t._dataToSave[Y]=p end return p
--- Provides a data storage facility with an ability to get sub-stores. So you can write
-- directly to this store, overwriting all children, or you can have more partial control
-- at children level. This minimizes accidently overwriting.
-- The big cost here is that we may leave keys that can't be removed.
-- @classmod DataStoreStage

local require = require(game:GetService("ReplicatedStorage"):WaitForChild("Nevermore"))

local BaseObject = require("BaseObject")
local Table = require("Table")
local DataStoreWriter = require("DataStoreWriter")
local DataStoreDeleteToken = require("DataStoreDeleteToken")

local DataStoreStage = setmetatable({}, BaseObject)
DataStoreStage.ClassName = "DataStoreStage"
DataStoreStage.__index = DataStoreStage

function DataStoreStage.new(loadName, loadParent)
	local self = setmetatable(BaseObject.new(), DataStoreStage)

	-- LoadParent is optional, used for loading
	self._loadName = loadName
	self._loadParent = loadParent

	self._takenKeys = {} -- [name] = true
	self._stores = {}

	return self
end

function DataStoreStage:Load(name, defaultValue)
	if not self._loadParent then
		error("[DataStoreStage.Load] - Failed to load, no loadParent!")
	end
	if not self._loadName then
		error("[DataStoreStage.Load] - Failed to load, no loadName!")
	end

	return self._loadParent:Load(self._loadName, {}):Then(function(data)
		if data[name] == nil then
			return defaultValue
		else
			return data[name]
		end
	end)
end

function DataStoreStage:Delete(name)
	if self._takenKeys[name] then
		error(("[DataStoreStage] - Already have a writer for %q"):format(name))
	end

	self:_doStore(name, nil)
end

function DataStoreStage:Store(name, value)
	if self._takenKeys[name] then
		error(("[DataStoreStage] - Already have a writer for %q"):format(name))
	end

	if value == nil then
		value = DataStoreDeleteToken
	end

	self:_doStore(name, value)
end

function DataStoreStage:GetSubStore(name)
	assert(type(name) == "string")

	if self._stores[name] then
		return self._stores[name]
	end

	if self._takenKeys[name] then
		error(("[DataStoreStage.GetSubStore] - Already have a writer for %q"):format(name))
	end

	local newStore = DataStoreStage.new(name, self)
	self._takenKeys[name] = true
	self._maid:GiveTask(newStore)

	self._stores[name] = newStore

	return newStore
end

function DataStoreStage:StoreOnValueChange(name, valueObj)
	assert(type(name) == "string")
	assert(typeof(valueObj) == "Instance")

	if self._takenKeys[name] then
		error(("[DataStoreStage] - Already have a writer for %q"):format(name))
	end

	self._takenKeys[name] = true
	local conn = valueObj.Changed:Connect(function()
		self:_doStore(name, valueObj.Value)
	end)
	self._maid:GiveTask(conn)
	return conn
end

function DataStoreStage:HasWritableData()
	if self._dataToSave then
		return true
	end

	for _, value in pairs(self._stores) do
		if value:HasWritableData() then
			return true
		end
	end

	return false
end

--- Constructs a writer which provides a snapshot of the current data state to write
function DataStoreStage:GetNewWriter()
	local writer = DataStoreWriter.new()
	if self._dataToSave then
		writer:SetRawData(self._dataToSave)
	end

	for name, store in pairs(self._stores) do
		if store:HasWritableData() then
			writer:AddWriter(name, store:GetNewWriter())
		end
	end

	return writer
end

-- Stores the data for overwrite.
function DataStoreStage:_doStore(name, value)
	assert(type(name) == "string")
	assert(value ~= nil)

	local newValue
	if value == DataStoreDeleteToken then
		newValue = DataStoreDeleteToken
	elseif type(value) == "Table" then
		newValue = Table.DeepCopy(value)
	else
		newValue = value
	end

	if not self._dataToSave then
		self._dataToSave = {}
	end

	self._dataToSave[name] = newValue
end


return DataStoreStage