--------------------------------------------------------------------------------
--
--   Fall Back Manager
--
--------------------------------------------------------------------------------

--
-- A Fall Back is a location that is monitored, and when it is infiltrated by an enemy, 
-- all units within the area will fall back to one of a number of predetermined locations.
-- 
-- 
-- 
-- 
-- 



--------------------------------------------------------------------------------
-- Interface Functions


--? @shortdesc Add a fallback location to the manager.
--? @extdesc
--? Add a fallback location to the manager, where if the enemy get close enough to the spot, the units within the vicinity will automatically fall back to one of the locations listed.
--? @result Void
--? @args PlayerID player, String marker, Table markerlist
function FallBack_AddLocation(pID, mkr, list)

	table.insert(FallBackManagerList, {player = pID, marker = mkr, destinationlist = list})

	-- start up the manager rule if necessary
	if not Rule_Exists(Rule_FallBackManager) then
		
		Rule_AddInterval(Rule_FallBackManager, 3)
		
	end
	
end


--? @shortdesc Remove a fallback location from the manager.
--? @extdesc
--? Remove a fallback location from the manager.
--? @result Void
--? @args PlayerID player, String marker
function FallBack_RemoveLocation(pID, mkr)

	for n = table.getn(FallBackManagerList), 1, -1 do
		
		if (pID == FallBackManagerList[n].player) and (mkr == FallBackManagerList[n].marker) then
			
			table.remove(FallBackManagerList, n)
			
		end
		
	end

	-- if that's the last fall back, then stop the manager rule
	if (table.getn(FallBackManagerList) == 0) and Rule_Exists(Rule_FallBackManager) then
		Rule_Remove(Rule_FallBackManager)
	end
	
end


--? @shortdesc Remove a destination from all fall backs for a player.
--? @extdesc
--? Remove a destination from all fall backs listed for a particular player.
--? @result Void
--? @args PlayerID player, String destination
function FallBack_RemoveDestination(pID, mkr)

	-- step through every destination in every fall back relating to the player...
	for n = table.getn(FallBackManagerList), 1, -1 do
		if (pID == FallBackManagerList[n].player) then
			for x = table.getn(FallBackManagerList[n].destinationlist), 1, -1 do
				
				-- if the destination matches the one to be removed...
				if (location == FallBackManagerList[n].destinationlist[x]) then
					
					-- remove the destination from the list of possibles
					table.remove(FallBackManagerList[n].destinationlist, x)
					
					-- if there are now no valid destinations, remove this fall back
					if (table.getn(FallBackManagerList[n].destinationlist) == 0) then
						table.remove(FallBackManagerList, n)
						-- if that's the last fall back, then stop the manager rule
						if (table.getn(FallBackManagerList) == 0) and Rule_Exists(Rule_FallBackManager) then
							Rule_Remove(Rule_FallBackManager)
						end
					end
					
				end
			end
		end
	end
end


--------------------------------------------------------------------------------
-- Initialisation function

function FallBack_Init()
	FallBackManagerList = {}
	sg_FallBackManagerRunAwaySquad = SGroup_Create("sg_FallBackManagerRunAwaySquad")
end

Scar_AddInit(FallBack_Init)


--------------------------------------------------------------------------------
-- The actual workhorse code
-- (automatically set up and removed by the other functions)

function Rule_FallBackManager()

	-- step through the list of fall backs
	for n = table.getn(FallBackManagerList), 1, -1 do
		
		local this = FallBackManagerList[n]
		local thisactivated = false
		
		-- check all players, and if they are enemy...
		for x = 1, World_GetPlayerCount() do
			
			local pID = World_GetPlayerAt(x)
			
			if (thisactivated == false) then
				
				-- if it's an enemy player, with squads near the fall back marker
				if ( Player_GetRelationship(this.player, pID) == R_ENEMY ) then
					
					if Player_AreSquadsNearMarker(pID, this.marker) then
						
						print("Fall back activated: "..Marker_GetName(this.marker))
						
						-- gather together all the units to run away...
						SGroup_Clear(sg_FallBackManagerRunAwaySquad)
						Player_GetAllSquadsNearPos(this.player, sg_FallBackManagerRunAwaySquad, Marker_GetPosition(this.marker), (Marker_GetProximityRadius(this.marker) * 2))
						
						if (SGroup_Count(sg_FallBackManagerRunAwaySquad) ~= 0) then
							
							local dest = {}
							
							-- sort the list of destinations by distance
							for i = 1, table.getn(this.destinationlist) do
								dest[i] = {destination = this.destinationlist[i], distance = Prox_MarkerSGroup(this.destinationlist[i], sg_FallBackManagerRunAwaySquad, PROX_CENTER)}
							end
							table.sort(dest, function(a,b) return (a.distance < b.distance) end)
							
							-- pick one of the closest two markers
							local rand = 1
							if (table.getn(dest) > 1) then
								rand = World_GetRand(1, 2)
							end
							
							print("Fall back activated: "..Marker_GetName(this.marker).." heading to "..dest[rand].destination)
							
							-- move the units to the new destination
							Cmd_MoveToMarker(sg_FallBackManagerRunAwaySquad, dest[rand].destination)
							
						else
							print("No-one there")
						end
						
						-- remove the old fall back
						FallBack_RemoveDestination(this.player, this.marker)
						FallBack_RemoveLocation(this.player, this.marker)
						
						thisactivated = true
						
					end
					
				end
				
			end
			
		end
		
	end
	
end



--------------------------------------------------------------------------------
-- Debug function - call this to print out a list of current fall backs being monitored

function FallBack_Print()

	-- step through the list of fall backs
	for n = 1, table.getn(FallBackManagerList) do
		
		print("Fallback Manager Entry "..n)
		
		local p = Player_GetID(FallBackManagerList[n].player)
		local m = Marker_GetName(FallBackManagerList[n].marker)
		
		print("Player = "..p.."    Marker = "..m.."   Destinations:")
		for i = 1, table.getn(FallBackManagerList[n].destinationlist) do
			print ("  "..i.." - "..FallBackManagerList[n].destinationlist[i])
		end
		
	end
	
end
