-- LUALOCALS < ---------------------------------------------------------
local PcgRandom, VoxelArea, ipairs, math, minetest, table
	= PcgRandom, VoxelArea, ipairs, math, minetest, table
local math_floor, math_random, table_insert
	= math.floor, math.random, table.insert
-- LUALOCALS > ---------------------------------------------------------

local modname = minetest.get_current_modname()
local hgapi = _G[modname]

local mapgens = {}
hgapi.registered_mapgen_shared = mapgens

local counters = {}
function hgapi.register_mapgen_shared(def)
	local label = def.label
	if not label then
		label = minetest.get_current_modname()
		local i = (counters[label] or 0) + 1
		counters[label] = i
		label = label .. ":" .. i
	end

	local prio = def.priority or 0
	def.priority = prio
	local min = 1
	local max = #mapgens + 1
	while max > min do
		local try = math_floor((min + max) / 2)
		local oldp = mapgens[try].priority
		if (prio < oldp) or (prio == oldp and label > mapgens[try].label) then
			min = try + 1
		else
			max = try
		end
	end
	table_insert(mapgens, min, def)
end

local mapperlin
minetest.after(0, function() mapperlin = minetest.get_perlin(0, 1, 0, 1) end)

minetest.register_on_mapgen_init(function(mapgen_params)
	mapgen_params["flags"] = "nocaves,nodungeons"
	minetest.set_mapgen_params(mapgen_params)
end)

minetest.register_on_generated(function(minp, maxp)
		local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
		local data = vm:get_data()
		local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})

		local rng
		if PcgRandom then
			local seed = mapperlin:get_3d(minp)
			seed = math_floor((seed - math_floor(seed)) * 2 ^ 32 - 2 ^ 31)
			local pcg = PcgRandom(seed)
			rng = function(a, b)
				if b then
					return pcg:next(a, b)
				elseif a then
					return pcg:next(1, a)
				end
				return (pcg:next() + 2 ^ 31) / 2 ^ 32
			end
		else
			rng = math_random
		end

		for _, def in ipairs(mapgens) do
			if def.enabled or (def.enabled == nil) then
				if def.schematics then
					vm:set_data(data)
					vm:write_to_map()
					vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
					data = vm:get_data()
				end
				def.func(minp, maxp, area, data, vm, emin, emax, rng)
				if def.schematics then
					vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
					data = vm:get_data()
				end
			end
		end

		vm:calc_lighting(minp, maxp, true)
		vm:set_data(data)
		vm:write_to_map()
	end)
