--- Loads configurations from files on demand.
-- @author DarkWiiPlayer
-- @license Unlicense

local lfs = require 'lfs'

local config = {}

local __metatable = {}
function __metatable:__index(index)
	if type(index)~="string" then return nil end
	local path = self.__dir..'/'..index
	local attributes = lfs.attributes(path)
	if attributes and attributes.mode=='directory' then
		return config.bind(path, self.__loaders)
	else
		for _, loader in ipairs(self.__loaders) do
			local result = loader(path)
			if result then
				rawset(self, index, result)
				return result
			end
		end
	end
end

--- Binds a table to a config directory.
-- The returned table maps keys to configurations, which are handled by
-- different "loaders". loaders are handlers that try loading a config entry in
-- a certain format and are tried  sequentially until one succeeds. If no
-- loader matches, nil is returned.
-- @tparam string dir Path to the directory to look in.
-- @tparam table loaders A table of loaders to use when attempting to load a configuration entry.
-- @treturn table config A table that maps to the config directory
-- @usage
-- 	local config = glass.bind 'configurations'
-- 	main_config.foo.bar
-- 	-- Loads some file like foo.json or foo.yaml
-- 	-- in the configurations directory
function config.bind(dir, loaders)
	if type(dir)~="string" then
		error(string.format("bad argument #1 to '%s' (string expected, got %s)", debug.getinfo(1).name, type(loaders)), 2)
	end
	if type(loaders)~="table" then
		error(string.format("bad argument #2 to '%s' (table expected, got %s)", debug.getinfo(1).name, type(loaders)), 2)
	end
	return setmetatable({__dir=dir, __loaders=loaders}, __metatable)
end

return config