------
-- Simple data serializer.
-- @author Adam Klvač <adam@klva.cz>
-- @license MIT
------

--- Foreach polyfill.
-- @param array table to be iterated over
-- @param callback function accepting key and value for each item
-- @return nil or result of break loop
local function foreach(array, callback)
	if table.foreach ~= nil then
		return table.foreach(array, callback)
	else
		for k, v in pairs(array) do
			local r = callback(k, v)
			if r ~= nil then
				return r
			end
		end
	end
end

--- Serializes a value.
-- This is an internal function.
-- @param value value to be serialized
-- @param recursion depth
-- @param throw error on unserializable data
-- @return string
-- @error unserializable data
local function serialize(value, recursion, strict)

	if recursion == nil then
		recursion = 0
	end

	local t = type(value)

	if t == 'nil' then
		return 'nil'
	elseif t == 'boolean' then
		if value then return 'true' else return 'false' end
	elseif t == 'string' then
		return string.format('%q', value)
	elseif t == 'number' then
		return tostring(value)
	elseif t == 'table' then

		local s = '{\n'
		local m = 1

		foreach(value, function(k, v)

			if m == k then
				m = m + 1
				s = s .. string.rep('\t', recursion + 1) .. serialize(v, recursion + 1, strict) .. ',\n'
			else

				m = nil

				if type(k) == 'number' then
					k = '[' .. tostring(k) .. ']'
				else
					k = '[' .. string.format('%q', k) .. ']'
				end

				s = s .. string.rep('\t', recursion + 1) .. k .. ' = ' .. serialize(v, recursion + 1, strict) .. ',\n'

			end

		end)

		return s .. string.rep('\t', recursion) .. '}'

	else
		if strict then
			error('unserializable data')
		else
			return string.format('%q', t)
		end
	end

end

--- Serializes data into Lua compliant expression string.
-- @param data data to be serialized
-- @param false to allow unserializable data to be printed (as string)?
-- @return serialized string
-- @error unserializable data
return function(data, strict)

	if strict ~= false then
		strict = true
	end

	return serialize(data, nil, strict)

end