local L=require(script.Parent:WaitForChild("\084\121\112\101"))local C={}local function t(L,C)assert(type(C)=="\116\097\098\108\101","\086\097\108\117\101\115 \105\115 \110\111\116 \097 \116\097\098\108\101")for C,t in next,C do if type(C)=="\110\117\109\098\101\114"then t.Parent=L else L[C]=t end end return L end local function l(L,C)return t(Instance.new(L),C)end local g={StringValue=true;IntValue=true;NumberValue=true;BrickColorValue=true;BoolValue=true;Color3Value=true;Vector3Value=true,IntConstrainedValue=true}local function I(L)return g[L]end C.TypeIsAcceptable=I C.typeIsAcceptable=I local function R(L,C)local t=C:FindFirstChild(L)or l("\067\111\110\102\105\103\117\114\097\116\105\111\110",{Name=L;Parent=C,Archivable=true})return t end C.AddSubDataLayer=R C.addSubDataLayer=R local A={}setmetatable(A,{__mode="\107"})local function p(C)if A[C]then return A[C]else local l={}local function I(L)return C:FindFirstChild(L)end setmetatable(l,{__index=function(l,R)if not type(R)=="\115\116\114\105\110\103"then error("\079\110\108\121 \073\110\100\101\120\105\110\103 \119\105\116\104 \115\116\114\105\110\103\115 \105\115 \115\117\112\112\111\114\116\101\100 \119\105\116\104 \101\097\115\121\067\111\110\102\105\103\117\114\097\116\105\111\110",2)end local A=R:lower()if A=="\097\100\100"or A=="\097\100\100\118\097\108\117\101"then return function(L,l)local g if l and(l.Name and type(l.Name)=="\115\116\114\105\110\103")then g=I(l.Name)if g and g.ClassName~=L then g:Destroy()g=nil end else error("\091\069\097\115\121\067\111\110\102\105\103\117\114\097\116\105\111\110\093 - \078\111 \118\097\108\117\101\115 \114\101\099\101\105\118\101\100 \105\110 \116\104\101 \097\100\100 \109\101\116\104\111\100 \111\102 \101\097\115\121 \099\111\110\102\105\103\117\114\097\116\105\111\110\046 \080\108\101\097\115\101 \103\105\118\101 \097 \116\097\098\108\101 \111\102 \100\101\102\097\117\108\116 \112\114\111\112\101\114\116\105\101\115 \105\110\099\108\117\100\105\110\103 \116\104\101 \110\097\109\101\046 ",2)end if not g then local g=Instance.new(L)t(g,l)g.Parent=C end end elseif A=="\103\101\116"or A=="\103\101\116\118\097\108\117\101"then return function(L)return I(L)end elseif A=="\103\101\116\099\111\110\116\097\105\110\101\114"then return function(L)return I(L)end else local t=C:FindFirstChild(R)if t and g[t.ClassName]then return t.Value else error("\091\069\097\115\121\067\111\110\102\105\103\117\114\097\116\105\111\110\093 - "..(t and"\079\098\106\101\099\116 \'"..(R..("\' \119\097\115 \097 "..(L.getType(t).." \118\097\108\117\101\044 \097\110\100 \110\111\116 \097\099\099\101\112\116\097\098\108\101\044 \115\111 \110\111 \114\101\116\117\114\110 \119\097\115 \103\105\118\101\110")))or"\067\111\117\108\100 \110\111\116 \102\105\110\100 \079\098\106\101\099\116 \'"..(R.."\' \105\110 \116\104\101 \099\111\110\102\105\103\117\114\097\116\105\111\110")),2)end end end;__newindex=function(L,C,t)if type(C)=="\115\116\114\105\110\103"then local L=I(C)if L and g[L.ClassName]then L.Value=t else error("\091\069\097\115\121\067\111\110\102\105\103\117\114\097\116\105\111\110\093 - \086\097\108\117\101 \'"..(C.."\' \119\097\115 \110\111\116 \097\099\099\101\112\116\101\100\044 \111\114 \119\097\115\110\'\116 \105\110 \116\104\101 \099\111\110\102\105\103\117\114\097\116\105\111\110"),2)end else error("\091\069\097\115\121\067\111\110\102\105\103\117\114\097\116\105\111\110\093 - \073\110\100\101\120 \119\105\116\104 \097 \115\116\114\105\110\103")end end})A[C]=l return l end end C.Make=p C.MakeEasyConfiguration=p return C


local Type = require(script.Parent:WaitForChild("Type"))

local lib = {}

local function Modify(Instance, Values)
	-- Modifies an Instance by using a table.  

	assert(type(Values) == "table", "Values is not a table");

	for Index, Value in next, Values do
		if type(Index) == "number" then
			Value.Parent = Instance
		else
			Instance[Index] = Value
		end
	end
	return Instance
end

local function Make(ClassType, Properties)
	-- Using a syntax hack to create a nice way to Make new items.  

	return Modify(Instance.new(ClassType), Properties)
end

local AcceptableTypes = { -- Anything in here has a .Value property. 
	["StringValue"]         = true;
	["IntValue"]            = true;
	["NumberValue"]         = true;
	["BrickColorValue"]     = true;
	["BoolValue"]           = true;
	["Color3Value"]         = true;
	["Vector3Value"]        = true;
	["IntConstrainedValue"] = true;
}

local function TypeIsAcceptable(TypeName)
	return AcceptableTypes[TypeName]
end
lib.TypeIsAcceptable = TypeIsAcceptable;
lib.typeIsAcceptable = TypeIsAcceptable

local function AddSubDataLayer(DataName, Parent)
	-- For organization of data. Adds another configuration with the name "DataName", if one can't be found, and then returns it. 

	local DataContainer = Parent:FindFirstChild(DataName) or Make("Configuration", {
		Name = DataName;
		Parent = Parent;
		Archivable = true;
	})

	return DataContainer
end
lib.AddSubDataLayer = AddSubDataLayer
lib.addSubDataLayer = AddSubDataLayer

local EasyConfigCache = {}
setmetatable(EasyConfigCache, {__mode = "k"})

local function MakeEasyConfiguration(Configuration)
	if EasyConfigCache[Configuration] then
		return EasyConfigCache[Configuration]
	else
		local NewConfiguration = {}

		local function Get(ObjectName)
			return Configuration:FindFirstChild(ObjectName)
		end

		setmetatable(NewConfiguration, {
			__index = function(_, value)

				if not type(value) == "string" then
					error("Only Indexing with strings is supported with easyConfiguration", 2)
				end

				local loweredValue = value:lower()

				if loweredValue == "add" or loweredValue == "addvalue" then
					--[[ 
					So they can do stuff like... Config.AddValue('IntValue', {
						Name = "PizzaEaten"
						Value = 0;
					})

					--]]
					return function(valueType, values)
						local Object

						if values and values.Name and type(values.Name) == "string" then
							Object = Get(values.Name)
							if Object and Object.ClassName ~= valueType then
								--print("[EasyConfiguration] - Invalid class '"..Object.ClassName.."' in configuration, being replaced by new data '"..valueType.."'");
								Object:Destroy()
								Object = nil;
							end
						else
							error("[EasyConfiguration] - No values received in the add method of easy configuration. Please give a table of default properties including the name. ", 2)
						end

						if not Object then
							local newInstance = Instance.new(valueType)
							Modify(newInstance, values)
							newInstance.Parent = Configuration
						end
					end
				elseif loweredValue == "get" or loweredValue == "getvalue" then
					return function(name)
						return Get(name)
					end
				elseif loweredValue == "getcontainer" then
					return function(name)
						return Get(name)
					end
				else
					local Object = Configuration:FindFirstChild(value)
					if Object and AcceptableTypes[Object.ClassName] then
						return Object.Value
					else
						error("[EasyConfiguration] - " .. (Object and "Object '"..value.."' was a "..Type.getType(Object).." value, and not acceptable, so no return was given" or "Could not find Object '"..value.."' in the configuration"), 2)
					end
				end
			end;
			__newindex = function(_, value, newValue)
				if type(value) == "string" then
					local Object = Get(value)
					if Object and AcceptableTypes[Object.ClassName] then
						Object.Value = newValue;
					else
						error("[EasyConfiguration] - Value '" .. value .. "' was not accepted, or wasn't in the configuration", 2);
					end
				else
					error("[EasyConfiguration] - Index with a string")
				end
			end;
		})

		EasyConfigCache[Configuration] = NewConfiguration
		return NewConfiguration;
	end
end
lib.Make = MakeEasyConfiguration;
lib.MakeEasyConfiguration = MakeEasyConfiguration;

return lib
