flowlib = {}

--sum of direction vectors must match an array index
local function to_unit_vector(dir_vector)
	--(sum,root)
	-- (0,1), (1,1+0=1), (2,1+1=2), (3,1+2^2=5), (4,2^2+2^2=8)
	local inv_roots = {[0] = 1, [1] = 1, [2] = 0.70710678118655, [4] = 0.5
		, [5] = 0.44721359549996, [8] = 0.35355339059327}
	local sum = dir_vector.x*dir_vector.x + dir_vector.z*dir_vector.z
	return {x=dir_vector.x*inv_roots[sum],y=dir_vector.y
		,z=dir_vector.z*inv_roots[sum]}
end

local is_touching = function(realpos,nodepos,radius)
	local boarder = 0.5 - radius
	return (math.abs(realpos - nodepos) > (boarder))
end

flowlib.is_touching = is_touching

local is_water = function(pos)
	return (minetest.get_item_group(minetest.get_node(
			{x=pos.x,y=pos.y,z=pos.z}).name
		, "water") ~= 0)
end

flowlib.is_water = is_water

local node_is_water = function(node)
	return (minetest.get_item_group(node.name, "water") ~= 0)
end

flowlib.node_is_water = node_is_water

local is_lava = function(pos)
	return (minetest.get_item_group(minetest.get_node(
			{x=pos.x,y=pos.y,z=pos.z}).name
		, "lava") ~= 0)
end

flowlib.is_lava = is_lava

local node_is_lava = function(node)
	return (minetest.get_item_group(node.name, "lava") ~= 0)
end

flowlib.node_is_lava = node_is_lava


local is_liquid = function(pos)
	return (minetest.get_item_group(minetest.get_node(
			{x=pos.x,y=pos.y,z=pos.z}).name
		, "liquid") ~= 0)
end

flowlib.is_liquid = is_liquid

local node_is_liquid = function(node)
	return (minetest.get_item_group(node.name, "liquid") ~= 0)
end

flowlib.node_is_liquid = node_is_liquid

--This code is more efficient
local function quick_flow_logic(node,pos_testing,direction)
	local name = node.name
	if not minetest.registered_nodes[name] then
		return 0
	end
	if minetest.registered_nodes[name].liquidtype == "source" then
		local node_testing = minetest.get_node(pos_testing)
		local param2_testing = node_testing.param2
		if not minetest.registered_nodes[node_testing.name] then
			return 0
		end
		if minetest.registered_nodes[node_testing.name].liquidtype 
		~= "flowing" then
			return 0
		else
			return direction
		end
	elseif minetest.registered_nodes[name].liquidtype == "flowing" then
		local node_testing = minetest.get_node(pos_testing)
		local param2_testing = node_testing.param2
		if not minetest.registered_nodes[node_testing.name] then
			return 0
		end
		if minetest.registered_nodes[node_testing.name].liquidtype 
		== "source" then
			return -direction
		elseif minetest.registered_nodes[node_testing.name].liquidtype 
		== "flowing" then
			if param2_testing < node.param2 then
				if (node.param2 - param2_testing) > 6 then
					return -direction
				else
					return direction
				end
			elseif param2_testing > node.param2 then
				if (param2_testing - node.param2) > 6 then
					return direction
				else
					return -direction
				end
			end
		end
	end
	return 0
end

local quick_flow = function(pos,node)
	local x = 0
	local z = 0
	
	if not node_is_liquid(node)  then
		return {x=0,y=0,z=0}
	end
	
	x = x + quick_flow_logic(node,{x=pos.x-1,y=pos.y,z=pos.z},-1)
	x = x + quick_flow_logic(node,{x=pos.x+1,y=pos.y,z=pos.z}, 1)
	z = z + quick_flow_logic(node,{x=pos.x,y=pos.y,z=pos.z-1},-1)
	z = z + quick_flow_logic(node,{x=pos.x,y=pos.y,z=pos.z+1}, 1)
	
	return to_unit_vector({x=x,y=0,z=z})
end

flowlib.quick_flow = quick_flow


	--if not in water but touching, move centre to touching block
	--x has higher precedence than z
	--if pos changes with x, it affects z
local move_centre = function(pos,realpos,node,radius)
	if is_touching(realpos.x,pos.x,radius) then
		if is_liquid({x=pos.x-1,y=pos.y,z=pos.z}) then
			node = minetest.get_node({x=pos.x-1,y=pos.y,z=pos.z})
			pos = {x=pos.x-1,y=pos.y,z=pos.z}
		elseif is_liquid({x=pos.x+1,y=pos.y,z=pos.z}) then
			node = minetest.get_node({x=pos.x+1,y=pos.y,z=pos.z})
			pos = {x=pos.x+1,y=pos.y,z=pos.z}
		end
	end
	if is_touching(realpos.z,pos.z,radius) then
		if is_liquid({x=pos.x,y=pos.y,z=pos.z-1}) then
			node = minetest.get_node({x=pos.x,y=pos.y,z=pos.z-1})
			pos = {x=pos.x,y=pos.y,z=pos.z-1}
		elseif is_liquid({x=pos.x,y=pos.y,z=pos.z+1}) then
			node = minetest.get_node({x=pos.x,y=pos.y,z=pos.z+1})
			pos = {x=pos.x,y=pos.y,z=pos.z+1}
		end
	end
	return pos,node
end

flowlib.move_centre = move_centre