local wea_c = worldeditadditions_core
local Vector3 = wea_c.Vector3

--- Applies changes to a heightmap to a Voxel Manipulator data block.
-- @param	pos1	vector		Position 1 of the defined region
-- @param	pos2	vector		Position 2 of the defined region
-- @param	area	VoxelArea	The VoxelArea object (see worldedit.manip_helpers.init)
-- @param	data	number[]	The node ids data array containing the slice of the Minetest world extracted using the Voxel Manipulator.
-- @param	heightmap_old	number[]	The original heightmap from worldeditadditions.make_heightmap.
-- @param	heightmap_new	number[]	The new heightmap containing the altered updated values. It is expected that worldeditadditions.table.shallowcopy be used to make a COPY of the data worldeditadditions.make_heightmap for this purpose. Both heightmap_old AND heightmap_new are REQUIRED in order for this function to work.
-- @param	heightmap_size	vector	The x / z size of the heightmap. Any y value set in the vector is ignored.
-- @returns	bool, string|{ added: number, removed: number }	A bool indicating whether the operation was successful or not, followed by either an error message as a string (if it was not successful) or a table of statistics (if it was successful).
local function apply_heightmap_changes(pos1, pos2, area, data, heightmap_old, heightmap_new, heightmap_size)
	local stats = { added = 0, removed = 0 }
	local node_id_air = minetest.get_content_id("air")
	local node_id_ignore = minetest.get_content_id("ignore")
	
	for z = heightmap_size.z - 1, 0, -1 do
		for x = heightmap_size.x - 1, 0, -1 do
			local hi = z*heightmap_size.x + x
			
			local height_old = heightmap_old[hi]
			local height_new = heightmap_new[hi]
			-- print("[conv/save] hi", hi, "height_old", heightmap_old[hi], "height_new", heightmap_new[hi], "z", z, "x", x, "pos1.y", pos1.y)
			
			-- Lua doesn't have a continue statement :-/
			if height_old == height_new then
				-- noop
			elseif height_new < height_old then
				local node_id_replace = data[area:index(
					pos1.x + x,
					pos1.y + height_old + 1,
					pos1.z + z
				)]
				-- Unlikely, but if it can happen, it *will* happen.....
				if node_id_replace == node_id_ignore then
					node_id_replace = node_id_air
				end
				stats.removed = stats.removed + (height_old - height_new)
				local y = height_new
				while y < height_old do
					local ci = area:index(pos1.x + x, pos1.y + y, pos1.z + z)
					-- print("[conv/save] remove at y", y, "→", pos1.y + y, "current:", minetest.get_name_from_content_id(data[ci]))
					if data[ci] ~= node_id_ignore then
						data[ci] = node_id_replace
					end
					y = y + 1
				end
			else -- height_new > height_old
				-- We subtract one because the heightmap starts at 1 (i.e. 1 = 1 node in the column), but the selected region is inclusive
				local node_id = data[area:index(pos1.x + x, pos1.y + (height_old - 1), pos1.z + z)]
				-- print("[conv/save] filling with ", node_id, "→", minetest.get_name_from_content_id(node_id))
				
				stats.added = stats.added + (height_new - height_old)
				local y = height_old
				while y < height_new do
					local ci = area:index(pos1.x + x, pos1.y + y, pos1.z + z)
					-- print("[conv/save] add at y", y, "→", pos1.y + y, "current:", minetest.get_name_from_content_id(data[ci]))
					if data[ci] ~= node_id_ignore then
						data[ci] = node_id
					end
					y = y + 1
				end
			end
		end
	end
	
	return true, stats
end

return apply_heightmap_changes
