//
/*
	VNS: Viral Noding System
		-- Component For Astar Pathfinding
			-- Author: Wattled Walnut
*/

local vns = {
	nodes = {},
	limit = 150,
	scale = 150,
	f = Vector( 1,0,0 ),
	r = Vector( 0,1,0 ),
	u = Vector( 0,0,1 ),
}

function vns:chat( sstring )
	chat.AddText( Color( 80,80,80,255 ),"[ VNS ] ",Color( 255,255,255,255 ),sstring )
end

function vns:configure( limit,scale )
	self.limit = limit
	self.scale = scale
	self:chat( "Noding Scale and Limitations ReConfigured, Limit: "..limit.." Scale: "..scale )
end

local limit = 0

function vns:node_exists( lx,ly,lz ) 
	if ( self.nodes[ lx ] != nil ) then
		if ( self.nodes[ lx ][ ly ] != nil ) then
			if ( self.nodes[ lx ][ ly ][ lz ] != nil ) then
				return true
			else
				return false
			end
		end
	end
end

function vns:create_node( lx,ly,lz,vector )
	if ( self:node_exists( lx,ly,lz ) ) then return end
	print( limit )
	if ( self.nodes[ lx ] == nil ) then
		self.nodes[ lx ] = {}
	end
	if ( self.nodes[ lx ][ ly ] == nil ) then
		self.nodes[ lx ][ ly ] = {}
	end
	self.nodes[ lx ][ ly ][ lz ] = vector
	limit = limit + 1
end


function vns:trace( vector,vector_2 )
	local tr = {}
	tr.start = vector
	tr.endpos = vector_2
	tr.mask = MASK_SOLID
	tr.filter = LocalPlayer()
	local trace = util.TraceLine( tr )
	return trace
end

function vns:ps( lx,ly,lz,nx,ny,nz,direction ) // positioning system
	if ( limit >= self.limit ) then return end
	local curnode = self.nodes[ lx ][ ly ][ lz ]
	local new_v = curnode + ( self.scale * direction )
	if ( !self:trace( curnode,new_v ).Hit ) then // Yay no collisions
		local g = self:trace( new_v,new_v - Vector( 0,0,99999 ) )
		self:create_node( nx,ny,nz,g.HitPos + Vector( 0,0,25 ) )
		self:populate( nx,ny,nz )
	else
		new_v = new_v + ( self.scale * self.u )
		if ( !self:trace( curnode,new_v ).Hit ) then
			local g = self:trace( new_v,new_v - Vector( 0,0,99999 ) )
			self:create_node( nx,ny,nz + 1,g.HitPos + Vector( 0,0,25 ) )
			self:populate( nx,ny,nz + 1 )
		end
	end
end

function vns:populate( lx,ly,lz )
	if ( !self:node_exists( lx,ly,lz ) ) then self:chat( "Non-Existant Node Lx: "..lx.." Ly: "..ly.." Lz: "..lz.." Process Denied" ) return end
	if ( limit >= self.limit ) then return end
	// Forward
	timer.Simple( .15,function()
		self:ps( lx,ly,lz,lx + 1,ly,lz,self.f,1 )
	
	// Backward
	timer.Simple( .30,function()
		self:ps( lx,ly,lz,lx - 1,ly,lz,-self.f,1.5 )
	end )
	// Right
	timer.Simple( .45,function()
		self:ps( lx,ly,lz,lx,ly + 1,lz,self.r,2 )
	end )
	// Left
	timer.Simple( 1,function()
		self:ps( lx,ly,lz,lx,ly - 1,lz,-self.r,2.5 )
	end )
	
	end )
	
end
vns:create_node( 0,0,0,LocalPlayer():GetPos() + Vector( 0,0,25 ) )
vns:populate( 0,0,0 )

------

local function drawnodes()
	surface.SetDrawColor( 250,250,80,200 )
	for x,_ in pairs( vns.nodes ) do
		for y,__ in pairs( vns.nodes[x] ) do
			for z,___ in pairs( vns.nodes[x][y] ) do
				local pos = vns.nodes[x][y][z]
				if ( pos:Distance( LocalPlayer():GetPos() + Vector( 0,0,25 ) ) <= 325 ) then
					local spos = pos:ToScreen()
					if ( spos.visible ) then
						surface.DrawRect( spos.x - 5,spos.y - 5,10,10 )
					end
				end
			end
		end
	end
end
//hook.Add( "HUDPaint","drawnodes",drawnodes )

local dumptable = {}
local function dump()
	for x,_ in pairs( vns.nodes ) do
		for y,__ in pairs( vns.nodes[x] ) do
			for z,___ in pairs( vns.nodes[x][y] ) do
				table.insert( dumptable,vns.nodes[x][y][z] )
			end
		end
	end
end
//dump()

concommand.Add( "dump_nodes",dump )
concommand.Add( "print_dump",function()
	PrintTable( dumptable )
end)
