local random = math.random

--
-- Grow trees from saplings
--

-- Ok. So the original implementation is a can of worms - fantasy worms that crawl under your skin and lay eggs in your brain.
-- It solved problems with iniominous hacks like making special schematics for when a tree grows into a sapling, in order to remove the sapling, despite the fact they have to handle case-by-case sapling growth anyway so they could have used remove_node() to solve it in a sane way.
-- (I think it could be handled by a table instead of an if/else ladder, aka the poor man's switch-case, aka I don't know how to program in Lua, but I'll leave it there cause I'm sick of this piece of code).
-- And yet, you still can tell the difference from a "decoration" tree and a "sapling" tree by the fact that one has a "root" (one node in soil) and not the other.

function default.can_grow(pos)
	local node_under = minetest.get_node_or_nil({x = pos.x, y = pos.y - 1, z = pos.z})
	if not node_under then return false end
	if minetest.get_item_group(node_under.name, "crumbly") == 0 then return false end
	local light_level = minetest.get_node_light(pos)
	return light_level and light_level>13
end

function default.start_grow_timer(base, pos, biome)
	-- starts a timer at pos with base duration, multiplied by the average absolute difference
	-- of temp and humidity between the prefered biome and the biome at pos.
	-- In effect, the duration can range from exactly 'base' in an ideal biome to 3 times that
	-- duration in the worst biome, e.g. ice sheet versus desert.
	-- The ideal biome is normally the one used by the mapgen to place the corresponding tree.
	-- Used for fruits as well.
	local start_timer_at=function(pos, t)
		minetest.get_node_timer(pos):start(t)
	end
	-- get biome at pos
	local biome_data=minetest.get_biome_data(pos)
	if not biome_data then return end -- won't grow
	if not biome then
		start_timer_at(pos, base)
		return
	end
	local ref_data=minetest.registered_biomes[biome]
	if not ref_data then
		minetest.log("warning", "incorrect biome for growth timer: "..biome)
		start_timer_at(pos, base)
		return
	end
	local overhead=(
	math.abs(biome_data.heat-ref_data.heat_point)+
	math.abs(biome_data.humidity-ref_data.humidity_point)
	) -- this is an average multiplied by 2
	start_timer_at(pos, base*(1+overhead/100))
	-- so time varies from 100% to 300% of the base timer
end

-- Grow sapling

function default.grow_sapling(pos)
	if not default.can_grow(pos) then
		-- try again 5 min later
		minetest.get_node_timer(pos):start(300)
		return
	end
	local node = minetest.get_node(pos)
	minetest.remove_node(pos)
	if node.name == "default:sapling" then
		default.grow_new_apple_tree(pos)
	elseif node.name == "default:junglesapling" then
			default.grow_new_jungle_tree(pos)
	elseif node.name == "default:pine_sapling" then
		default.grow_new_pine_tree(pos)
	elseif node.name == "default:acacia_sapling" then
		default.grow_new_acacia_tree(pos)
	elseif node.name == "default:aspen_sapling" then
		default.grow_new_aspen_tree(pos)
	elseif node.name == "default:bush_sapling" then
		default.grow_bush(pos)
	elseif node.name == "default:blueberry_bush_sapling" then
		default.grow_blueberry_bush(pos)
	elseif node.name == "default:acacia_bush_sapling" then
		default.grow_acacia_bush(pos)
	elseif node.name == "default:pine_bush_sapling" then
		default.grow_pine_bush(pos)
	elseif node.name == "default:palmtree_sapling" then
		default.grow_new_palm_tree(pos)
	elseif node.name == "default:large_cactus_seedling" then
		default.grow_large_cactus(pos)
	end
end

local mod=minetest.get_modpath("mf_default")

-- New apple tree

function default.grow_new_apple_tree(pos)
	local path = mod ..  "/schematics/apple_tree.mts"
	minetest.place_schematic({x = pos.x - 3, y = pos.y, z = pos.z - 3},
		path, "random", nil, false)
end


-- New jungle tree

function default.grow_new_jungle_tree(pos)
	local path = mod ..  "/schematics/jungle_tree.mts"
	minetest.place_schematic({x = pos.x - 2, y = pos.y, z = pos.z - 2},
		path, "random", nil, false)
end


-- New pine tree

function default.grow_new_pine_tree(pos)
	local path = mod ..  "/schematics/pine_tree.mts"
	minetest.place_schematic({x = pos.x - 2, y = pos.y,  z = pos.z - 2},
	path, "0", nil, false)
end



-- New acacia tree

function default.grow_new_acacia_tree(pos)
	local path = mod ..  "/schematics/acacia_tree.mts"
	minetest.place_schematic({x = pos.x - 4, y = pos.y, z = pos.z - 4},
		path, "random", nil, false)
end


-- New aspen tree

function default.grow_new_aspen_tree(pos)
	local path = mod ..  "/schematics/aspen_tree.mts"
	minetest.place_schematic({x = pos.x - 2, y = pos.y, z = pos.z - 2},
		path, "0", nil, false)
end

function default.grow_new_palm_tree(pos)
	local path = mod ..  "/schematics/palmtree.mts"
	minetest.place_schematic({x = pos.x - 3, y = pos.y, z = pos.z - 3},
		path, "0", nil, false)
end

-- Large cactus

function default.grow_large_cactus(pos)
	local path = mod ..  "/schematics/large_cactus.mts"
	minetest.place_schematic({x = pos.x - 2, y = pos.y, z = pos.z - 2},
		path, "random", nil, false)
end



-- Bushes do not need 'from sapling' schematic variants because
-- only the stem node is force-placed in the schematic.

-- Bush

function default.grow_bush(pos)
	local path = mod ..  "/schematics/bush.mts"
	minetest.place_schematic({x = pos.x - 1, y = pos.y - 1, z = pos.z - 1},
		path, "0", nil, false)
end

-- Blueberry bush

function default.grow_blueberry_bush(pos)
	local path = mod ..  "/schematics/blueberry_bush.mts"
	minetest.place_schematic({x = pos.x - 1, y = pos.y, z = pos.z - 1},
		path, "0", nil, false)
end


-- Acacia bush

function default.grow_acacia_bush(pos)
	local path = mod .. "/schematics/acacia_bush.mts"
	minetest.place_schematic({x = pos.x - 1, y = pos.y - 1, z = pos.z - 1},
		path, "0", nil, false)
end


-- Pine bush

function default.grow_pine_bush(pos)
	local path = mod ..  "/schematics/pine_bush.mts"
	minetest.place_schematic({x = pos.x - 1, y = pos.y - 1, z = pos.z - 1},
		path, "0", nil, false)
end



--
-- Sapling 'on place' function to check protection of node and resulting tree volume
--

function default.sapling_on_place(itemstack, placer, pointed_thing,
		sapling_name, minp_relative, maxp_relative, interval)
	-- Position of sapling
	local pos = pointed_thing.under
	local node = minetest.get_node_or_nil(pos)
	local pdef = node and minetest.registered_nodes[node.name]

	if pdef and pdef.on_rightclick and
			not (placer and placer:is_player() and
			placer:get_player_control().sneak) then
		return pdef.on_rightclick(pos, node, placer, itemstack, pointed_thing)
	end

	if not pdef or not pdef.buildable_to then
		pos = pointed_thing.above
		node = minetest.get_node_or_nil(pos)
		pdef = node and minetest.registered_nodes[node.name]
		if not pdef or not pdef.buildable_to then
			return itemstack
		end
	end

	local take_item = true
	local newnode = {name = sapling_name}
	local ndef = minetest.registered_nodes[sapling_name]
	minetest.set_node(pos, newnode)

	-- Run callback
	if ndef and ndef.after_place_node then
		-- Deepcopy place_to and pointed_thing because callback can modify it
		if ndef.after_place_node(table.copy(pos), placer,
				itemstack, table.copy(pointed_thing)) then
			take_item = false
		end
	end

	-- Run script hook
	for _, callback in ipairs(minetest.registered_on_placenodes) do
		-- Deepcopy pos, node and pointed_thing because callback can modify them
		if callback(table.copy(pos), table.copy(newnode),
				placer, table.copy(node or {}),
				itemstack, table.copy(pointed_thing)) then
			take_item = false
		end
	end

	if take_item then
		itemstack:take_item()
	end

	return itemstack
end
