local R = mcl_levelgen.build_random_spread_placement

------------------------------------------------------------------------
-- Jungle Temple structure.
------------------------------------------------------------------------

if not mcl_levelgen.is_levelgen_environment then
	local v = vector.zero ()
	local level_to_minetest_position = mcl_levelgen.level_to_minetest_position
	local jungle_temple_loot = {
		stacks_min = 2,
		stacks_max = 6,
		items = {
			{ itemstring = "mcl_mobitems:bone", weight = 20, amount_min = 4, amount_max=6 },
			{ itemstring = "mcl_mobitems:rotten_flesh", weight = 16, amount_min = 3, amount_max=7 },
			{ itemstring = "mcl_core:gold_ingot", weight = 15, amount_min = 2, amount_max = 7 },
			{ itemstring = "mcl_bamboo:bamboo", weight = 15, amount_min = 1, amount_max=3 },
			{ itemstring = "mcl_core:iron_ingot", weight = 15, amount_min = 1, amount_max = 5 },
			{ itemstring = "mcl_core:diamond", weight = 3, amount_min = 1, amount_max = 3 },
			{ itemstring = "mcl_mobitems:saddle", weight = 3, },
			{ itemstring = "mcl_core:emerald", weight = 2, amount_min = 1, amount_max = 3 },
			{ itemstring = "mcl_books:book", weight = 1, func = function(stack, pr)
				  mcl_enchanting.enchant_uniform_randomly(stack, {"soul_speed"}, pr)
			end },
			{ itemstring = "mcl_mobitems:iron_horse_armor", weight = 1, },
			{ itemstring = "mcl_mobitems:gold_horse_armor", weight = 1, },
			{ itemstring = "mcl_mobitems:diamond_horse_armor", weight = 1, },
			{ itemstring = "mcl_core:apple_gold_enchanted", weight = 2, },
			{ itemstring = "mcl_armor:wild", amount_min = 1, amount_max = 1, },
		},
	}

	local function handle_jungle_temple_loot (_, data)
		v.x, v.y, v.z
			= level_to_minetest_position (data[1], data[2], data[3])
		core.load_area (v)

		local node = core.get_node (v)
		if node.name == "mcl_chests:chest_small" then
			mcl_structures.init_node_construct (v)
			local meta = core.get_meta (v)
			local inv = meta:get_inventory ()
			local pr = PcgRandom (data[4])
			local loot = mcl_loot.get_loot (jungle_temple_loot, pr)
			mcl_loot.fill_inventory (inv, "main", loot, pr)
		end
	end

	mcl_levelgen.register_notification_handler ("mcl_levelgen:jungle_temple_loot",
						    handle_jungle_temple_loot)
end

local name = mcl_levelgen.prefix .. "/templates/jungle_temple.dat"
local template, WIDTH, LENGTH

local function init_templates ()
	local err
	template, err = mcl_levelgen.read_structure_template (name)
	if err then
		error (err)
	end
	WIDTH = template.width
	LENGTH = template.length
end

if not mcl_levelgen.is_levelgen_environment then
	core.register_on_mods_loaded (init_templates)
else
	init_templates ()
end

local function getcid (name)
	if mcl_levelgen.is_levelgen_environment then
		return core.get_content_id (name)
	else
		return 0 -- Not nil so as to prevent errors in table
			 -- initializers.
	end
end

local GROUND_OFFSET = 4

local random_schematic_rotation = mcl_levelgen.random_schematic_rotation
local make_template_piece = mcl_levelgen.make_template_piece

local cid_cobblestone
	= getcid ("mcl_core:cobble")
local cid_cobblestone_stairs
	= getcid ("mcl_stairs:stair_cobble")
local cid_cobblestone_stairs_inner
	= getcid ("mcl_stairs:stair_cobble_inner")
local cid_cobblestone_stairs_outer
	= getcid ("mcl_stairs:stair_cobble_outer")

local cid_mossy_cobblestone
	= getcid ("mcl_core:mossycobble")
local cid_mossy_cobblestone_stairs
	= getcid ("mcl_stairs:stair_mossycobble")
local cid_mossy_cobblestone_stairs_inner
	= getcid ("mcl_stairs:stair_mossycobble_inner")
local cid_mossy_cobblestone_stairs_outer
	= getcid ("mcl_stairs:stair_mossycobble_outer")

local replacements = {
	[cid_cobblestone] = cid_mossy_cobblestone,
	[cid_cobblestone_stairs] = cid_mossy_cobblestone_stairs,
	[cid_cobblestone_stairs_inner] = cid_mossy_cobblestone_stairs_inner,
	[cid_cobblestone_stairs_outer] = cid_mossy_cobblestone_stairs_outer,
}

local set_current_template_meta = mcl_levelgen.set_current_template_meta

local function jungle_temple_mossify (x, y, z, rng, cid_existing,
				      param2_existing, cid, param2)
	if replacements[cid] and rng:next_float () < 0.4 then
		return replacements[cid], param2
	end
	return cid, param2
end

local cid_chest_small
	= getcid ("mcl_chests:chest_small")
local mathabs = math.abs
local notify_generated = mcl_levelgen.notify_generated

local function jungle_temple_loot (x, y, z, rng, cid_existing,
				   param2_existing, cid, param2)
	if cid == cid_chest_small then
		notify_generated ("mcl_levelgen:jungle_temple_loot", x, y, z, {
			x, y, z, mathabs (rng:next_integer ()),
		})
		-- Hack: constructor execution must be suppressed lest
		-- it overwrite loot generated by this handler.
		set_current_template_meta (nil, true)
	end
	return cid, param2
end

local jungle_temple_processors = {
	jungle_temple_mossify,
	jungle_temple_loot,
}

local function create_jungle_temple_piece (rng, x, y, z)
	local rot = random_schematic_rotation (rng)
	if rot == "90" then
		x = x + LENGTH - 1
	elseif rot == "180" then
		x = x + WIDTH + 1
		z = z + LENGTH - 1
	elseif rot == "270" then
		z = z + WIDTH - 1
	end
	return make_template_piece (template, x, y, z,
				    nil, rot, rng,
				    nil, jungle_temple_processors,
				    GROUND_OFFSET, nil)
end

local lowest_corner_from_chunk_origin
	= mcl_levelgen.lowest_corner_from_chunk_origin
local structure_biome_test = mcl_levelgen.structure_biome_test
local is_not_air = mcl_levelgen.is_not_air
local create_structure_start = mcl_levelgen.create_structure_start

local function jungle_temple_create_start (self, level, terrain, rng, cx, cz)
	local sea_level = level.preset.sea_level
	local y = lowest_corner_from_chunk_origin (terrain, cx, cz, WIDTH, LENGTH)
	if y < sea_level then
		return nil
	else
		local x = cx * 16 + 8
		local z = cz * 16 + 8
		local y = terrain:get_one_height (x, z, is_not_air)

		if structure_biome_test (level, self, x, y, z) then
			local pieces = {
				create_jungle_temple_piece (rng, x - 8,
							    y, z - 8),
			}
			-- Adjust the bbox's vertical position to the
			-- bottommost height in the area it occupies.
			local bbox = pieces[1].bbox
			local hmin = terrain:area_average_height (bbox[1], bbox[3],
								  bbox[4], bbox[6],
								  is_not_air)
				- GROUND_OFFSET
			pieces[1].y = hmin
			bbox[5] = hmin + (bbox[5] - bbox[2])
			bbox[2] = hmin
			return create_structure_start (self, pieces)
		end

		return nil
	end
end

------------------------------------------------------------------------
-- Jungle Temple registration.
------------------------------------------------------------------------

local jungle_temple_biomes = {
	"BambooJungle",
	"Jungle",
}

mcl_levelgen.modify_biome_groups (jungle_temple_biomes, {
	has_jungle_temple = true,
})

mcl_levelgen.register_structure ("mcl_levelgen:jungle_temple", {
	create_start = jungle_temple_create_start,
	step = mcl_levelgen.SURFACE_STRUCTURES,
	terrain_adaptation = "none",
	biomes = mcl_levelgen.build_biome_list ({"#has_jungle_temple",}),
})

mcl_levelgen.register_structure_set ("mcl_levelgen:jungle_temples", {
	structures = {
		"mcl_levelgen:jungle_temple",
	},
	placement = R (1.0, "default", 32, 8, 14357619, "linear",
		       nil, nil),
})
