local modname = minetest.get_current_modname()
local modpath = minetest.get_modpath(modname)
local S = minetest.get_translator(modname)

local mod_screwdriver = minetest.get_modpath("screwdriver")
local has_mcl_flowerpots = minetest.get_modpath("mcl_flowerpots")

mcl_flowers = {}
mcl_flowers.registered_simple_flowers = {}
-- Simple flower template
local smallflowerlongdesc = S("This is a small flower. Small flowers are mainly used for dye production and can also be potted.")
local plant_usage_help = S("It can only be placed on a block on which it would also survive.")

local get_palette_color_from_pos = function(pos)
	local biome_data = minetest.get_biome_data(pos)
	local index = 0
	if biome_data then
		local biome = biome_data.biome
		local biome_name = minetest.get_biome_name(biome)
		local reg_biome = minetest.registered_biomes[biome_name]
		if reg_biome then
			index = reg_biome._mcl_palette_index
		end
	end
	return index
end

-- on_place function for flowers
local on_place_flower = mcl_util.generate_on_place_plant_function(function(pos, node, itemstack)
	local below = {x=pos.x, y=pos.y-1, z=pos.z}
	local soil_node = minetest.get_node_or_nil(below)
	if not soil_node then return false end

	local has_palette = minetest.registered_nodes[itemstack:get_name()].palette ~= nil
	local colorize
	if has_palette then
		colorize = get_palette_color_from_pos(pos)
	end
	if not colorize then
		colorize = 0
	end

--[[	Placement requirements:
	* Dirt or grass block
	* If not flower, also allowed on podzol and coarse dirt
	* Light level >= 8 at any time or exposed to sunlight at day
]]
	local light_night = minetest.get_node_light(pos, 0.0)
	local light_day = minetest.get_node_light(pos, 0.5)
	local light_ok = false
	if (light_night and light_night >= 8) or (light_day and light_day >= minetest.LIGHT_MAX) then
		light_ok = true
	end
	local is_flower = minetest.get_item_group(itemstack:get_name(), "flower") == 1
	local ok = (soil_node.name == "mcl_core:dirt" or minetest.get_item_group(soil_node.name, "grass_block") == 1 or (not is_flower and (soil_node.name == "mcl_core:coarse_dirt" or soil_node.name == "mcl_core:podzol" or soil_node.name == "mcl_core:podzol_snow"))) and light_ok
	return ok, colorize
end)

function mcl_flowers.register_simple_flower(name, def)
	local newname = "mcl_flowers:"..name
	if not def._mcl_silk_touch_drop then def._mcl_silk_touch_drop = nil end
	if not def.drop then def.drop = newname end
	mcl_flowers.registered_simple_flowers[newname] = {
		name=name,
		desc=def.desc,
		image=def.image,
		simple_selection_box=def.simple_selection_box,
	}
	minetest.register_node(newname, {
		description = def.desc,
		_doc_items_longdesc = smallflowerlongdesc,
		_doc_items_usagehelp = plant_usage_help,
		drawtype = "plantlike",
		waving = 1,
		tiles = { def.image },
		inventory_image = def.image,
		wield_image = def.image,
		sunlight_propagates = true,
		paramtype = "light",
		walkable = false,
		stack_max = 64,
		drop = def.drop,
		groups = {
			attached_node = 1, deco_block = 1, dig_by_piston = 1, dig_immediate = 3,
			dig_by_water = 1, destroy_by_lava_flow = 1, enderman_takable = 1,
			plant = 1, flower = 1, place_flowerlike = 1, non_mycelium_plant = 1,
			flammable = 2, fire_encouragement = 60, fire_flammability = 100,
			compostability = 65
		},
		sounds = mcl_sounds.node_sound_leaves_defaults(),
		node_placement_prediction = "",
		on_place = on_place_flower,
		selection_box = {
			type = "fixed",
			fixed = def.selection_box,
		},
		_mcl_silk_touch_drop = def._mcl_silk_touch_drop,
	})
	if def.potted and has_mcl_flowerpots then
		mcl_flowerpots.register_potted_flower(newname, {
			name = name,
			desc = def.desc,
			image = def.image,
		})
	end
end

local wheat_seed_drop = {
	max_items = 1,
	items = {
		{
			items = {"mcl_farming:wheat_seeds"},
			rarity = 8,
		},
	},
}

local fortune_wheat_seed_drop = {
	discrete_uniform_distribution = true,
	items = {"mcl_farming:wheat_seeds"},
	chance = 1 / 8,
	min_count = 1,
	max_count = 1,
	factor = 2,
	overwrite = true,
}

-- CHECKME: How does tall grass behave when pushed by a piston?

--- Tall Grass ---
local def_tallgrass = {
	description = S("Tall Grass"),
	drawtype = "plantlike",
	_doc_items_longdesc = S("Tall grass is a small plant which often occurs on the surface of grasslands. It can be harvested for wheat seeds. By using bone meal, tall grass can be turned into double tallgrass which is two blocks high."),
	_doc_items_usagehelp = plant_usage_help,
	_doc_items_hidden = false,
	waving = 1,
	tiles = {"mcl_flowers_tallgrass.png"},
	inventory_image = "mcl_flowers_tallgrass_inv.png",
	wield_image = "mcl_flowers_tallgrass_inv.png",
	selection_box = {
		type = "fixed",
		fixed = {{ -6/16, -8/16, -6/16, 6/16, 4/16, 6/16 }},
	},
	paramtype = "light",
	paramtype2 = "color",
	palette = "mcl_core_palette_grass.png",
	sunlight_propagates = true,
	walkable = false,
	buildable_to = true,
	is_ground_content = true,
	groups = {
		handy = 1, shearsy = 1, attached_node = 1, deco_block = 1,
		plant = 1, place_flowerlike = 2, non_mycelium_plant = 1,
		flammable = 3, fire_encouragement = 60, fire_flammability = 100,
		dig_by_water = 1, destroy_by_lava_flow = 1, compostability = 30
	},
	sounds = mcl_sounds.node_sound_leaves_defaults(),
	drop = wheat_seed_drop,
	_mcl_shears_drop = true,
	_mcl_fortune_drop = fortune_wheat_seed_drop,
	node_placement_prediction = "",
	on_place = on_place_flower,
	_mcl_blast_resistance = 0,
	_mcl_hardness = 0,
}
minetest.register_node("mcl_flowers:tallgrass", def_tallgrass)

--- Fern ---
-- The fern is very similar to tall grass, so we can copy a lot from it.
local def_fern = table.copy(def_tallgrass)
def_fern.description = S("Fern")
def_fern._doc_items_longdesc = S("Ferns are small plants which occur naturally in jungles and taigas. They can be harvested for wheat seeds. By using bone meal, a fern can be turned into a large fern which is two blocks high.")
def_fern.tiles = { "mcl_flowers_fern.png" }
def_fern.inventory_image = "mcl_flowers_fern_inv.png"
def_fern.wield_image = "mcl_flowers_fern_inv.png"
def_fern.selection_box = {
	type = "fixed",
	fixed = { -6/16, -0.5, -6/16, 6/16, 5/16, 6/16 },
}
def_fern.groups.compostability = 65

minetest.register_node("mcl_flowers:fern", def_fern)

if has_mcl_flowerpots then
	mcl_flowerpots.register_potted_flower("mcl_flowers:fern", {
		name = "fern",
		desc = S("Fern"),
		image = "mcl_flowers_fern_inv.png",
	})
end

local function add_large_plant(name, desc, longdesc, bottom_img, top_img, inv_img, selbox_radius, selbox_top_height, drop, shears_drop, is_flower, grass_color, fortune_drop)
	if not inv_img then
		inv_img = top_img
	end
	local create_entry, paramtype2, palette
	if is_flower == nil then
		is_flower = true
	end

	local bottom_groups = {
		attached_node = 1, deco_block = 1,
		dig_by_water = 1, destroy_by_lava_flow = 1, dig_by_piston = 1,
		flammable = 2, fire_encouragement = 60, fire_flammability = 100,
		plant = 1, double_plant = 1, non_mycelium_plant = 1, compostability = 65
	}
	if name == "double_grass" then
		bottom_groups.compostability = 50
	end
	if is_flower then
		bottom_groups.flower = 1
		bottom_groups.place_flowerlike = 1
		bottom_groups.dig_immediate = 3
	else
		bottom_groups.place_flowerlike = 2
		bottom_groups.handy = 1
		bottom_groups.shearsy = 1
	end
	if grass_color then
		paramtype2 = "color"
		palette = "mcl_core_palette_grass.png"
	end
	if longdesc == nil then
		bottom_groups.not_in_creative_inventory = 1
		create_entry = false
	end
	-- Drop itself by default
	local drop_bottom, drop_top
	if not drop then
		drop_top = "mcl_flowers:"..name
	else
		drop_top = drop
		drop_bottom = drop
	end
	minetest.register_node("mcl_flowers:"..name, {
		description = desc,
		_doc_items_create_entry = create_entry,
		_doc_items_longdesc = longdesc,
		_doc_items_usagehelp = plant_usage_help,
		drawtype = "plantlike",
		tiles = { bottom_img },
		inventory_image = inv_img,
		wield_image = inv_img,
		sunlight_propagates = true,
		paramtype = "light",
		paramtype2 = paramtype2,
		palette = palette,
		walkable = false,
		buildable_to = true,
		drop = drop_bottom,
		_mcl_shears_drop = shears_drop,
		_mcl_fortune_drop = fortune_drop,
		node_placement_prediction = "",
		selection_box = {
			type = "fixed",
			fixed = { -selbox_radius, -0.5, -selbox_radius, selbox_radius, 0.5, selbox_radius },
		},
		on_place = function(itemstack, placer, pointed_thing)
			-- We can only place on nodes
			if pointed_thing.type ~= "node" then
				return
			end

			local itemstring = "mcl_flowers:"..name

			-- Call on_rightclick if the pointed node defines it
			local node = minetest.get_node(pointed_thing.under)
			if placer and not placer:get_player_control().sneak then
				if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
					return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack
				end
			end

			-- Check for a floor and a space of 1×2×1
			local ptu_node = minetest.get_node(pointed_thing.under)
			local bottom
			if not minetest.registered_nodes[ptu_node.name] then
				return itemstack
			end
			if minetest.registered_nodes[ptu_node.name].buildable_to then
				bottom = pointed_thing.under
			else
				bottom = pointed_thing.above
			end
			if not minetest.registered_nodes[minetest.get_node(bottom).name] then
				return itemstack
			end
			local top = { x = bottom.x, y = bottom.y + 1, z = bottom.z }
			local bottom_buildable = minetest.registered_nodes[minetest.get_node(bottom).name].buildable_to
			local top_buildable = minetest.registered_nodes[minetest.get_node(top).name].buildable_to
			local floor = minetest.get_node({x=bottom.x, y=bottom.y-1, z=bottom.z})
			if not minetest.registered_nodes[floor.name] then
				return itemstack
			end

			local light_night = minetest.get_node_light(bottom, 0.0)
			local light_day = minetest.get_node_light(bottom, 0.5)
			local light_ok = false
			if (light_night and light_night >= 8) or (light_day and light_day >= minetest.LIGHT_MAX) then
				light_ok = true
			end

			-- Placement rules:
			-- * Allowed on dirt or grass block
			-- * If not a flower, also allowed on podzol and coarse dirt
			-- * Only with light level >= 8
			-- * Only if two enough space
			if (floor.name == "mcl_core:dirt" or minetest.get_item_group(floor.name, "grass_block") == 1 or (not is_flower and (floor.name == "mcl_core:coarse_dirt" or floor.name == "mcl_core:podzol" or floor.name == "mcl_core:podzol_snow"))) and bottom_buildable and top_buildable and light_ok then
				local param2
				if grass_color then
					param2 = get_palette_color_from_pos(bottom)
				end
				-- Success! We can now place the flower
				minetest.sound_play(minetest.registered_nodes[itemstring].sounds.place, {pos = bottom, gain=1}, true)
				minetest.set_node(bottom, {name=itemstring, param2=param2})
				minetest.set_node(top, {name=itemstring.."_top", param2=param2})
				if not minetest.is_creative_enabled(placer:get_player_name()) then
					itemstack:take_item()
				end
			end
			return itemstack
		end,
		after_destruct = function(pos, oldnode)
			-- Remove top half of flower (if it exists)
			local bottom = pos
			local top = { x = bottom.x, y = bottom.y + 1, z = bottom.z }
			if minetest.get_node(bottom).name ~= "mcl_flowers:"..name and minetest.get_node(top).name == "mcl_flowers:"..name.."_top" then
				minetest.remove_node(top)
			end
		end,
		groups = bottom_groups,
		sounds = mcl_sounds.node_sound_leaves_defaults(),
	})

	local top_groups = table.copy(bottom_groups)
	top_groups.not_in_creative_inventory=1
	top_groups.double_plant=2
	top_groups.attached_node=nil

	-- Top
	minetest.register_node("mcl_flowers:"..name.."_top", {
		description = desc.." " .. S("(Top Part)"),
		_doc_items_create_entry = false,
		drawtype = "plantlike",
		tiles = { top_img },
		sunlight_propagates = true,
		paramtype = "light",
		paramtype2 = paramtype2,
		palette = palette,
		walkable = false,
		buildable_to = true,
		selection_box = {
			type = "fixed",
			fixed = { -selbox_radius, -0.5, -selbox_radius, selbox_radius, selbox_top_height, selbox_radius },
		},
		drop = drop_top,
		_mcl_shears_drop = shears_drop,
		_mcl_fortune_drop = fortune_drop,
		after_destruct = function(pos, oldnode)
			-- Remove bottom half of flower (if it exists)
			local top = pos
			local bottom = { x = top.x, y = top.y - 1, z = top.z }
			if minetest.get_node(top).name ~= "mcl_flowers:"..name.."_top" and minetest.get_node(bottom).name == "mcl_flowers:"..name then
				minetest.remove_node(bottom)
			end
		end,
		groups = top_groups,
		sounds = mcl_sounds.node_sound_leaves_defaults(),
	})

	if minetest.get_modpath("doc") and longdesc then
		doc.add_entry_alias("nodes", "mcl_flowers:"..name, "nodes", "mcl_flowers:"..name.."_top")
		-- If no longdesc, help alias must be added manually
	end

end

add_large_plant("peony", S("Peony"), S("A peony is a large plant which occupies two blocks. It is mainly used in dye production."), "mcl_flowers_double_plant_paeonia_bottom.png", "mcl_flowers_double_plant_paeonia_top.png", nil, 5/16, 6/16)
add_large_plant("rose_bush", S("Rose Bush"), S("A rose bush is a large plant which occupies two blocks. It is safe to touch it. Rose bushes are mainly used in dye production."), "mcl_flowers_double_plant_rose_bottom.png", "mcl_flowers_double_plant_rose_top.png", nil, 5/16, 1/16)
add_large_plant("lilac", S("Lilac"), S("A lilac is a large plant which occupies two blocks. It is mainly used in dye production."), "mcl_flowers_double_plant_syringa_bottom.png", "mcl_flowers_double_plant_syringa_top.png", nil, 5/16, 6/16)

-- TODO: Make the sunflower face East. Requires a mesh for the top node.
add_large_plant("sunflower", S("Sunflower"), S("A sunflower is a large plant which occupies two blocks. It is mainly used in dye production."), "mcl_flowers_double_plant_sunflower_bottom.png", "mcl_flowers_double_plant_sunflower_top.png^mcl_flowers_double_plant_sunflower_front.png", "mcl_flowers_double_plant_sunflower_front.png", 6/16, 6/16)

local longdesc_grass = S("Double tallgrass a variant of tall grass and occupies two blocks. It can be harvested for wheat seeds.")
local longdesc_fern = S("Large fern is a variant of fern and occupies two blocks. It can be harvested for wheat seeds.")

add_large_plant("double_grass", S("Double Tallgrass"), longdesc_grass, "mcl_flowers_double_plant_grass_bottom.png", "mcl_flowers_double_plant_grass_top.png", "mcl_flowers_double_plant_grass_inv.png", 6/16, 4/16, wheat_seed_drop, {"mcl_flowers:tallgrass 2"}, false, true, fortune_wheat_seed_drop)
add_large_plant("double_fern", S("Large Fern"), longdesc_fern, "mcl_flowers_double_plant_fern_bottom.png", "mcl_flowers_double_plant_fern_top.png", "mcl_flowers_double_plant_fern_inv.png", 5/16, 5/16, wheat_seed_drop, {"mcl_flowers:fern 2"}, false, true, fortune_wheat_seed_drop)

minetest.register_abm({
	label = "Pop out flowers",
	nodenames = {"group:flower"},
	interval = 12,
	chance = 2,
	action = function(pos, node)
		-- Ignore the upper part of double plants
		if minetest.get_item_group(node.name, "double_plant") == 2 then
			return
		end
		local below = minetest.get_node_or_nil({x=pos.x, y=pos.y-1, z=pos.z})
		if not below then
			return
		end
		-- Pop out flower if not on dirt, grass block or too low brightness
		if (below.name ~= "mcl_core:dirt" and minetest.get_item_group(below.name, "grass_block") ~= 1) or (minetest.get_node_light(pos, 0.5) < 8) then
			minetest.dig_node(pos)
			return
		end
	end,
})

local on_rotate
if mod_screwdriver then
	on_rotate = screwdriver.rotate_simple
end

-- Lily Pad
minetest.register_node("mcl_flowers:waterlily", {
	description = S("Lily Pad"),
	_doc_items_longdesc = S("A lily pad is a flat plant block which can be walked on. They can be placed on water sources, ice and frosted ice."),
	drawtype = "nodebox",
	paramtype = "light",
	paramtype2 = "facedir",
	tiles = {"flowers_waterlily.png", "flowers_waterlily.png^[transformFY"},
	use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or true,
	inventory_image = "flowers_waterlily.png",
	wield_image = "flowers_waterlily.png",
	liquids_pointable = true,
	walkable = true,
	sunlight_propagates = true,
	groups = {
		deco_block = 1, plant = 1, compostability = 65, destroy_by_lava_flow = 1,
		dig_immediate = 3, dig_by_water = 1, dig_by_piston = 1, dig_by_boat = 1,
	},
	sounds = mcl_sounds.node_sound_leaves_defaults(),
	node_placement_prediction = "",
	node_box = {
		type = "fixed",
		fixed = {-0.5, -31/64, -0.5, 0.5, -15/32, 0.5}
	},
	selection_box = {
		type = "fixed",
		fixed = {-7 / 16, -0.5, -7 / 16, 7 / 16, -15 / 32, 7 / 16}
	},

	on_place = function(itemstack, placer, pointed_thing)
		local pos = pointed_thing.above
		local node = minetest.get_node(pointed_thing.under)
		local nodename = node.name
		local def = minetest.registered_nodes[nodename]
		local node_above = minetest.get_node(pointed_thing.above).name
		local def_above = minetest.registered_nodes[node_above]
		local player_name = placer:get_player_name()

		if def then
			-- Use pointed node's on_rightclick function first, if present
			if placer and not placer:get_player_control().sneak then
				if def and def.on_rightclick then
					return def.on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack
				end
			end

			if (pointed_thing.under.x == pointed_thing.above.x and pointed_thing.under.z == pointed_thing.above.z) and
					((def.liquidtype == "source" and minetest.get_item_group(nodename, "water") > 0) or
					(nodename == "mcl_core:ice") or
					(minetest.get_item_group(nodename, "frosted_ice") > 0)) and
					(def_above.buildable_to and minetest.get_item_group(node_above, "liquid") == 0) then
				if not minetest.is_protected(pos, player_name) then
					minetest.set_node(pos, {name = "mcl_flowers:waterlily", param2 = math.random(0, 3)})
					local idef = itemstack:get_definition()

					if idef.sounds and idef.sounds.place then
						minetest.sound_play(idef.sounds.place, {pos=pointed_thing.above, gain=1}, true)
					end

					if not minetest.is_creative_enabled(player_name) then
						itemstack:take_item()
					end
				else
					minetest.record_protection_violation(pos, player_name)
				end
			end
		end
		return itemstack
	end,
	on_rotate = on_rotate,
})

-- Legacy support
minetest.register_alias("mcl_core:tallgrass", "mcl_flowers:tallgrass")

-- mcimport support: re-adds missing double_plant tops in mcimported worlds.
local mg_name = minetest.get_mapgen_setting("mg_name")
local mod_mcimport = minetest.get_modpath("mcimport")

local fix_doubleplants = minetest.settings:get_bool("fix_doubleplants", true)

if mod_mcimport and mg_name == "singlenode" and fix_doubleplants == true then
	local flowernames = { "peony", "rose_bush", "lilac", "sunflower", "double_fern", "double_grass" }

	minetest.register_lbm({
		label = "Add double plant tops.",
		name = "mcl_flowers:double_plant_topper",
		run_at_every_load = true,
		nodenames = { "mcl_flowers:peony", "mcl_flowers:rose_bush", "mcl_flowers:lilac", "mcl_flowers:sunflower", "mcl_flowers:double_fern", "mcl_flowers:double_grass" },
		action = function(pos, node)
			for c = 1, 6 do
				local flowername = flowernames[c]
				local bottom = pos
				local top = { x = bottom.x, y = bottom.y + 1, z = bottom.z }
				if node.name == "mcl_flowers:"..flowername then
					minetest.set_node(top, {name = "mcl_flowers:"..flowername.."_top"})
				end
			end
		end,
	})
end

dofile(modpath.."/register.lua")