-- LUALOCALS < ---------------------------------------------------------
local math, minetest, nodecore, pairs
    = math, minetest, nodecore, pairs
local math_floor, math_pow, math_random
    = math.floor, math.pow, math.random
-- LUALOCALS > ---------------------------------------------------------

local modname = minetest.get_current_modname()

------------------------------------------------------------------------
-- Hard Stone Strata

nodecore.hard_stone_strata = 7

function nodecore.hard_stone_tile(n)
	local o = math_floor(math_pow(n, 0.75) * 59)
	if o <= 0 then
		return modname .. "_stone.png"
	end
	if o >= 255 then
		return modname .. "_stone.png^"
		.. modname .. "_stone_hard.png"
	end
	return modname .. "_stone.png^("
	.. modname .. "_stone_hard.png^[opacity:"
	.. o .. ")"
end

------------------------------------------------------------------------
-- Dirt Leaching

function nodecore.register_dirt_leaching(fromnode, tonode, rate)
	local waters = {}
	minetest.after(0, function()
			for k, v in pairs(minetest.registered_nodes) do
				if v.groups and v.groups.water and v.groups.water > 0 then
					waters[k] = true
				end
			end
		end)
	local function waterat(pos, dx, dy, dz)
		return waters[minetest.get_node(
			{x = pos.x + dx, y = pos.y + dy, z = pos.z + dz}
		).name]
	end
	nodecore.register_soaking_abm({
			label = fromnode .. " leaching to " .. tonode,
			fieldname = "leach",
			nodenames = {fromnode},
			interval = 5,
			quickcheck = function(pos)
				return waterat(pos, 0, 1, 0)
			end,
			soakrate = function(pos)
				local qty = 1
				if waterat(pos, 1, 0, 0) then qty = qty * 1.5 end
				if waterat(pos, -1, 0, 0) then qty = qty * 1.5 end
				if waterat(pos, 0, 0, 1) then qty = qty * 1.5 end
				if waterat(pos, 0, 0, -1) then qty = qty * 1.5 end
				if waterat(pos, 0, -1, 0) then qty = qty * 1.5 end
				return qty * (rate or 1)
			end,
			soakcheck = function(data, pos)
				if data.total < 5000 then return end
				nodecore.set_loud(pos, {name = tonode})
				nodecore.witness(pos, "leach " .. fromnode)
				return nodecore.fallcheck(pos)
			end
		})
end

------------------------------------------------------------------------
-- Artificial Water

local graywatersrc = "nc_terrain:water_gray_source"
local graywaterflow = "nc_terrain:water_gray_flowing"
local graywatercache = {}

local function rmwater(pos)
	nodecore.node_sound(pos, "dig")
	return minetest.set_node(pos, {name = graywaterflow, param2 = 7})
end
function nodecore.artificial_water_check(pos)
	local data = graywatercache[minetest.hash_node_position(pos)]
	if not data then
		data = minetest.get_meta(pos):get_string(modname)
		data = data and data ~= "" and minetest.deserialize(data)
	end
	if not data then return rmwater(pos) end

	if data.recheck and nodecore.gametime < data.recheck then
		return nodecore.dnt_set(pos, graywatersrc, data.recheck - nodecore.gametime)
	end
	if data.expire and nodecore.gametime >= data.expire then
		return rmwater(pos)
	end

	if data.matchpos and data.match then
		local mnode = minetest.get_node(data.matchpos)
		if mnode.name ~= "ignore" and not nodecore.match(mnode, data.match) then
			return rmwater(pos)
		end
	end

	return nodecore.dnt_set(pos, graywatersrc, 1 + math_random())
end

nodecore.register_dnt({
		name = graywatersrc,
		nodenames = {graywatersrc},
		action = function(pos) return nodecore.artificial_water_check(pos) end
	})

minetest.register_abm({
		label = "artificial water check",
		interval = 1,
		chance = 1,
		nodenames = {graywatersrc},
		action = function(pos) return nodecore.artificial_water_check(pos) end
	})

--[[
artificial water def:
- matchpos = position of node that's producing the water
- match = match criteria to check that water-producing node is still present
- minttl = minimum amount of time water must be there before rechecking for valid source
- maxttl = maximum amount of time water will remain without being updated
--]]
function nodecore.artificial_water(pos, def, node)
	node = node or minetest.get_node(pos)
	local nn = node.name
	if nn ~= graywatersrc then
		if nn ~= graywaterflow then
			local nd = minetest.registered_nodes[nn]
			if not (nd and nd.floodable) then return end
			if nd.on_flood and not nd.on_flood(
				pos, node, {name = graywatersrc}) then return end
		end
		nodecore.set_loud(pos, {name = graywatersrc})
	end
	local meta = minetest.get_meta(pos)
	local data = {
		match = def.match,
		matchpos = def.matchpos,
		recheck = def.minttl and nodecore.gametime + def.minttl,
		expire = def.maxttl and nodecore.gametime + def.maxttl
	}
	meta:set_string(modname, minetest.serialize(data))
	graywatercache[minetest.hash_node_position(pos)] = data
	nodecore.dnt_set(pos, graywatersrc, def.minttl or 1)
	return true
end
