local O={}for X in pairs(defaultConfig)do table.insert(O,X)end local X={}function X.new()local q={}q._currentConfig=setmetatable({},{__index=function(X,q)local P=("\073\110\118\097\108\105\100 \103\108\111\098\097\108 \099\111\110\102\105\103\117\114\097\116\105\111\110 \107\101\121 \037\113\046 \086\097\108\105\100 \099\111\110\102\105\103\117\114\097\116\105\111\110 \107\101\121\115 \097\114\101\058 \037\115"):format(tostring(q),table.concat(O,"\044 "))error(P,3)end})q.set=function(...)return X.set(q,...)end q.get=function(...)return X.get(q,...)end q.scoped=function(...)return X.scoped(q,...)end q.set(defaultConfig)return q end function X.set(q,X)for X,P in pairs(X)do if defaultConfig[X]==nil then local q=("\073\110\118\097\108\105\100 \103\108\111\098\097\108 \099\111\110\102\105\103\117\114\097\116\105\111\110 \107\101\121 \037\113 \040\116\121\112\101 \037\115\041\046 \086\097\108\105\100 \099\111\110\102\105\103\117\114\097\116\105\111\110 \107\101\121\115 \097\114\101\058 \037\115"):format(tostring(X),typeof(X),table.concat(O,"\044 "))error(q,3)end if typeof(P)~="\098\111\111\108\101\097\110"then local O=("\073\110\118\097\108\105\100 \118\097\108\117\101 \037\113 \040\116\121\112\101 \037\115\041 \102\111\114 \103\108\111\098\097\108 \099\111\110\102\105\103\117\114\097\116\105\111\110 \107\101\121 \037\113\046 \086\097\108\105\100 \118\097\108\117\101\115 \097\114\101\058 \116\114\117\101\044 \102\097\108\115\101"):format(tostring(P),typeof(P),tostring(X))error(O,3)end q._currentConfig[X]=P end end function X.get(O)return O._currentConfig end function X.scoped(q,O,X)local P={}for O,X in pairs(q._currentConfig)do P[O]=X end q.set(O)local o,t=pcall(X)q.set(P)assert(o,t)end return X
-- Build a list of valid configuration values up for debug messages.
local defaultConfigKeys = {}
for key in pairs(defaultConfig) do
	table.insert(defaultConfigKeys, key)
end

local Config = {}

function Config.new()
	local self = {}

	self._currentConfig = setmetatable({}, {
		__index = function(_, key)
			local message = ("Invalid global configuration key %q. Valid configuration keys are: %s"):format(
				tostring(key),
				table.concat(defaultConfigKeys, ", ")
			)

			error(message, 3)
		end,
	})

	-- We manually bind these methods here so that the Config's methods can be
	-- used without passing in self, since they eventually get exposed on the
	-- root Roact object.
	self.set = function(...)
		return Config.set(self, ...)
	end

	self.get = function(...)
		return Config.get(self, ...)
	end

	self.scoped = function(...)
		return Config.scoped(self, ...)
	end

	self.set(defaultConfig)

	return self
end

function Config:set(configValues)
	-- Validate values without changing any configuration.
	-- We only want to apply this configuration if it's valid!
	for key, value in pairs(configValues) do
		if defaultConfig[key] == nil then
			local message = ("Invalid global configuration key %q (type %s). Valid configuration keys are: %s"):format(
				tostring(key),
				typeof(key),
				table.concat(defaultConfigKeys, ", ")
			)

			error(message, 3)
		end

		-- Right now, all configuration values must be boolean.
		if typeof(value) ~= "boolean" then
			local message = ("Invalid value %q (type %s) for global configuration key %q. Valid values are: true, false"):format(
				tostring(value),
				typeof(value),
				tostring(key)
			)

			error(message, 3)
		end

		self._currentConfig[key] = value
	end
end

function Config:get()
	return self._currentConfig
end

function Config:scoped(configValues, callback)
	local previousValues = {}
	for key, value in pairs(self._currentConfig) do
		previousValues[key] = value
	end

	self.set(configValues)

	local success, result = pcall(callback)

	self.set(previousValues)

	assert(success, result)
end

return Config
