local utils = ...



if minetest.get_translator and minetest.get_translator ("lwcomponents") then
	utils.S = minetest.get_translator ("lwcomponents")
elseif minetest.global_exists ("intllib") then
   if intllib.make_gettext_pair then
      utils.S = intllib.make_gettext_pair ()
   else
      utils.S = intllib.Getter ()
   end
else
   utils.S = function (s) return s end
end



-- check for mesecon
if minetest.global_exists ("mesecon") then
	utils.mesecon_supported = true
	utils.mesecon_state_on = mesecon.state.on
	utils.mesecon_state_off = mesecon.state.off
	utils.mesecon_receptor_on = mesecon.receptor_on
	utils.mesecon_receptor_off = mesecon.receptor_off
	utils.mesecon_default_rules = mesecon.rules.default
	utils.mesecon_flat_rules = mesecon.rules.flat

else
	utils.mesecon_supported = false
	utils.mesecon_state_on = "on"
	utils.mesecon_state_off = "off"
	utils.mesecon_default_rules = { }
	utils.mesecon_flat_rules = { }

	-- dummies
	utils.mesecon_receptor_on = function (pos, rules)
	end

	utils.mesecon_receptor_off = function (pos, rules)
	end

end



-- check for digilines
if minetest.global_exists ("digilines") then
	utils.digilines_supported = true
	utils.digilines_default_rules = digiline.rules.default
	utils.digilines_flat_rules = {
		{ x =  1, y = 0, z =  0 },
		{ x = -1, y = 0, z =  0 },
		{ x =  0, y = 0, z =  1 },
		{ x =  0, y = 0, z = -1 },
	}
	utils.digilines_receptor_send = digilines.receptor_send
else
	utils.digilines_supported = false
	utils.digilines_default_rules = { }
	utils.digilines_flat_rules = { }

	-- dummy
	utils.digilines_receptor_send = function (pos, rules, channel, msg)
	end
end



-- check for unifieddyes
if minetest.global_exists ("unifieddyes") then
	utils.unifieddyes_supported = true
else
	utils.unifieddyes_supported = false
end



-- check for hopper
if minetest.global_exists ("hopper") then
	utils.hopper_supported = true

	utils.hopper_add_container = function (list)
		hopper:add_container (list)
	end
else
	utils.hopper_supported = false

	utils.hopper_add_container = function (list)
	end
end



-- check for digistuff
if minetest.global_exists ("digistuff") then
	utils.digistuff_supported = true
else
	utils.digistuff_supported = false
end



-- check for pipeworks
if minetest.global_exists ("pipeworks") then
	utils.pipeworks_supported = true
	utils.pipeworks_after_place = pipeworks.after_place
	utils.pipeworks_after_dig = pipeworks.after_dig
else
	utils.pipeworks_supported = false
	utils.pipeworks_after_place = function (pos)
	end
	utils.pipeworks_after_dig = function (pos)
	end
end



function utils.on_destroy (itemstack)
	local stack = ItemStack (itemstack)

	if stack and stack:get_count () > 0 then
		local def = utils.find_item_def (stack:get_name ())

		if def and def.on_destroy then
			def.on_destroy (stack)
		end
	end
end



function utils.item_pickup (entity, cleanup)
	local stack = nil

	if entity and entity.name and entity.name == "__builtin:item" and
		entity.itemstring and entity.itemstring ~= "" then

		stack = ItemStack (entity.itemstring)

		if cleanup ~= false then
			entity.itemstring = ""
			entity.object:remove ()
		end
	end

	return stack
end



function utils.item_drop (itemstack, dropper, pos)
	if itemstack then
		local def = utils.find_item_def (itemstack:get_name ())

		if def and def.on_drop then
			return def.on_drop (itemstack, dropper, pos)
		end
	end

	return minetest.item_drop (itemstack, dropper, pos)
end



function utils.can_interact_with_node (pos, player)
	if not player or not player:is_player () then
		return false
	end

	if minetest.check_player_privs (player, "protection_bypass") then
		return true
	end

	local meta = minetest.get_meta (pos)
	if meta then
		local owner = meta:get_string ("owner")
		local name = player:get_player_name ()

		if not owner or owner == "" or owner == name then
			return true
		end
	end

	return false
end


utils.allow_metadata_inventory_move = function(pos, from_list, from_index,
		to_list, to_index, count, player)
	if not utils.can_interact_with_node(pos, player) then
		return 0
	end
	return count
end
utils.allow_metadata_inventory_put = function(pos, listname, index, stack, player)
	if not utils.can_interact_with_node(pos, player) then
		return 0
	end
	return stack:get_count()
end
utils.allow_metadata_inventory_take = function(pos, listname, index, stack, player)
	if not utils.can_interact_with_node(pos, player) then
		return 0
	end
	return stack:get_count()
end


function utils.get_far_node (pos)
	local node = minetest.get_node (pos)

	if node.name == "ignore" then
		minetest.get_voxel_manip ():read_from_map (pos, pos)

		node = minetest.get_node (pos)

		if node.name == "ignore" then
			return nil
		end
	end

	return node
end



function utils.find_item_def (name)
	local def = minetest.registered_items[name]

	if not def then
		def = minetest.registered_craftitems[name]
	end

	if not def then
		def = minetest.registered_nodes[name]
	end

	if not def then
		def = minetest.registered_tools[name]
	end

	return def
end



function utils.table_equal (t1, t2)
	for k, v in pairs (t1) do
		if type (t2[k]) ~= type (v) then
			return false
		end

		if type (v) == "table" then
			if not utils.table_equal (v, t2[k]) then
				return false
			end
		elseif v ~= t2[k] then
			return false
		end
	end

	for k, v in pairs (t2) do
		if type (t1[k]) ~= type (v) then
			return false
		end

		if type (v) == "table" then
			if not utils.table_equal (v, t1[k]) then
				return false
			end
		elseif v ~= t1[k] then
			return false
		end
	end

	return true
end



function utils.is_same_item (item1, item2)
	local copy1 = ItemStack (item1)
	local copy2 = ItemStack (item2)

	if copy1 and copy2 then
		copy1:set_count (1)
		copy2:set_count (1)

		return utils.table_equal (copy1:to_table (), copy2:to_table ())
	end

	return false
end



function utils.unescape_description (description)
	description = description:gsub (string.char (27, 70), ""):
									  gsub (string.char (27, 69), ""):
									  gsub ("\n", " ")

	local first = description:find (string.char (27, 40, 84, 64), 1, true)
	while first do
		local last = description:find (")", first + 4, true)

		if not last then
			last = first + 3
		end

		description = description:sub (1, first - 1)..description:sub (last + 1)

		first = description:find (string.char (27, 40, 84, 64), 1, true)
	end

	return description
end



function utils.is_drop (obj)
	if obj then
		local entity = obj.get_luaentity and obj:get_luaentity ()

		return (entity and entity.name and entity.name == "__builtin:item")
	end

	return false
end



function utils.destroy_node (pos)
	local node = utils.get_far_node (pos)

	if node then
		local items = minetest.get_node_drops (node, nil)

		if items then
			for i = 1, #items do
				local stack = ItemStack (items[i])

				if stack and not stack:is_empty () then
					local name = stack:get_name ()
					local def = utils.find_item_def (name)

					if def then
						if def.preserve_metadata then
							def.preserve_metadata (pos, node, minetest.get_meta (pos), { stack })
						end

						utils.on_destroy (stack)
					end
				end
			end
		end

		minetest.remove_node (pos)
	end
end



utils.registered_spawners = { }
-- each entry [spawner_itemname] = spawner_func



function utils.register_spawner (itemname, spawn_func)
	if type (itemname) == "string" and type (spawn_func) == "function" then
		if not utils.registered_spawners[itemname] then
			utils.registered_spawners[itemname] = spawn_func

			return true
		end
	end

	return false
end



function utils.spawn_registered (itemname, spawn_pos, itemstack, owner, spawner_pos, spawner_dir, force)
	local func = utils.registered_spawners[itemname]

	if func then
		local result, obj, cancel = pcall (func, spawn_pos, itemstack, owner, spawner_pos, spawner_dir, force)

		if result and (obj == nil or type (obj) == "userdata" or type (obj) == "table") then
			return obj, cancel
		end

		minetest.log ("error", "lwcomponents.register_spawner spawner function for "..itemname.." failed "..
									  ((type (obj) == "string" and obj) or ""))

		return nil, true
	end

	return nil, false
end



function utils.can_place (pos)
	local node = minetest.get_node_or_nil (pos)

	if node and node.name ~= "air" then
		local def = minetest.registered_nodes[node.name]

		if not def or not def.buildable_to then
			return false
		end
	end

	return true
end



function utils.is_protected (pos, player)
	local name = (player and player:get_player_name ()) or ""

	return minetest.is_protected (pos, name)
end



function utils.get_on_rightclick (pos, player)
	local node = minetest.get_node_or_nil (pos)

	if node then
		local def = minetest.registered_nodes[node.name]

		if def and def.on_rightclick and
			not (player and player:is_player () and
				  player:get_player_control ().sneak) then

				return def.on_rightclick
		end
	end

	return nil
end



function utils.is_creative (player)
	if minetest.settings:get_bool ("creative_mode") then
		return true
	end

	if player and player:is_player () then
		return minetest.is_creative_enabled (player:get_player_name ()) or
				 minetest.check_player_privs (player, "creative")
	end

	return false
end



local crafting_mods = dofile (minetest.get_modpath ("lwcomponents").."/crafting_mods.lua")


function utils.get_crafting_mods (item)
	return crafting_mods[item]
end



--
