:NAME patrol

:PARAM float32		unused

:VAR boolean		enabled
:VAR boolean		attached
:VAR boolean		first_tick
:VAR c_object*		current_node
:VAR c_object*		current_link
:VAR int16			current_point_index
:VAR int16			point_index_delta


:CONFIG boolean		start_patrol_when_placed

-- -------------------- CONSTANTS --------------------

local vectorlib = require "scripts/vector_math"

k_attach_distance= 10


-- -------------------- INITIALIZATION --------------------

function param_initialize(p)
	p.unused= 0
end

function var_initialize(v)
	v.enabled= true
	v.attached= false
	v.first_tick= true
	v.current_node= nil
	v.current_link= nil
	v.current_point_index= -1
	v.point_index_delta= 0
	
end

function config_initialize(c)
	c.start_patrol_when_placed= false
end

-- -------------------- CODE --------------------


function attempt_attach(object)

	-- look for a graph node component with a patrol_data on it
	
	local ws= world_state_get()
	local iterator= ws.component_cache.component_graph_node.iterator_get()
	local best_graph_node= nil
	local best_distance= k_attach_distance
	local object_position= object.world_position_get()
	local result= false
		
	while (true) do
		local node= iterator.next()
		if (node) then
			local pdata= node.object._c.patrol_data
			if (pdata) then
				local patrol_position= node.object.world_position_get()
				local distance= vectorlib.distance2d(object_position, patrol_position)
				if (distance < best_distance) then
					best_distance= distance
					best_graph_node= node.object
				end
			end
		else
			break
		end	
	end

	if (best_graph_node) then
		if (attempt_next_link(object, best_graph_node)) then
			result= true
		end
	end
	
	return result
end

function attempt_next_link(object, node_object)
	local best_dot= -2
	local best_next_node= nil
	local best_next_link= nil
	local best_delta= 0
	local result= false
	local forward= nil
	
	local laf= object.laf_get()
	if (laf) then
		forward= laf.face_state.vector
	else
		forward= object.forward_vector_get();
	end
	
	local node= node_object.graph_node_get()
	local link_count= node.get_link_count()
	for i= 0, link_count-1 do
		local link_object= node.get_link(i)
		local link= link_object.graph_link_get()
		if (link) then

			--print("node object")
			--print(node_object)
			--print(link_object)
			--print(link)
		
			local t= 1
			local index= 1
			--print(link.nodes[0])
			--print(link.nodes[1])
			if (link.nodes[0]==node_object) then
				-- if we are at nodes[0], we are at the start of the link
				t= 0
				index= 0
			end
			
			--print("index: "..index)

			local v= link.get_vector(t)
			if (index==1) then
				vectorlib.scale(v, -1)
			end
			
			local mag= vectorlib.normalize2d(v)
			if (mag > 0) then
				local d= vectorlib.dot2d(v, forward)
				--print("d: "..d)
				if (d > best_dot) then
					best_next_node= link.nodes[1-index]
					best_next_link= link
					best_dot= d
				end
			end
		end	
	end
	
	if (best_next_node and best_next_link) then
		local point_count= best_next_link.get_point_count()
		if (point_count > 1) then

			var.current_node= best_next_node
			var.current_link= best_next_link.object

			if (best_next_link.nodes[0]==best_next_node) then
				-- going from the end to the beginning
				-- remember, first thing we're going to do is advance to the next point
				var.current_point_index= point_count-1
				var.point_index_delta= -1
			else
				-- going from the beginning to the end
				-- remember, first thing we're going to do is advance to the next point
				var.current_point_index= 0
				var.point_index_delta= 1
			end
			
			result= true
		else
			print("ERROR: in patrol.lua:attempt_next_link we somehow got a vector, but have less than 2 control points")
		end
	else
		print("ERROR: unable to find next link/node")
	end
	
	return result
end


-- -------------------- COMPONENT --------------------

function attach(object)
end


function update(object)

	if (var.first_tick) then
		if (not config.start_patrol_when_placed) then
			var.enabled= false
		end
		var.first_tick= false
	end
	
	if (not var.enabled) then
		var.attached= false
		return
	end

	if (var.enabled and not var.attached) then
		local path= object.path_get()
		if (path) then
			if (attempt_attach(object)) then
				var.attached= true
				path.clear_path()
			else
				print("warning: patrol attach failed. Disabling patrol")
				var.enabled= false
			end
		end
	end
	
	if (var.enabled and var.attached) then
		local path= object.path_get()
		
		if (path.path_active()) then
			-- we're on our way, presumably
		elseif (path.path_finished() or path.path_none()) then
		
			local advance_node= false
									
			-- go to our next point
			var.current_point_index = var.current_point_index + var.point_index_delta
			if (var.current_point_index < 0) then
				advance_node= true
			elseif (var.current_link) then
				local point_count= var.current_link.graph_link_get().get_point_count()
				if (var.current_point_index >= point_count) then
					advance_node= true
				end
			end
			
			if (advance_node) then
				var.current_link= nil
				attempt_next_link(object, var.current_node)
			end
			
			if (var.current_node and var.current_link) then
				-- move to the current point index
				local target_point= var.current_link.graph_link_get().get_point(var.current_point_index)
				path.move_to_point(world_get().arena, target_point.x, target_point.y)
			end
			
			--print(var.current_point_index)
			
		elseif (path.path_failed()) then
			-- yikes, we have failed our path. There's no recovering from this.
		end
	end
end


component_register(attach, update, nil, nil)
