local range = 100
local v = 1
local a = 100
local speed = 0.1 --0 or less for default maximum speed

local function spray_foam(pos)
	if minetest.get_node(pos).name == "extinguisher:foam" then
		-- Do not spray foam onto foam
		return
	end
	for z = -1,1 do
		for y = -1,1 do
			for x = -1,1 do
				local p = {x=pos.x+x, y=pos.y+y, z=pos.z+z}
				local nn = minetest.get_node(p).name
				if nn == "fire:basic_flame" or nn == "fire:permanent_flame" then
					minetest.set_node(p, {name="air"})
					minetest.sound_play("fire_extinguish_flame",
						{pos = p, max_hear_distance = 16, gain = 0.15})
					minetest.check_for_falling(p)
				elseif math.random(0,3) >= 1 then
					if nn == "air" then
						minetest.set_node(p, {name="air"})
						minetest.check_for_falling(p)
					
					end
				end
			end
		end
	end
end

local function extinguish(player)
	--local t1 = os.clock()

	local playerpos = player:get_pos()
	local dir = player:get_look_dir()

	local startpos = vector.new(playerpos)
	startpos.y = startpos.y+1.625
	local bl, pos = minetest.line_of_sight(startpos,
		vector.add(vector.multiply(dir, range), startpos), 1)
	local snd = minetest.sound_play("extinguisher",
		{pos = playerpos, gain = 0.5, max_hear_distance = range})
	local flight_time = 1
	if pos then
		local s = math.max(vector.distance(startpos, pos)-0.5, 0)
		flight_time = (math.sqrt(v * v + 2 * a * s) - v) / a
	end
	if not bl then
		minetest.after(flight_time, function()
			-- Extinguish the node
			minetest.sound_stop(snd)
			spray_foam(vector.round(pos))
		end)
	end
	minetest.add_particle({
		pos = startpos,
		velocity = vector.multiply(dir, v),
		acceleration = vector.multiply(dir, a),
		expirationtime = flight_time,
		size = 1,
		texture = "extinguisher_shot.png^[transform" .. math.random(0,7),
	})

	--print("[extinguisher] my shot was calculated after "..tostring(os.clock()-t1).."s")
end


--[[
local function table_empty(t)
	for _,_ in pairs(t) do
		return false
	end
	return true
end

local function get_tab(pos)
	local tab_tmp = {pos}
	local tab_avoid = {[pos.x.." "..pos.y.." "..pos.z] = true}
	local tab_done,num = {pos},2
	while not table_empty(tab_tmp) do
		for n,p in pairs(tab_tmp) do
			tab_tmp[n] = nil
			for z = -2,2 do
				for y = -2,2 do
					for x = -2,2 do
						local p2 = {x=pos.x+x, y=pos.y+y, z=pos.z+z}
						local pstr = p2.x.." "..p2.y.." "..p2.z
						if not tab_avoid[pstr]
						and minetest.get_node(p2).name == "fire:basic_flame" then
							tab_avoid[pstr] = true
							tab_done[num] = p2
							num = num+1
							table.insert(tab_tmp, p2)
						end
					end
				end
			end
		end
	end
	return tab_done
end]]

local function stop_all_fire_sounds()
	local players = minetest.get_connected_players()
	for i = 1, #players do
		fire.update_player_sound(players[i])
	end
end

local c_fire, c_foam, c_lava, c_lavaf, c_obsidian, c_cobble
local function extinguish_fire(pos)
	local t1 = os.clock()
	c_fire = c_fire or minetest.get_content_id("fire:basic_flame")
	c_fire1 = c_fire1 or minetest.get_content_id("fire:permanent_flame")
	c_foam = c_foam or minetest.get_content_id("extinguisher:foam")
	
	local tab = vector.explosion_table(40)

	local manip = minetest.get_voxel_manip()
	local emerged_pos1, emerged_pos2 = manip:read_from_map(vector.add(pos, -40),
		vector.add(pos, 40))
	local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2})
	local nodes = manip:get_data()

	for _,i in pairs(tab) do
		local ran = i[2]
		if not ran
		or math.random(2) == 1 then
			local p = area:indexp(vector.add(pos, i[1]))
			local d_p = nodes[p]
			if d_p == c_fire then
				nodes[p] = air;
			elseif d_p == c_fire1 then
				nodes[p] = air;
			end
		end
	end

	manip:set_data(nodes)
	manip:write_to_map()
	stop_all_fire_sounds()
	print(string.format("[extinguisher] exploded at %s after ca. %.2fs",
		minetest.pos_to_string(pos), os.clock() - t1))
	--[[t1 = os.clock()
	manip:update_map()
	print(string.format("[extinguisher] map updated after ca. %.2fs", os.clock() - t1))]]
end

local function eexpl(pos)
	if minetest.get_node(pos).name ~= "extinguisher:automatic" then
		return
	end
	minetest.sound_play("extinguisher_explosion", {pos=pos})
	minetest.set_node(pos, {name="extinguisher:destroyed"})
	local startpos = minetest.find_node_near(pos, 2, {"fire:basic_flame"})
	if not startpos then
		return
	end
	extinguish_fire(startpos)
end


minetest.register_node(":extinguisher:foam", {
	drawtype = "nodebox",
	paramtype = "light",
	node_box = {
		type = "fixed",
		fixed = {
			{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
		}
	},
	use_texture_alpha = "blend",
	tiles = {"extinguisher_foam.png"},
	drop = "",
	groups = {dig_immediate=3, puts_out_fire=1, not_in_creative_inventory=1, falling_node=1},
})

local adtime = 0
local time = minetest.get_us_time()
local count = 0
minetest.register_abm({
	nodenames = {"extinguisher:foam"},
	interval = 5,
	chance = 5,
	catch_up = false,
	action = function(pos)
		count = count+1
		local ct = minetest.get_us_time()
		if count > 10
		and ct-time < 1000000 then
			return
		end
		time = ct
		count = 0
		minetest.remove_node(pos)
		if adtime < 0.1 then
			minetest.check_for_falling(pos)
		end
	end,
})

minetest.register_node(":extinguisher:automatic", {
	description = "Extinguisher",
	tiles = {"extinguisher_top.png", "extinguisher_bottom.png",
		"extinguisher.png", "extinguisher.png^[transformFX",
		"extinguisher_front.png", "extinguisher_back.png"},
	use_texture_alpha = "opaque",
	inventory_image = "extinguisher.png",
	wield_image = "extinguisher_pipe.png",
	paramtype = "light",
	drawtype = "nodebox",
	node_box = {
		type = "fixed",
		fixed = {
			-- Main bottle
			{-2/16, -0.5, -5/16, 3/16, 0, 0},
			{-1/16, 0, -5/16, 2/16, 3/16, 0},
			{-2/16, 0, -4/16, 3/16, 3/16, -1/16},
			{-1/16, 3/16, -4/16, 2/16, 5/16, -1/16},
			{0, 5/16, -3/16, 1/16, 6/16, -2/16},

			-- Outlet
			{0, 3/16, -1/16, 1/16, 4/16, 2/16},
			{-1/16, 3/16, 2/16, 0, 4/16, 4/16},
			{1/16, 3/16, 2/16, 2/16, 4/16, 4/16},
			{0, 4/16, 2/16, 1/16, 5/16, 6/16},
			{0, 2/16, 2/16, 1/16, 3/16, 6/16},

			-- Handle
			{0, 6/16, -6/16, 1/16, 7/16, -1/16},
			{-1/16, 6/16, -3/16, 2/16, 7/16, -2/16},
			{0, 5/16, -7/16, 1/16, 6/16, -5/16},
			{0, 4/16, -7/16, 1/16, 5/16, -6/16},
		},
	},
	groups = {dig_immediate=2},
	sounds = {dig=""},
	on_punch = function(pos, _, player)
		minetest.sound_play("extinguisher_touch", {pos=pos, gain=0.25, max_hear_distance=8})
		if player:get_wielded_item():get_name() == "main:torch" then
			minetest.after(math.random()*5, eexpl, pos)
		end
	end,
	on_use = function() -- do not dig or punch nodes
	end,
})

minetest.register_node(":extinguisher:destroyed", {
	description = "Destroyed Extinguisher",
	tiles = {"extinguisher_top.png", "extinguisher_bottom.png",
		"extinguisher.png", "extinguisher.png^[transformFX",
		"extinguisher_front.png", "extinguisher_destroyed.png"},
	use_texture_alpha = "opaque",
	inventory_image = "extinguisher.png",
	wield_image = "extinguisher_pipe.png",
	paramtype = "light",
	drawtype = "nodebox",
	node_box = {
		type = "fixed",
		fixed = {
			-- Main bottle
			{-2/16, -0.5, -3/16, 3/16, 0, 0},
			{-1/16, 0, -5/16, 1/16, 3/16, 0},
			{-1/16, 0, -4/16, 3/16, 3/16, -1/16},
			{-1/16, -3/16, -4/16, 2/16, 4/16, -1/16},
		},
	},
	groups = {dig_immediate=2},
	sounds = {dig=""},
	on_punch = function(pos, _, player)
		minetest.sound_play("extinguisher_touch", {pos=pos, gain=0.25, max_hear_distance=8})
		if player:get_wielded_item():get_name() == "main:torch" then
			minetest.after(math.random()*5, eexpl, pos)
		end
	end,
	on_use = function() -- do not dig or punch nodes
	end,
})

local timer = 0
minetest.register_globalstep(function(dtime)
	adtime = dtime
	timer = timer+dtime
	if timer < speed then
		return
	end
	timer = 0
	for _,player in pairs(minetest.get_connected_players()) do
		if player:get_wielded_item():get_name() == "extinguisher:automatic"
		and player:get_player_control().LMB then
			extinguish(player)
		end
	end
end)





