---------------------------------------------------------------------------------------
-- simple anvil that can be used to repair tools
---------------------------------------------------------------------------------------
-- * can be used to repair tools
-- * the hammer gets damaged a bit at each repair step
---------------------------------------------------------------------------------------

anvil = {
	setting = {
		item_displacement = 2/16,
	}
}



local S = minetest.get_translator(minetest.get_current_modname())

-- the hammer for the anvil

minetest.register_tool("anvil:hammer", 
{
	description = S("Steel blacksmithing hammer.\nTo be used with the anvil, or as a weapon."),
	image           = "anvil_tool_steelhammer.png",
	inventory_image = "anvil_tool_steelhammer.png",
	groups={not_repaired_by_anvil=1}, -- Would be weird
	range=3,
	tool_capabilities = {
		full_punch_interval = 0.8,
		max_drop_level=1,
		groupcaps={
			-- cracky={times={[1]=5.50, [2]=2.80, [3]=1.90}, uses=150, maxlevel=2},
		},
		damage_groups = {fleshy=8, knockback=8},
		-- twice the cost of a steel sword, so twice the uses, but the extra damage, range, and snare
		-- adds to its value.
		punch_attack_uses = 1024,
	}
})

local tmp = {}

minetest.register_entity("anvil:item",{
	hp_max = 1,
	visual="wielditem",
	visual_size={x=.33,y=.33},
	collisionbox = {0,0,0,0,0,0},
	physical=false,
	textures={"air"},
	on_activate = function(self, staticdata)
		if tmp.nodename ~= nil and tmp.texture ~= nil then
			self.nodename = tmp.nodename
			tmp.nodename = nil
			self.texture = tmp.texture
			tmp.texture = nil
		else
			if staticdata ~= nil and staticdata ~= "" then
				local data = staticdata:split(';')
				if data and data[1] and data[2] then
					self.nodename = data[1]
					self.texture = data[2]
				end
			end
		end
		if self.texture ~= nil then
			self.object:set_properties({textures={self.texture}})
		end
	end,
	get_staticdata = function(self)
		if self.nodename ~= nil and self.texture ~= nil then
			return self.nodename .. ';' .. self.texture
		end
		return ""
	end,
})

local remove_item = function(pos, node)
	local objs = minetest.get_objects_inside_radius({x = pos.x, y = pos.y + anvil.setting.item_displacement, z = pos.z}, .5)
	if objs then
		for _, obj in ipairs(objs) do
			if obj and obj:get_luaentity() and obj:get_luaentity().name == "anvil:item" then
				obj:remove()
			end
		end
	end
end

local update_item = function(pos, node)
	local meta = minetest.get_meta(pos)
	local inv = meta:get_inventory()
	if not inv:is_empty("input") then
		pos.y = pos.y + anvil.setting.item_displacement
		tmp.nodename = node.name
		tmp.texture = inv:get_stack("input", 1):get_name()
		local e = minetest.add_entity(pos,"anvil:item")
		local yaw = math.pi*2 - node.param2 * math.pi/2
		if e.set_rotation == nil then
			-- This is for 0.4.16 support, remove it eventually
			e:set_yaw(yaw)
			pos.y = pos.y + 5/16
			e:set_pos(pos)
		else
			e:set_rotation({x=-1.5708, y=yaw, z=0}) -- x is pitch, 1.5708 is 90 degrees.
		end
	end
end

minetest.register_node("anvil:anvil", {
	drawtype = "nodebox",
	description = S("Anvil\nLet you repair crafted tools and armor.\nRight-click the anvil with the item to repair in hand, then use the hammer on it (separate craft)."),
	tiles = {"default_stone.png"},
	paramtype  = "light",
	paramtype2 = "facedir",
	groups = {cracky=1, protected=1, nopicker=1},
	sounds = default.node_sound_metal_defaults(),
	-- the nodebox model comes from realtest
	node_box = {
		type = "fixed",
		fixed = {
			{-0.5,-0.5,-0.3,0.5,-0.4,0.3},
			{-0.35,-0.4,-0.25,0.35,-0.3,0.25},
			{-0.3,-0.3,-0.15,0.3,-0.1,0.15},
			{-0.35,-0.1,-0.2,0.35,0.1,0.2},
		},
	},
	selection_box = {
		type = "fixed",
		fixed = {
			{-0.5,-0.5,-0.3,0.5,-0.4,0.3},
			{-0.35,-0.4,-0.25,0.35,-0.3,0.25},
			{-0.3,-0.3,-0.15,0.3,-0.1,0.15},
			{-0.35,-0.1,-0.2,0.35,0.1,0.2},
		}
	},

	on_construct = function(pos)
		local meta = minetest.get_meta(pos)
		local inv = meta:get_inventory()
		inv:set_size("input", 1)
	end,

	after_place_node = function(pos, placer)
		local meta = minetest.get_meta(pos)
		-- meta:set_string("owner", placer:get_player_name() or "")
		meta:set_string("infotext", S("Anvil"))
	end,

	can_dig = function(pos,player)
		local meta  = minetest.get_meta(pos)
		local inv   = meta:get_inventory()

		if not inv:is_empty("input") then
			return false
		end
		return true
	end,

	allow_metadata_inventory_put = function(pos, listname, index, stack, player)
		local meta = minetest.get_meta(pos)
		if listname~="input" then
			return 0
		end
		if (listname=='input') then
			if (stack:get_wear() == 0) then
				minetest.chat_send_player( player:get_player_name(), S('This anvil is for damaged tools only.'))
				return 0
			end
		
			if (minetest.get_item_group(stack:get_name(), "not_repaired_by_anvil") ~= 0) then
				local item_def = minetest.registered_items[stack:get_name()]
				minetest.chat_send_player( player:get_player_name(), S('@1 cannot be repaired with an anvil.', item_def.description))
				return 0
			end
		end

		if meta:get_inventory():room_for_item("input", stack) then
			return stack:get_count()
		end
		return 0
	end,

	allow_metadata_inventory_take = function(pos, listname, index, stack, player)
		if listname~="input" then
			return 0
		end
		return stack:get_count()
	end,

	on_rightclick = function(pos, node, clicker, itemstack)
		if not clicker or not itemstack then
			return
		end
		local name = clicker:get_player_name()

		if not mf.clan_ok(name, pos) then return end

		local meta = minetest.get_meta(pos)

		-- if name ~= meta:get_string("owner") then return itemstack end
		if itemstack:get_count() == 0 then
		local inv = meta:get_inventory()
			if not inv:is_empty("input") then
				local return_stack = inv:get_stack("input", 1)
				inv:set_stack("input", 1, nil)
				local wield_index = clicker:get_wield_index()
				clicker:get_inventory():set_stack("main", wield_index, return_stack)
				remove_item(pos, node)
				return return_stack
			end
		end
		local this_def = minetest.registered_nodes[node.name]
		if this_def.allow_metadata_inventory_put(pos, "input", 1, itemstack:peek_item(), clicker) > 0 then
			local s = itemstack:take_item()
			local meta = minetest.get_meta(pos)
			local inv = meta:get_inventory()
			inv:add_item("input", s)
			update_item(pos,node)
		end

		return itemstack
	end,

	on_punch = function(pos, node, puncher)
		if( not( pos ) or not( node ) or not( puncher )) then
			return
		end

		local wielded = puncher:get_wielded_item()
		local meta = minetest.get_meta(pos)
		local inv  = meta:get_inventory()
		--[[
		if meta:get_string("owner") ~= puncher:get_player_name() then
			return
		end
		--]]

		if wielded:get_count() == 0 then
			if not inv:is_empty("input") then
				local return_stack = inv:get_stack("input", 1)
				inv:set_stack("input", 1, nil)
				local wield_index = puncher:get_wield_index()
				puncher:get_inventory():set_stack("main", wield_index, return_stack)
				remove_item(pos, node)
			end
		end

		-- only punching with the hammer is supposed to work
		if wielded:get_name() ~= 'anvil:hammer' then
			return
		end

		local name=puncher:get_player_name()
		if mfplayers[name].energy < 1 then
			mfplayers[name].energy=0
			return
		end
		mfplayers[name].energy=mfplayers[name].energy-1

		local input = inv:get_stack('input',1)

		if not( input ) or input:is_empty() then
			return
		end


		-- tell the player when the job is done
		if(   input:get_wear() ~= 0 ) then
			pos.y = pos.y + anvil.setting.item_displacement
			minetest.sound_play({name="anvil_clang"}, {pos=pos})
			minetest.add_particlespawner({
			amount = 10,
			time = 0.1,
			minpos = pos,
			maxpos = pos,
			minvel = {x=2, y=3, z=2},
			maxvel = {x=-2, y=1, z=-2},
			minacc = {x=0, y= -10, z=0},
			maxacc = {x=0, y= -10, z=0},
			minexptime = 0.5,
			maxexptime = 1,
			minsize = 1,
			maxsize = 1,
			collisiondetection = true,
			vertical = false,
			texture = "anvil_spark.png",
			glow=7,
			})
		end

		-- do the actual repair
		input:add_wear(-128) -- input:add_wear( -5000 ) -- equals to what technic toolshop does in 5 seconds
		inv:set_stack("input", 1, input)

		-- damage the hammer
		wielded:add_wear(128)
		puncher:set_wielded_item( wielded )
	end,
	is_ground_content = false,
})

-- automatically restore entities lost due to /clearobjects or similar
--[[
minetest.register_lbm({
	name = "anvil:anvil_item_restoration",
	nodenames = { "anvil:anvil" },
	run_at_every_load = true,
	action = function(pos, node, active_object_count, active_object_count_wider)
		local test_pos = {x=pos.x, y=pos.y + anvil.setting.item_displacement, z=pos.z}
		if #minetest.get_objects_inside_radius(test_pos, 0.5) > 0 then return end
		update_item(pos, node)
	end
})
--]]

-- Transfer the hammer from the old hammer storage slot to the main slot, or else drop it in world
--[[
minetest.register_lbm({
	name = "anvil:hammer_ejection",
	nodenames = "anvil:anvil",
	run_at_every_load = false,
	action = function(pos, node)
		local meta = minetest.get_meta(pos)
		local inv  = meta:get_inventory()
		if not inv:is_empty("hammer") then
			local hammer = inv:get_stack("hammer", 1)
			inv:set_stack("hammer", 1, nil)
			inv:set_size("hammer", 0)
			if inv:is_empty("input") then
				inv:set_stack("input", 1, hammer) -- the abm will ensure there's an entity showing the hammer is here
			else
				minetest.add_item({x=pos.x, y=pos.y+1, z=pos.z}, hammer)
			end
		end
	end
})
--]]
---------------------------------------------------------------------------------------
-- crafting receipes
---------------------------------------------------------------------------------------
minetest.register_craft({
	output = "anvil:hammer",
	recipe = {
		{ "default:steel_ingot", "default:gold_ingot","default:steel_ingot"},
		{"","group:stick",""},
		{"", "group:stick",""},
	}
	-- The gold ingot is there to introduce a gold sink; otherwise once the players
	-- get their gold armor, since they can repair it, there don't need gold anymore
	-- except for furniture.
})

minetest.register_craft({
	output = "anvil:anvil",
	recipe = {
		{"default:steel_ingot","default:steel_ingot","default:steel_ingot"},
		{"","default:steel_ingot",""},
	}
})

