-- IndustrialTest
-- Copyright (C) 2023 mrkubax10

-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.

-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU General Public License for more details.

-- You should have received a copy of the GNU General Public License
-- along with this program.  If not, see <http://www.gnu.org/licenses/>.

local S=minetest.get_translator("industrialtest")

local definition={
	description=S("Machine Block"),
	tiles={"industrialtest_machine_block.png"},
}
if industrialtest.mtgAvailable then
	definition.sounds=default.node_sound_metal_defaults()
	definition.groups={cracky=1,level=2}
elseif industrialtest.mclAvailable then
	definition.sounds=mcl_sounds.node_sound_metal_defaults()
	definition._mcl_blast_resistance=6
	definition._mcl_hardness=5
end
minetest.register_node("industrialtest:machine_block",definition)
minetest.register_craft({
	type="shaped",
	output="industrialtest:machine_block",
	recipe={
		{"industrialtest:refined_iron_ingot","industrialtest:refined_iron_ingot","industrialtest:refined_iron_ingot"},
		{"industrialtest:refined_iron_ingot","","industrialtest:refined_iron_ingot"},
		{"industrialtest:refined_iron_ingot","industrialtest:refined_iron_ingot","industrialtest:refined_iron_ingot"}
	}
})

definition={
	description=S("Advanced Machine Block"),
	tiles={"industrialtest_advanced_machine_block.png"},
	groups={
		_industrialtest_wrenchUnmountable=1
	}
}
if industrialtest.mtgAvailable then
	definition.sounds=default.node_sound_metal_defaults()
	definition.groups.cracky=2
	definition.groups.level=2
elseif industrialtest.mclAvailable then
	definition.sounds=mcl_sounds.node_sound_metal_defaults()
	definition._mcl_blast_resistance=7
	definition._mcl_hardness=5
end
minetest.register_node("industrialtest:advanced_machine_block",definition)
minetest.register_craft({
	type="shaped",
	output="industrialtest:advanced_machine_block",
	recipe={
		{"","industrialtest:advanced_alloy",""},
		{"industrialtest:carbon_plate","industrialtest:machine_block","industrialtest:carbon_plate"},
		{"","industrialtest:advanced_alloy",""}
	}
})

if not industrialtest.mods.mclRubber then
	definition={
		description=S("Rubber Wood"),
		tiles={
			"industrialtest_rubber_wood_top.png",
			"industrialtest_rubber_wood_top.png",
			"industrialtest_rubber_wood_side.png"
		},
		paramtype2="4dir"
	}
	if industrialtest.mtgAvailable then
		definition.sounds=default.node_sound_wood_defaults()
		definition.groups={
			tree=1,
			choppy=2,
			oddly_breakable_by_hand=1,
			flammable=2
		}
	elseif industrialtest.mclAvailable then
		definition.sounds=mcl_sounds.node_sound_wood_defaults()
		definition.groups={
			handy=1,
			axey=1,
			tree=1,
			flammable=2,
			building_block=1,
			material_wood=1,
			fire_encouragement=5,
			fire_flammability=5
		}
		definition.after_destruct=mcl_core.update_leaves
		definition._mcl_blast_resistance=1.8
		definition._mcl_hardness=1.8
	end
	definition.groups._industrialtest_rubberWood=1
	minetest.register_node("industrialtest:rubber_wood",definition)
	definition=table.copy(definition)
	definition.description=nil
	definition.tiles={
		"industrialtest_rubber_wood_top.png",
		"industrialtest_rubber_wood_top.png",
		"industrialtest_rubber_wood_side.png",
		"industrialtest_rubber_wood_side.png",
		"industrialtest_rubber_wood_side_with_rubber.png",
		"industrialtest_rubber_wood_side.png"
	}
	definition.drop="industrialtest:rubber_wood"
	if industrialtest.mclAvailable then
		definition.groups.not_in_creative_inventory=1
		definition._doc_items_create_entry=false
	end
	minetest.register_node("industrialtest:rubber_wood_with_rubber",definition)
	minetest.register_abm({
			label="Rubber forming",
			nodenames={"industrialtest:rubber_wood"},
			interval=120,
			chance=2,
			action=function(pos)
				local neighbourPositions={
					vector.offset(pos,-1,0,0),
					vector.offset(pos,1,0,0),
					vector.offset(pos,0,-1,0),
					vector.offset(pos,0,1,0),
					vector.offset(pos,0,0,-1),
					vector.offset(pos,0,0,1)
				}
				for _,value in ipairs(neighbourPositions) do
					if minetest.get_node(value).name=="industrialtest:rubber_wood_with_rubber" then
						return
					end
				end
				minetest.set_node(pos,{
					name="industrialtest:rubber_wood_with_rubber",
					param2=industrialtest.random:next(0,3)
				})
			end
	})
	minetest.register_craft({
		type="shapeless",
		output=industrialtest.elementKeys.junglePlanks.." 3",
		recipe={"group:_industrialtest_rubberWood"}
	})
	definition={
		description=S("Rubber Leaves"),
		drawtype="allfaces_optional",
		tiles={"industrialtest_rubber_leaves.png"},
		special_tiles={"industrialtest_rubber_leaves_simple.png"},
		paramtype="light",
		sunlight_propagates=true,
		waving=1
	}
	if industrialtest.mtgAvailable then
		definition.sounds=default.node_sound_leaves_defaults()
		definition.groups={
			snappy=3,
			leafdecay=3,
			flammable=2,
			leaves=1
		}
		definition.drop={
			max_items=1,
			items={
				{
					items={"industrialtest:rubber_sapling"},
					rarity=20
				},
				{items={"industrialtest:rubber_leaves"}}
			}
		}
		definition.after_place_node=default.after_place_leaves
	elseif industrialtest.mclAvailable then
		local saplingChances={20,16,12,10}
		local stickChances={50,45,30,35,10}
		-- Taken and adapted from https://git.minetest.land/MineClone2/MineClone2/src/branch/master/mods/ITEMS/mcl_core/nodes_trees.lua#L157
		local function getDrops(fortuneLevel)
			local drop = {
				max_items=1,
				items = {
					{
						items = {"industrialtest:rubber_sapling"},
						rarity = saplingChances[fortuneLevel+1] or saplingChances[fortuneLevel]
					},
					{
						items = {"mcl_core:stick 1"},
						rarity = stickChances[fortuneLevel+1]
					},
					{
						items = {"mcl_core:stick 2"},
						rarity = stickChances[fortuneLevel+1]
					},
				}
			}
			return drop
		end
		definition.sounds=mcl_sounds.node_sound_leaves_defaults()
		definition.groups={
			handy=1,
			hoey=1,
			shearsy=1,
			swordy=1,
			dig_by_piston=1,
			flammable=2,
			fire_encouragement=30,
			fire_flammability=60,
			leaves=1,
			deco_block=1,
			compostability=30
		}
		definition.drop=getDrops(0)
		definition.after_place_node=mcl_core.make_player_leaves
		definition._mcl_shears_drop=true
		definition._mcl_blast_resistance=0.2
		definition._mcl_hardness=0.2
		definition._mcl_silk_touch_drop=true
		definition._mcl_fortune_drop={getDrops(1),getDrops(2),getDrops(3),getDrops(4)}
	end
	minetest.register_node("industrialtest:rubber_leaves",definition)
	if industrialtest.mtgAvailable then
		default.register_leafdecay({
			trunks={"industrialtest:rubber_wood"},
			leaves={"industrialtest:rubber_leaves"},
			radius=2
		})
	end
	if industrialtest.mclAvailable then
		definition=table.copy(definition)
		definition._doc_items_create_entry=false
		definition.groups.not_in_creative_inventory=1
		definition.groups.orphan_leaves=1
		definition._mcl_shears_drop={"industrialtest:rubber_leaves"}
		definition._mcl_silk_touch_drop={"industrialtest:rubber_leaves"}
		minetest.register_node("industrialtest:rubber_leaves_orphan",definition)
	end
	industrialtest.internal.makeRubberTree=function(pos)
		-- FIXME: Replace this with placing schematic
		-- Taken and adapted from https://github.com/minetest/minetest_game/blob/master/mods/default/trees.lua#L182
		local height=industrialtest.random:next(4,5)
		local tree=minetest.get_content_id("industrialtest:rubber_wood")
		local treeWithRubber=minetest.get_content_id("industrialtest:rubber_wood_with_rubber")
		local leaves=minetest.get_content_id("industrialtest:rubber_leaves")
		local air=minetest.get_content_id("air")
		local ignore=minetest.get_content_id("ignore")

		local manip=minetest.get_voxel_manip()
		local minp,maxp=manip:read_from_map(vector.new(pos.x-2,pos.y,pos.z),vector.new(pos.x+2,pos.y+height+1,pos.z+2))
		local area=VoxelArea:new({
			MinEdge=minp,
			MaxEdge=maxp
		})
		local data=manip:get_data()

		-- Trunk
		data[area:index(pos.x,pos.y,pos.z)]=tree
		for y=pos.y+1,pos.y+height-1 do
			local index=area:index(pos.x,y,pos.z)
			local id=data[index]
			if id==air or id==ignore or id==leaves then
				data[index]=(industrialtest.random:next(0,5)==1 and treeWithRubber or tree)
			end
		end
		-- Force leaves near the trunk
		for dz=-1,1 do
			for dy=-2,1 do
				local index=area:index(pos.x-1,pos.y+height+dy,pos.z+dz)
				for dx=-1,1 do
					if data[index]==air or data[index]==ignore then
						data[index]=leaves
					end
					index=index+1
				end
			end
		end
		-- Randomly add leaves in 2x2x2 clusters.
		for i=1,8 do
			local x=pos.x+industrialtest.random:next(-2,1)
			local y=pos.y+height+industrialtest.random:next(-2,0)
			local z=pos.z+industrialtest.random:next(-2,1)
			for dx=0,1 do
				for dy=0,1 do
					for dz=0,1 do
						local index=area:index(x+dx,y+dy,z+dz)
						if data[index]==air or data[index]==ignore then
							data[index]=leaves
						end
					end
				end
			end
		end

		manip:set_data(data)
		manip:write_to_map()
		manip:update_map()
	end
	definition={
		description=S("Rubber Sapling"),
		inventory_image="industrialtest_rubber_sapling.png",
		wield_image="industrialtest_rubber_sapling.png",
		drawtype="plantlike",
		tiles={"industrialtest_rubber_sapling.png"},
		paramtype="light",
		sunlight_propagates=true,
		walkable=false,
		waving=1
	}
	if industrialtest.mtgAvailable then
		definition.sounds=default.node_sound_leaves_defaults()
		definition.groups={
			snappy=2,
			flammable=2
		}
		definition.on_construct=function(pos)
			minetest.get_node_timer(pos):start(industrialtest.random:next(300,1500))
		end
		definition.on_timer=function(pos)
			if not default.can_grow(pos) then
				minetest.get_node_timer(pos):start(300)
				return false
			end

			industrialtest.internal.makeRubberTree(pos)

			return false
		end
	elseif industrialtest.mclAvailable then
		definition.sounds=mcl_sounds.node_sound_leaves_defaults()
		definition.groups={
			plant=1,
			non_mycelium_plant=1,
			deco_block=1,
			dig_by_water=1,
			dig_by_piston=1,
			destroy_by_lava_flow=1,
			compostability=40
		}
		definition.on_construct=function(pos)
			local meta=minetest.get_meta(pos)
			meta:set_int("stage",0)
		end
		definition.on_place=mcl_util.generate_on_place_plant_function(function(pos,node)
			local nodeBelow = minetest.get_node_or_nil(vector.new(pos.x,pos.y-1,pos.z))
			if not nodeBelow then
				return false
			end
			local name = nodeBelow.name
			return minetest.get_item_group(name,"grass_block")==1 or
					name=="mcl_core:podzol" or name=="mcl_core:podzol_snow" or
					name=="mcl_core:dirt" or name=="mcl_core:mycelium" or name=="mcl_core:coarse_dirt"
		end)
		definition._on_bone_meal=function(itemstack,user,pointed)
			if industrialtest.random:next(1,100)>45 then
				return
			end
			local meta=minetest.get_meta(pointed.under)
			local stage=meta:get_int("stage") or 0
			stage=stage+1
			if stage>=3 then
				industrialtest.internal.makeRubberTree(pointed.under)
			else
				meta:set_int("stage",stage)
			end
		end
		minetest.register_abm({
			label="Rubber sapling growing",
			nodenames={"industrialtest:rubber_sapling"},
			interval=120,
			chance=1,
			catch_up=false,
			action=function(pos)
				local under=minetest.get_node_or_nil(vector.offset(pos,0,-1,0))
				if not under or minetest.get_item_group(under.name,"soil")==0 then
					return
				end
				local lightLevel=minetest.get_node_light(pos)
				if not lightLevel or lightLevel<13 then
					return
				end
				local meta=minetest.get_meta(pos)
				local stage=meta:get_int("stage") or 0
				stage=stage+1
				if stage>=3 then
					industrialtest.internal.makeRubberTree(pos)
				else
					meta:set_int("stage",stage)
				end
			end
		})
	end
	definition.groups.attached_node=1
	definition.groups.dig_immediate=3
	definition.groups.sapling=1
	minetest.register_node("industrialtest:rubber_sapling",definition)
	if industrialtest.mtgAvailable then
		minetest.register_lbm({
			name="industrialtest:rubber_sapling_lbm",
			nodenames={"industrialtest:rubber_sapling"},
			action=function(pos)
				minetest.get_node_timer(pos):start(industrialtest.random:next(300,1500))
			end
		})
	end
end

definition={
	description=S("Reinforced Stone"),
	tiles={"industrialtest_reinforced_stone.png"}
}
if industrialtest.mtgAvailable then
	definition.groups={cracky=3}
	definition.sounds=default.node_sound_stone_defaults()
	definition.on_blast=function(pos,intensity)
		if intensity>20 then
			minetest.remove_node(pos)
			minetest.add_item(pos,ItemStack("industrialtest:reinforced_stone"))
		end
	end
elseif industrialtest.mclAvailable then
	definition.groups={
		pickaxey=1,
		stone=1,
		building_block=1,
		material_stone=1
	}
	definition.sounds=mcl_sounds.node_sound_stone_defaults()
	definition._mcl_blast_resistance=1200
	definition._mcl_hardness=5
end
minetest.register_node("industrialtest:reinforced_stone",definition)
minetest.register_craft({
	type="shaped",
	output="industrialtest:reinforced_stone 8",
	recipe={
		{industrialtest.elementKeys.stone,industrialtest.elementKeys.stone,industrialtest.elementKeys.stone},
		{industrialtest.elementKeys.stone,"industrialtest:advanced_alloy",industrialtest.elementKeys.stone},
		{industrialtest.elementKeys.stone,industrialtest.elementKeys.stone,industrialtest.elementKeys.stone}
	}
})

definition={
	description=S("Reinforced Glass"),
	drawtype="glasslike_framed_optional",
	tiles={"industrialtest_reinforced_glass.png"},
	use_texture_alpha="clip",
	paramtype="light",
	sunlight_propagates=true
}
if industrialtest.mtgAvailable then
	definition.groups={cracky=3}
	definition.sounds=default.node_sound_glass_defaults()
	definition.on_blast=function(pos,intensity)
		if intensity>10 then
			minetest.remove_node(pos)
			minetest.add_item(pos,ItemStack("industrialtest:reinforced_glass"))
		end
	end
elseif industrialtest.mclAvailable then
	definition.groups={
		glass=1,
		building_block=1,
		material_glass=1
	}
	definition.sounds=mcl_sounds.node_sound_glass_defaults()
	definition._mcl_blast_resistance=15
	definition._mcl_hardness=1.5
end
minetest.register_node("industrialtest:reinforced_glass",definition)
minetest.register_craft({
	type="shaped",
	output="industrialtest:reinforced_glass 7",
	recipe={
		{industrialtest.elementKeys.glass,industrialtest.elementKeys.glass,industrialtest.elementKeys.glass},
		{"industrialtest:advanced_alloy",industrialtest.elementKeys.glass,"industrialtest:advanced_alloy"},
		{industrialtest.elementKeys.glass,industrialtest.elementKeys.glass,industrialtest.elementKeys.glass}
	}
})
minetest.register_craft({
	type="shaped",
	output="industrialtest:reinforced_glass 7",
	recipe={
		{industrialtest.elementKeys.glass,"industrialtest:advanced_alloy",industrialtest.elementKeys.glass},
		{industrialtest.elementKeys.glass,industrialtest.elementKeys.glass,industrialtest.elementKeys.glass},
		{industrialtest.elementKeys.glass,"industrialtest:advanced_alloy",industrialtest.elementKeys.glass}
	}
})

-- \brief Function which should be called after iron fence was constructed
-- \param pos vector
-- \returns nil
local function ironFenceOnConstruct(pos)
	local neighbours={
		vector.offset(pos,0,-1,0),
		vector.offset(pos,0,1,0)
	}
	for _,neighbourPosition in ipairs(neighbours) do
		local meta=minetest.get_meta(neighbourPosition)
		if meta:contains("magnetizerPosition") then
			local magnetizerPosition=minetest.deserialize(meta:get_string("magnetizerPosition"))
			industrialtest.Magnetizer:determineFenceRail(magnetizerPosition)
			industrialtest.Magnetizer:determinePowerCapacity(magnetizerPosition)
			industrialtest.Magnetizer:updateFormspec(magnetizerPosition)
			industrialtest.Magnetizer:requestPower(magnetizerPosition)
			break
		end
	end

	neighbours={
		vector.offset(pos,1,0,0),
		vector.offset(pos,-1,0,0),
		vector.offset(pos,0,0,1),
		vector.offset(pos,0,0,-1)
	}
	for _,neighbourPosition in ipairs(neighbours) do
		local neighbourNode=minetest.get_node(neighbourPosition)
		if neighbourNode.name=="industrialtest:magnetizer" then
			local meta=minetest.get_meta(neighbourPosition)
			if not meta:contains("railPosition") then
				industrialtest.Magnetizer:determineFenceRail(neighbourPosition)
				industrialtest.Magnetizer:determinePowerCapacity(neighbourPosition)
				industrialtest.Magnetizer:updateFormspec(neighbourPosition)
				industrialtest.Magnetizer:requestPower(neighbourPosition)
				break
			end
		end
	end
end

-- \brief Function which should be called before iron fence was removed
-- \param pos vector
-- \returns nil
local function ironFenceOnDestruct(pos)
	local meta=minetest.get_meta(pos)
	if not meta:contains("magnetizerPosition") then
		return
	end
	local magnetizerPosition=minetest.deserialize(meta:get_string("magnetizerPosition"))
	industrialtest.Magnetizer.detachFenceRail(magnetizerPosition)
end

-- \brief Function which should be called after iron fence was removed
-- \param meta table
-- \returns nil
local function ironFenceDetach(meta)
	if not meta or not meta.fields or not meta.fields.magnetizerPosition then
		return
	end
	local magnetizerPosition=minetest.deserialize(meta.fields.magnetizerPosition)
	industrialtest.Magnetizer:determineFenceRail(magnetizerPosition)
	industrialtest.Magnetizer:determinePowerCapacity(magnetizerPosition)
	industrialtest.Magnetizer:updateFormspec(magnetizerPosition)
end

if industrialtest.mtgAvailable then
	local inventoryImage="default_fence_overlay.png^default_steel_block.png^default_fence_overlay.png^[makealpha:255,126,126"
	default.register_fence("industrialtest:iron_fence",{
		description=S("Iron Fence"),
		texture="default_steel_block.png",
		inventory_image=inventoryImage,
		wield_image=inventoryImage,
		groups={
			cracky=1,
			level=2,
			_industrialtest_metalFence=1
		},
		sounds=default.node_sound_metal_defaults(),
		connects_to={
			"group:fence",
			"group:wood",
			"group:tree",
			"group:wall",
			"industrialtest:magnetizer"
		},
		on_construct=ironFenceOnConstruct,
		on_destruct=ironFenceOnDestruct,
		after_dig_node=function(pos,oldnode,oldmeta)
			ironFenceDetach(oldmeta)
		end
	})
	minetest.register_craft({
		type="shaped",
		output="industrialtest:iron_fence 4",
		recipe={
			{"industrialtest:iron_plate","industrialtest:iron_plate","industrialtest:iron_plate"},
			{"industrialtest:iron_plate","industrialtest:iron_plate","industrialtest:iron_plate"}
		}
	})
elseif industrialtest.mclAvailable then
	-- Some MCL2 forks define this function so use it if available
	if mcl_fences.register_fence_def then
		mcl_fences.register_fence_def("iron_fence",{
			description=S("Iron Fence"),
			tiles={"default_steel_block.png"},
			groups={
				_industrialtest_metalFence=1
			},
			connects_to={
				"group:fence",
				"group:fence_gate",
				"group:solid",
				"industrialtest:magnetizer"
			},
			on_construct=ironFenceOnConstruct,
			on_destruct=ironFenceOnDestruct,
			after_destruct=function(pos,oldnode,oldmeta)
				ironFenceDetach(oldmeta)
			end
		})
	else
		mcl_fences.register_fence("iron_fence",S("Iron Fence"),"default_steel_block.png",{_industrialtest_metalFence=1},4,5,{"industrialtest:magnetizer","group:fence"},mcl_sounds.node_sound_metal_defaults())
	end
	if minetest.registered_nodes["mcl_fences:iron_fence"] then
		-- mcl_fences.register_fence_def registers fences in it's own namespace so register alias here to keep compatibility
		minetest.register_alias("industrialtest:iron_fence","mcl_fences:iron_fence")
	end
	minetest.register_craft({
		type="shaped",
		output="industrialtest:iron_fence 3",
		recipe={
			{"industrialtest:iron_plate","industrialtest:iron_plate","industrialtest:iron_plate"},
			{"industrialtest:iron_plate","industrialtest:iron_plate","industrialtest:iron_plate"}
		}
	})
end
