local constants = {
	farcaster_nonlocal_cost = 0.1;
	-- the amount of power it takes to cast 50 nodes away
}
minetest.register_node('sorcery:raycaster', {
	description = 'Raycaster';
	groups = { cracky = 2; sorcery_ley_device = 1; sorcery_magitech = 1; };
	paramtype2 = 'facedir';
	tiles = {
		'sorcery_farcaster_linear_top.png';
		'sorcery_farcaster_linear_bottom.png';
		'sorcery_farcaster_linear_side.png';
	};
	_sorcery = {
		ley = {
			mode = 'consume', affinity = {'mandatic'};
			power = function(pos,delta)
				local tune = sorcery.attunement.verify(pos)
				if tune then return 0.3 else return 0 end
			end
		};
		attune = {
			class = 'sorcery:raycaster', accepts = 'sorcery:raycaster';
			source = true, target = true, reciprocal = true;
		};
		farcaster = {
			partner = function(pos)
				local tune = sorcery.attunement.verify(pos)
				print('   *!* verifying farcaster tuning',tune)
				if not tune then return nil end
				minetest.load_area(tune.partner)
				local vis = false
				local ignored
				repeat
					ignored = false
					for _,p in pairs(sorcery.lib.node.offsets.neighbors) do
						local sum = vector.add(pos,p)
						local _, stop = minetest.line_of_sight(sum,tune.partner) 
						if vector.equals(stop, tune.partner) then
							vis = true 
							break
						else
							if minetest.get_node(stop).name == 'ignore' then
								minetest.load_area(stop)
								ignored = true
							end
						end
					end
				until ignored == false
				if vis == true
					then return tune.partner
					else return nil
				end
			end;
		};
	};
})

minetest.register_node('sorcery:farcaster', {
	description = 'Farcaster';
	paramtype2 = 'facedir';
	groups = { cracky = 2; sorcery_ley_device = 1; sorcery_magitech = 1; };
	tiles = {
		'sorcery_farcaster_nonlocal_top.png';
		'sorcery_farcaster_nonlocal_top.png';
		'sorcery_farcaster_nonlocal_side.png';
		'sorcery_farcaster_nonlocal_side.png';
		'sorcery_farcaster_nonlocal_back.png';
		'sorcery_farcaster_nonlocal_front.png';
	};
	_sorcery = {
		ley = { mode = 'consume'; affinity = {'mandatic'};
			power = function(pos,delta)
				local tune = sorcery.attunement.verify(pos)
				if not tune then
					return 0
				else
					return (vector.distance(pos,tune.partner) / 50) * constants.farcaster_nonlocal_cost
				end
			end;
		};
		attune = {
			class = 'sorcery:farcaster', accepts = 'sorcery:farcaster';
			source = true, target = true, reciprocal = true;
		};
		farcaster = {
			partner = function(pos)
				local tune = sorcery.attunement.verify(pos)
				if not tune then return nil end

				return tune.partner
			end;
		}
	};
})

sorcery.farcaster = {}
sorcery.farcaster.junction = function(start,minconduct)
	local stack = {{pos = start, hops = 0, route = {}}}
	local checked, network = {},{}
	local checkedp = function(pos)
		for _,v in pairs(checked) do
			if vector.equals(pos,v) then return true end
		end
		return false
	end
	local i = 1 repeat
		local caps = sorcery.ley.netcaps(stack[i].pos,1,nil,minconduct)
		network[#network+1] = {
			caps = caps;
			hops = stack[i].hops;
			route = stack[i].route;
		}
		for _,d in pairs(caps.net.devices.consume) do
			if not checkedp(d.pos) then
				checked[#checked+1] = d.pos
				local def = minetest.registered_nodes[d.id]
				if def and def._sorcery and def._sorcery.farcaster then
					local fc = def._sorcery.farcaster
					local p = fc.partner(d.pos)
					if p ~= nil and d.powerdraw >= d.minpower and not checkedp(p) then
						local nr = table.copy(stack[i].route)
						checked[#checked+1] = p
						nr[#nr+1] = d.pos
						stack[#stack+1] = {
							pos = p;
							route = nr;
							hops = stack[i].hops + 1;
						}
					else
					end
				end
			end
		end
	i = i + 1 until i > #stack

	return network
end
