#include "scripts/common.txt"
#include "scripts/BP_common.txt"

//(2) Health -32768..32767 (WayPoint ID - start at 1)
//self.ModelVariation (neighbor 1 ID)
//(5) Texture -128..127 (neighbor 2 ID)
//(7) Params 1 -128..127 (neighbor 3 ID)
//(6) Params 2 -128..127 (neighbor 4 ID)
	
array<BP_WayPoint@> waypoints;
bool waypointsInitialized;

//------------------------------------------------------------------------------------------------------------------------
void SetupWayPoints()
{
	waypointsInitialized = true;
	for (uint i = 0; i < waypoints.length(); i++)
	{
		array<int> neighborIDs = { waypoints[i].self.ModelVariation(), waypoints[i].self.SpawnParams(5), waypoints[i].self.SpawnParams(7), waypoints[i].self.SpawnParams(6) };
		for (uint j = 0; j < waypoints.length(); j++)
		{
			if (i == j)
				continue;
			
			for (uint n = 0; n < neighborIDs.length(); n++)
			{
				if (neighborIDs[n] == waypoints[j].self.SpawnParams(2))
				{
					if (waypoints[i].neighbors.findByRef(waypoints[j]) < 0)
					{
						waypoints[i].neighbors.insertLast(waypoints[j]);
					}
				}
			}
		}

		//check for spawners if can see
		for (uint j = 0; j < spawnersMP.length(); j++)
		{
			kVec3 pos = spawnersMP[j].self.Origin();
			float distance = waypoints[i].self.Origin().Distance(pos);
			if (distance < 1024.0f && waypoints[i].self.CanSee(spawnersMP[j].self))
			{
				waypoints[i].spawners.insertLast(spawnersMP[j]);
			}
		}
		
		// if (waypoints[i].self.Health() == 1)
		// {
			// Sys.Print("Waypoint 1 has " + int(waypoints[i].spawners.length()) + " items");
			// for (uint j = 0; j < waypoints[i].spawners.length(); j++)
			// {
				// Sys.Print("" + waypoints[i].spawners[j].GetItemType());
			// }
		// }
		
	}
}
//------------------------------------------------------------------------------------------------------------------------
void DestroyWayPoints()
{
	waypoints.resize(0);
	waypointsInitialized = false;
}
//------------------------------------------------------------------------------------------------------------------------
// Returns an array of kVec3 points to the destination
//------------------------------------------------------------------------------------------------------------------------
void NavigateTo(const kVec3 &in origin, const kVec3 &in destination, array<BP_WayPoint@> &out pathResult, array<kVec3> &out pathVecResult)
{
	pathResult.resize(0);
	pathVecResult.resize(0);
	
	if (!waypointsInitialized)
		return;
	
	BP_WayPoint@ currentNode = FindClosestWaypoint(origin);
	BP_WayPoint@ endNode = FindClosestWaypoint(destination);
	if (@currentNode == null || @endNode == null)
		return;
	
	if (@currentNode == @endNode)
	{
		pathResult.insertAt(0, null);
		pathVecResult.insertAt(0, destination);
		return;
	}
	
	array<BP_WayPoint@> openList; //should be sorted by distance
	array<BP_WayPoint@> closedList;
	openList.insertLast(currentNode);
	@currentNode.parent = null;
	currentNode.distance = 0.0f;
	while (openList.length() > 0)
	{
		@currentNode = @openList[0]; //lowest cost node
		openList.removeAt(0);
		//float dist = currentNode.distance;
		closedList.insertLast(currentNode);
		if (@currentNode == @endNode)
			break;
		for (uint i = 0; i < currentNode.neighbors.length(); i++)
		{
			BP_WayPoint@ neighbor = currentNode.neighbors[i];
			if (closedList.findByRef(neighbor) >= 0 || openList.findByRef(neighbor) >= 0)
				continue;
			@neighbor.parent = @currentNode;
			//neighbor.distance = dist + neighbor.Origin().Distance(currentNode.Origin());
			//float distanceToTarget = neighbor.Origin().Distance(endNode.Origin());
			openList.insertLast(neighbor);
		}
	}
	if (@currentNode == @endNode)
	{
		pathResult.insertAt(0, null);
		pathVecResult.insertAt(0, destination);
		while (@currentNode.parent != null)
		{
			pathResult.insertAt(0, currentNode);
			pathVecResult.insertAt(0, currentNode.self.Origin());
			@currentNode = @currentNode.parent;
		}
		//currentPath.insertAt(0, origin);
	}
	
	//openList.sort(function(a,b) { return a.distance < b.distance; });
}
//------------------------------------------------------------------------------------------------------------------------
BP_WayPoint@ FindClosestWaypoint(const kVec3 &in target)
{
	BP_WayPoint@ closestWaypoint = null;
	float closestDist = 999999.0f;
	for (uint i = 0; i < waypoints.length(); i++)
	{
		BP_WayPoint@ waypoint = @waypoints[i];
		float dist = waypoint.self.Origin().Distance(target);
		if (dist < closestDist)
		{
			@closestWaypoint = @waypoint;
			closestDist = dist;
		}
	}
	return closestWaypoint;
}
//========================================================================================================================
class BP_WayPoint : ScriptObject
{
    kActor @self;
	BP_WayPoint@ parent;
	float distance;
	array<BP_WayPoint@> neighbors;
	array<BP_SpawnerMP@> spawners;
	//------------------------------------------------------------------------------------------------------------------------
    BP_WayPoint(kActor @actor)
	{
        @self = actor;
		waypoints.insertLast(@this);
    }
	//------------------------------------------------------------------------------------------------------------------------
    void OnTick() {}
	//------------------------------------------------------------------------------------------------------------------------
    void OnSpawn() {}
	//------------------------------------------------------------------------------------------------------------------------
}
