local function T(T,G,o,H,y,R)for T,f in pairs(T)do if type(T)~="\115\116\114\105\110\103"then o(("\037\115\058 \105\103\110\111\114\101\100 \037\115 \062 \037\113 \040\110\097\109\101 \105\115 \110\111\116 \097 \115\116\114\105\110\103\044 \098\117\116 \097 \037\115\041"):format(H,y,tostring(T),typeof(T)))elseif type(f)~="\116\097\098\108\101"then o(("\037\115\058 \105\103\110\111\114\101\100 \037\115 \062 \037\113 \040\115\099\111\112\101 \108\105\115\116 \105\115 \110\111\116 \097 \116\097\098\108\101\044 \098\117\116 \097 \037\115\041"):format(H,y,T,typeof(f)))elseif#T==0 then o(("\037\115\058 \105\103\110\111\114\101\100 \037\115 \062 \037\113 \040\110\097\109\101 \105\115 \097\110 \101\109\112\116\121 \115\116\114\105\110\103\041"):format(H,y,T))elseif#T>Constants.MAX_LENGTH_NAME then o(("\037\115\058 \105\103\110\111\114\101\100 \037\115 \062 \037\113 \040\110\097\109\101 \101\120\099\101\101\100\115 \037\100 \099\104\097\114\097\099\116\101\114 \108\105\109\105\116\041"):format(H,y,T,Constants.MAX_LENGTH_NAME))else for f,N in pairs(f)do if type(f)~="\115\116\114\105\110\103"then o(("\037\115\058 \105\103\110\111\114\101\100 \037\115 \062 \037\113 \062 \037\113 \040\115\099\111\112\101 \105\115 \110\111\116 \097 \115\116\114\105\110\103\044 \098\117\116 \097 \037\115\041"):format(H,y,T,tostring(f),typeof(f)))elseif type(N)~="\116\097\098\108\101"then o(("\037\115\058 \105\103\110\111\114\101\100 \037\115 \062 \037\113 \062 \037\113 \040\100\097\116\097 \108\105\115\116 \105\115 \110\111\116 \097 \116\097\098\108\101\044 \098\117\116 \097 \037\115\041"):format(H,y,T,f,typeof(N)))elseif#f==0 then o(("\037\115\058 \105\103\110\111\114\101\100 \037\115 \062 \037\113 \062 \037\113 \040\115\099\111\112\101 \105\115 \097\110 \101\109\112\116\121 \115\116\114\105\110\103\041"):format(H,y,T,f))elseif#f>Constants.MAX_LENGTH_SCOPE then o(("\037\115\058 \105\103\110\111\114\101\100 \037\115 \062 \037\113 \062 \037\113 \040\115\099\111\112\101 \101\120\099\101\101\100\115 \037\100 \099\104\097\114\097\099\116\101\114 \108\105\109\105\116\041"):format(H,y,T,f,Constants.MAX_LENGTH_SCOPE))else if not G[T]then G[T]={}end if not G[T][f]then G[T][f]={}end Utils.importPairsFromTable(N,G[T][f],Interfaces[G[T][f]],o,H,("\037\115 \062 \037\113 \062 \037\113"):format(y,T,f),R)end end end end end function MockDataStoreManager.ImportFromJSON(G,o)assert(type(G)=="\116\097\098\108\101")assert(o==nil or type(o)=="\098\111\111\108\101\097\110")local H=warn if o==false then H=function() end end if type(G.GlobalDataStore)=="\116\097\098\108\101"then Utils.importPairsFromTable(G.GlobalDataStore,Data.GlobalDataStore,Interfaces[Data.GlobalDataStore],H,"\073\109\112\111\114\116\070\114\111\109\074\083\079\078","\071\108\111\098\097\108\068\097\116\097\083\116\111\114\101",false)end if type(G.DataStore)=="\116\097\098\108\101"then T(G.DataStore,Data.DataStore,H,"\073\109\112\111\114\116\070\114\111\109\074\083\079\078","\068\097\116\097\083\116\111\114\101",false)end if type(G.OrderedDataStore)=="\116\097\098\108\101"then T(G.OrderedDataStore,Data.OrderedDataStore,H,"\073\109\112\111\114\116\070\114\111\109\074\083\079\078","\079\114\100\101\114\101\100\068\097\116\097\083\116\111\114\101",true)end end local function G(T)for G,o in pairs(T)do T[G]=nil end end function MockDataStoreManager.ResetData()for T,G in pairs(Interfaces)do for T,o in pairs(G.__data)do G.__data[T]=nil G.__event:Fire(T,nil)end G.__getCache={}G.__writeCache={}G.__writeLock={}if G.__sorted then G.__sorted={}G.__ref={}G.__changed=false end end G(Data.GlobalDataStore)for T,o in pairs(Data.DataStore)do for T,o in pairs(o)do G(o)end end for T,o in pairs(Data.OrderedDataStore)do for T,o in pairs(o)do G(o)end end end return MockDataStoreManager

local function importDataStoresFromTable(origin, destination, warnFunc, methodName, prefix, isOrdered)
	for name, scopes in pairs(origin) do
		if type(name) ~= "string" then
			warnFunc(("%s: ignored %s > %q (name is not a string, but a %s)")
				:format(methodName, prefix, tostring(name), typeof(name)))
		elseif type(scopes) ~= "table" then
			warnFunc(("%s: ignored %s > %q (scope list is not a table, but a %s)")
				:format(methodName, prefix, name, typeof(scopes)))
		elseif #name == 0 then
			warnFunc(("%s: ignored %s > %q (name is an empty string)")
				:format(methodName, prefix, name))
		elseif #name > Constants.MAX_LENGTH_NAME then
			warnFunc(("%s: ignored %s > %q (name exceeds %d character limit)")
				:format(methodName, prefix, name, Constants.MAX_LENGTH_NAME))
		else
			for scope, data in pairs(scopes) do
				if type(scope) ~= "string" then
					warnFunc(("%s: ignored %s > %q > %q (scope is not a string, but a %s)")
						:format(methodName, prefix, name, tostring(scope), typeof(scope)))
				elseif type(data) ~= "table" then
					warnFunc(("%s: ignored %s > %q > %q (data list is not a table, but a %s)")
						:format(methodName, prefix, name, scope, typeof(data)))
				elseif #scope == 0 then
					warnFunc(("%s: ignored %s > %q > %q (scope is an empty string)")
						:format(methodName, prefix, name, scope))
				elseif #scope > Constants.MAX_LENGTH_SCOPE then
					warnFunc(("%s: ignored %s > %q > %q (scope exceeds %d character limit)")
						:format(methodName, prefix, name, scope, Constants.MAX_LENGTH_SCOPE))
				else
					if not destination[name] then
						destination[name] = {}
					end
					if not destination[name][scope] then
						destination[name][scope] = {}
					end
					Utils.importPairsFromTable(
						data,
						destination[name][scope],
						Interfaces[destination[name][scope]],
						warnFunc,
						methodName,
						("%s > %q > %q"):format(prefix, name, scope),
						isOrdered
					)
				end
			end
		end
	end
end

function MockDataStoreManager.ImportFromJSON(content, verbose)
	assert(type(content) == "table")
	assert(verbose == nil or type(verbose) == "boolean")

	local warnFunc = warn -- assume verbose as default
	if verbose == false then -- intentional formatting
		warnFunc = function() end
	end

	if type(content.GlobalDataStore) == "table" then
		Utils.importPairsFromTable(
			content.GlobalDataStore,
			Data.GlobalDataStore,
			Interfaces[Data.GlobalDataStore],
			warnFunc,
			"ImportFromJSON",
			"GlobalDataStore",
			false
		)
	end
	if type(content.DataStore) == "table" then
		importDataStoresFromTable(
			content.DataStore,
			Data.DataStore,
			warnFunc,
			"ImportFromJSON",
			"DataStore",
			false
		)
	end
	if type(content.OrderedDataStore) == "table" then
		importDataStoresFromTable(
			content.OrderedDataStore,
			Data.OrderedDataStore,
			warnFunc,
			"ImportFromJSON",
			"OrderedDataStore",
			true
		)
	end
end

local function clearTable(t)
	for i,_ in pairs(t) do
		t[i] = nil
	end
end

function MockDataStoreManager.ResetData()
	for _, interface in pairs(Interfaces) do
		for key, _ in pairs(interface.__data) do
			interface.__data[key] = nil
			interface.__event:Fire(key, nil)
		end
		interface.__getCache = {}
		interface.__writeCache = {}
		interface.__writeLock = {}
		if interface.__sorted then
			interface.__sorted = {};
            interface.__ref = {};
            interface.__changed = false;
		end
	end

	clearTable(Data.GlobalDataStore)

	for _, scopes in pairs(Data.DataStore) do
		for _, data in pairs(scopes) do
			clearTable(data)
		end
	end

	for _, scopes in pairs(Data.OrderedDataStore) do
		for _, data in pairs(scopes) do
			clearTable(data)
		end
	end
end

return MockDataStoreManager
