-- LUALOCALS < ---------------------------------------------------------
local klots, math, minetest, string
    = klots, math, minetest, string
local math_floor, string_format
    = math.floor, string.format
-- LUALOCALS > ---------------------------------------------------------

local modstore = minetest.get_mod_storage()

------------------------------------------------------------------------

local function mbfloor(n) return math_floor(n / 16) * 16 end

local mbkeyraw, mbkey
do
	local template = "mbdirty(%d,%d,%d)"
	mbkeyraw = function(pos)
		return string_format(template, pos.x, pos.y, pos.z)
	end
	mbkey = function(pos)
		return string_format(template, mbfloor(pos.x),
			mbfloor(pos.y), mbfloor(pos.z))
	end
end

------------------------------------------------------------------------

local function hook(key)
	local old = minetest[key]
	minetest[key] = function(pos, ...)
		modstore:set_string(mbkey(pos), "1")
		return old(pos, ...)
	end
end
hook("set_node")
hook("remove_node")
hook("add_node")

-- trying to hook into a metaref to determine if it's actually
-- being written to is tricky, so for now just assume it could be
hook("get_meta")

local olddel = minetest.delete_area
function minetest.delete_area(pos1, pos2, ...)
	local function helper(...)
		local xdir = pos1.x < pos2.x and 16 or -16
		local ydir = pos1.y < pos2.y and 16 or -16
		local zdir = pos1.z < pos2.z and 16 or -16
		for z = mbfloor(pos1.z), mbfloor(pos2.z), zdir do
			for y = mbfloor(pos1.y), mbfloor(pos2.y), ydir do
				for x = mbfloor(pos1.x), mbfloor(pos2.x), xdir do
					modstore:set_string(mbkeyraw({x = x, y = y, z = z}), "")
				end
			end
		end
		return ...
	end
	return helper(olddel(pos1, pos2, ...))
end

------------------------------------------------------------------------

function klots.mapblock_dirty(pos1, pos2)
	if not pos2 then
		return modstore:get_string(mbkey(pos1)) ~= ""
	end
	local found = {}
	local xdir = pos1.x < pos2.x and 16 or -16
	local ydir = pos1.y < pos2.y and 16 or -16
	local zdir = pos1.z < pos2.z and 16 or -16
	for z = mbfloor(pos1.z), mbfloor(pos2.z), zdir do
		for y = mbfloor(pos1.y), mbfloor(pos2.y), ydir do
			for x = mbfloor(pos1.x), mbfloor(pos2.x), xdir do
				local pos = {x = x, y = y, z = z}
				if modstore:get_string(mbkeyraw(pos)) ~= "" then
					found[#found + 1] = pos
				end
			end
		end
	end
	return found
end
