local T={}function T.isValueBase(T)return typeof(T)=="\073\110\115\116\097\110\099\101"and T.ClassName:sub(-5)=="\086\097\108\117\101"end function T.getOrCreateValue(T,S,v,t)assert(typeof(T)=="\073\110\115\116\097\110\099\101","\066\097\100 \097\114\103\117\109\101\110\116 \'\112\097\114\101\110\116\'")assert(type(S)=="\115\116\114\105\110\103","\066\097\100 \097\114\103\117\109\101\110\116 \'\105\110\115\116\097\110\099\101\084\121\112\101\'")assert(type(v)=="\115\116\114\105\110\103","\066\097\100 \097\114\103\117\109\101\110\116 \'\110\097\109\101\'")local a=T:FindFirstChild(v)if a then if not a:IsA(S)then warn(("\091\086\097\108\117\101\066\097\115\101\085\116\105\108\115\046\103\101\116\079\114\067\114\101\097\116\101\086\097\108\117\101\093 - \086\097\108\117\101 \111\102 \116\121\112\101 \037\113 \111\102 \110\097\109\101 \037\113 \105\115 \111\102 \116\121\112\101 \037\113 \105\110 \037\115 \105\110\115\116\101\097\100"):format(S,v,a.ClassName,a:GetFullName()))end return a else local a=Instance.new(S)a.Name=v a.Value=t a.Parent=T return a end end function T.setValue(T,S,v,t)assert(typeof(T)=="\073\110\115\116\097\110\099\101","\066\097\100 \097\114\103\117\109\101\110\116 \'\112\097\114\101\110\116\'")assert(type(S)=="\115\116\114\105\110\103","\066\097\100 \097\114\103\117\109\101\110\116 \'\105\110\115\116\097\110\099\101\084\121\112\101\'")assert(type(v)=="\115\116\114\105\110\103","\066\097\100 \097\114\103\117\109\101\110\116 \'\110\097\109\101\'")local a=T:FindFirstChild(v)if a then if not a:IsA(S)then warn(("\091\086\097\108\117\101\066\097\115\101\085\116\105\108\115\046\115\101\116\086\097\108\117\101\093 - \086\097\108\117\101 \111\102 \116\121\112\101 \037\113 \111\102 \110\097\109\101 \037\113 \105\115 \111\102 \116\121\112\101 \037\113 \105\110 \037\115 \105\110\115\116\101\097\100"):format(S,v,a.ClassName,a:GetFullName()))end a.Value=t else local a=Instance.new(S)a.Name=v a.Value=t a.Parent=T end end function T.getValue(T,S,v,t)assert(typeof(T)=="\073\110\115\116\097\110\099\101","\066\097\100 \097\114\103\117\109\101\110\116 \'\112\097\114\101\110\116\'")assert(type(S)=="\115\116\114\105\110\103","\066\097\100 \097\114\103\117\109\101\110\116 \'\105\110\115\116\097\110\099\101\084\121\112\101\'")assert(type(v)=="\115\116\114\105\110\103","\066\097\100 \097\114\103\117\109\101\110\116 \'\110\097\109\101\'")local a=T:FindFirstChild(v)if a then if a:IsA(S)then return a.Value else warn(("\091\086\097\108\117\101\066\097\115\101\085\116\105\108\115\046\103\101\116\086\097\108\117\101\093 - \086\097\108\117\101 \111\102 \116\121\112\101 \037\113 \111\102 \110\097\109\101 \037\113 \105\115 \111\102 \116\121\112\101 \037\113 \105\110 \037\115 \105\110\115\116\101\097\100"):format(S,v,a.ClassName,a:GetFullName()))return nil end else return t end end function T.createGetSet(S,v)assert(type(S)=="\115\116\114\105\110\103","\066\097\100 \097\114\103\117\109\101\110\116 \'\105\110\115\116\097\110\099\101\084\121\112\101\'")assert(type(v)=="\115\116\114\105\110\103","\066\097\100 \097\114\103\117\109\101\110\116 \'\110\097\109\101\'")return function(t,a)assert(typeof(t)=="\073\110\115\116\097\110\099\101","\066\097\100 \097\114\103\117\109\101\110\116 \'\112\097\114\101\110\116\'")return T.getValue(t,S,v,a)end,function(t,a)assert(typeof(t)=="\073\110\115\116\097\110\099\101","\066\097\100 \097\114\103\117\109\101\110\116 \'\112\097\114\101\110\116\'")return T.setValue(t,S,v,a)end,function(t,a)return T.getOrCreateValue(t,S,v,a)end end return T


local ValueBaseUtils = {}

function ValueBaseUtils.isValueBase(instance)
	return typeof(instance) == "Instance" and instance.ClassName:sub(-#"Value") == "Value"
end

function ValueBaseUtils.getOrCreateValue(parent, instanceType, name, defaultValue)
	assert(typeof(parent) == "Instance", "Bad argument 'parent'")
	assert(type(instanceType) == "string", "Bad argument 'instanceType'")
	assert(type(name) == "string", "Bad argument 'name'")

	local foundChild = parent:FindFirstChild(name)
	if foundChild then
		if not foundChild:IsA(instanceType) then
			warn(("[ValueBaseUtils.getOrCreateValue] - Value of type %q of name %q is of type %q in %s instead")
				:format(instanceType, name, foundChild.ClassName, foundChild:GetFullName()))
		end

		return foundChild
	else
		local newChild = Instance.new(instanceType)
		newChild.Name = name
		newChild.Value = defaultValue
		newChild.Parent = parent

		return newChild
	end
end

function ValueBaseUtils.setValue(parent, instanceType, name, value)
	assert(typeof(parent) == "Instance", "Bad argument 'parent'")
	assert(type(instanceType) == "string", "Bad argument 'instanceType'")
	assert(type(name) == "string", "Bad argument 'name'")

	local foundChild = parent:FindFirstChild(name)
	if foundChild then
		if not foundChild:IsA(instanceType) then
			warn(("[ValueBaseUtils.setValue] - Value of type %q of name %q is of type %q in %s instead")
				:format(instanceType, name, foundChild.ClassName, foundChild:GetFullName()))
		end

		foundChild.Value = value
	else
		local newChild = Instance.new(instanceType)
		newChild.Name = name
		newChild.Value = value
		newChild.Parent = parent
	end
end

function ValueBaseUtils.getValue(parent, instanceType, name, default)
	assert(typeof(parent) == "Instance", "Bad argument 'parent'")
	assert(type(instanceType) == "string", "Bad argument 'instanceType'")
	assert(type(name) == "string", "Bad argument 'name'")

	local foundChild = parent:FindFirstChild(name)
	if foundChild then
		if foundChild:IsA(instanceType) then
			return foundChild.Value
		else
			warn(("[ValueBaseUtils.getValue] - Value of type %q of name %q is of type %q in %s instead")
				:format(instanceType, name, foundChild.ClassName, foundChild:GetFullName()))
			return nil
		end
	else
		return default
	end
end

function ValueBaseUtils.createGetSet(instanceType, name)
	assert(type(instanceType) == "string", "Bad argument 'instanceType'")
	assert(type(name) == "string", "Bad argument 'name'")

	return function(parent, defaultValue)
		assert(typeof(parent) == "Instance", "Bad argument 'parent'")

		return ValueBaseUtils.getValue(parent, instanceType, name, defaultValue)
	end, function(parent, value)
		assert(typeof(parent) == "Instance", "Bad argument 'parent'")

		return ValueBaseUtils.setValue(parent, instanceType, name, value)
	end, function(parent, defaultValue)
		return ValueBaseUtils.getOrCreateValue(parent, instanceType, name, defaultValue)
	end
end

return ValueBaseUtils
