#include "empire.h"

void check_APC_options(_unit *u)
{
  _loc d;
	_loc dest;
  int real_move = u->move;
  int x, y;
  if (real_move > u->gas)
  {
    real_move = u->gas;
  }
  if (u->load[0].loaded == 1)
  {  //if it's carrying a unit
    d = closest_move_to_enemy_building(u->color, u->number, u->movetype, real_move, u->tilex, u->tiley, 1, &dest);
    if (d.x != -1)
    {  //if it can get to an enemy building
      d = closest_move_to_destination(u->color, u->number, u->movetype, real_move, u->tilex, u->tiley, d, 1);
      if (d.x != -1)
      {
        action[0].type = action_move;
        action[0].loc = d;
				action[0].destination = dest;
        if (tile_distance(d.x, d.y, x, y) == 1)
        {  //if the final move brings it one move away from the building
          action[1].type = action_unload1;
          action[1].loc.x = x;
          action[1].loc.y = y;
       }
      }
    }
    else
    {  //it can't get to a building, so go for an enemy unit instead
      d = closest_move_to_enemy_unit(u->color, u->number, u->movetype, real_move, u->tilex, u->tiley, &dest);
      if (d.x != -1)
      {
        d = closest_move_to_destination(u->color, u->number, u->movetype, real_move, u->tilex, u->tiley, d, 2);
        if (d.x != -1)
        {
          action[0].type = action_move;
          action[0].loc = d;
					action[0].destination = dest;
        }
      }
    }
    if (action[1].type == action_standby)
    {  //try to unload whenever it has something loaded
      if (action[0].type == action_move)
      {
        d = unloadable_point(action[0].loc.x, action[0].loc.y, 1);
      }
      else
      {
        d = unloadable_point(u->tilex, u->tiley, 1);
      }
      if (d.x != -1)
      {
        if (action[0].type == action_standby)
        {
          action[0].type = action_unload1;
          action[0].loc = d;
        }
        else
        {
          action[1].type = action_unload1;
          action[1].loc = d;
        }
      }
    }
  }
  else
  {  //if not loaded, resupply any units that need it
    d = closest_move_to_needy_friendly(u->color, u->number, u->movetype, real_move, u->tilex, u->tiley, &dest);
    if (d.x != -1)
    {
      if ((d.x != u->tilex) || (d.y != u->tiley))
      {
        action[0].type = action_move;
        action[0].loc = d;
				action[0].destination = dest;
        if (next_to_needy_friendly(u->color, d.x, d.y) == 1)
        {
          action[1].type = action_supply;
          action[1].loc = d;
        }
      }
      else
      {
        action[0].type = action_supply;
        action[0].loc = d;
      }
    }
  }
  if (action[1].type == action_standby)
  {  //if doing nothing, resupply whatever friendly units are around
    d.x = u->tilex;
    d.y = u->tiley;
    action[1].type = action_supply;
    action[1].loc = d;
  }
}

void check_tcopter_options(_unit *u)
{
  _loc d, t;
  unsigned int i;
  int x, y, real_move;
  bool repeat = true;
  bool repeated = false;
  d.x = -1;
  d.y = -1;
  real_move = u->move;
  if (real_move > u->gas)
  {
    real_move = u->gas;
  }
  if (u->load[0].loaded != 0)
  {  //if the copter has a passenger
    d = nearest_enemy_building(u->color, u->tilex, u->tiley);
  }
  else
  {
    i = 0;
    x = 999;
    while (i < need_transport.size())
    {      
      if ((need_transport[i]->type == INFANTRY) || (need_transport[i]->type == MECH))
      {
        t = best_copter_adjacent_space(need_transport[i]->tilex, need_transport[i]->tiley);
        if (t.x != -1)
        {
          if (worldmap.tile[t.x][t.y].get_step() < x)
          {
            x = worldmap.tile[t.x][t.y].get_step();
            d = t;
          }
        }
      }
      i++;
    }
  }
  while (repeat == true)
  {
    x = d.x;
    y = d.y;
    if (any_unit_here(x, y) == -1)
    {  //if the target space is empty
      repeat = false;
      if (u->load[0].loaded == 1)
      {
        d = closest_move_to_destination(u->color, u->number, u->movetype, real_move, u->tilex, u->tiley, d, 1);
      }
      else
      {
        d = closest_move_to_destination(u->color, u->number, u->movetype, real_move, u->tilex, u->tiley, d, 0);
      }
      if (d.x != -1)
      {
        action[0].type = action_move;
        action[0].loc = d;
				action[0].destination.x = x;
				action[0].destination.y = y;
        if ((tile_distance(x, y, d.x, d.y) == 1) && (u->load[0].loaded == 1))
        {  //if the move takes it to one away from the carried unit's target
          action[1].type = action_unload1;
          action[1].loc.x = x;
          action[1].loc.y = y;
        }
      }
      else
      {
        if ((tile_distance(x, y, u->tilex, u->tiley) == 1) && (u->load[0].loaded == 1))
        {  //if it is already one away from the carried unit's target
          action[0].type = action_unload1;
          action[0].loc.x = x;
          action[0].loc.y = y;
        }
      }
    }
    else
    {  //if there is a unit on that space
      if (repeated == true)
      {
        repeat = false;
      }
      repeated = true;
      d = a_free_space(u, x, y);
    }
  }
}

void check_lander_options(_unit *u)
{
  bool to_enemy = false;
  int capper = 0, dist;
  unsigned int i;
  _loc d, targetbeach;
  targetbeach.x = -1;
  targetbeach.y = -1;
  dist = 999;
  if ((u->load[0].loaded == 1) || (u->load[1].loaded == 1))
  {  //if it has a passenger
    if ((u->load[0].loaded == 1) && (u->load[1].loaded == 1))
    {  //if it is full
      to_enemy = true;
    }
    if (to_enemy == true)
    {
      capper = 0;
      if (u->load[0].loaded == 1)
      {
        if ((u->load[0].type == INFANTRY) || (u->load[0].type == MECH))
        {
          capper = 1;
        }
      }
      if (u->load[1].loaded == 1)
      {
        if ((u->load[1].type == INFANTRY) || (u->load[1].type == MECH))
        {
          capper = 1;
        }
      }
      d = closest_enemy_beach(u->color, u->tilex, u->tiley, capper);
      if (d.x != -1)
      {
        targetbeach = d;
      }
    }
    else  //if it doesn't have both slots filled
    {  //check to see if it's on enemy territory
      i = M_TREAD;
      capper = 0;
      if (u->load[0].loaded == 1)
      {
        if ((u->load[0].type == INFANTRY) || (u->load[0].type == MECH))
        {
          capper = 1;
          i = M_MECH;
        }
      }
      if (u->load[1].loaded == 1)
      {
        if ((u->load[1].type == INFANTRY) || (u->load[1].type == MECH))
        {
          capper = 1;
          i = M_MECH;
        }
      }
      d = reachable_enemy_building(u->color, i, u->tilex, u->tiley, capper);
      if (d.x != -1)
      {  //if it is (so it maybe could only unload one unit last turn), unload now
        d.x = u->tilex;
        d.y = u->tiley;
        check_unload(u, d);
      }
    }
  }
  else
  {  //no passengers, find the closest unit in need of transportation
    i = 0;
    while (i < need_transport.size())
    {
      if (need_transport[i]->basetype == LAND)
      {
        d = closest_beach_for_lander(u->color, need_transport[i]->tilex, need_transport[i]->tiley, u);
        if (d.x != -1)
        {
          if (worldmap.tile[d.x][d.y].get_step() < dist)
          {
            targetbeach = d;
            dist = worldmap.tile[d.x][d.y].get_step();
          }
        }
      }
      i++;
    }
  }
  if (targetbeach.x != -1)
  {
    d = closest_move_to_destination(u->color, u->number, M_LANDER, u->move, u->tilex, u->tiley, targetbeach, 0);
    if (d.x != -1)
    {
      action[0].type = action_move;
      action[0].loc = d;
			action[0].destination = targetbeach;
      if ((d.x == targetbeach.x) && (d.y == targetbeach.y))
      {  //if it reaches its destination at the end of the move
        check_unload(u, targetbeach);
      }
    }
  }
}

void check_unload(_unit *u, _loc targetbeach)
{
  int actnum = 1;
  _loc d;
	d.x = -1; d.y = -1;
	if (u->load[0].loaded == 1)
  {
    if ((u->load[0].type == INFANTRY) || (u->load[0].type == MECH))
    {
      d = unloadable_point(targetbeach.x, targetbeach.y, 1);
    }
    else
    {
      d = unloadable_point(targetbeach.x, targetbeach.y, 0);
    }
    if (d.x != -1)
    {
      action[actnum].type = action_unload1;
      action[actnum].loc = d;
      actnum++;
    }
  }
  if (u->load[1].loaded == 1)
  {
    if (actnum == 1)
    {  //if there wasn't a unit in load[0]
      d.x = -1;
      d.y = -1;
    }
    if ((u->load[1].type == INFANTRY) || (u->load[1].type == MECH))
    {
      d = unloadable_point(targetbeach.x, targetbeach.y, 1, d);
    }
    else
    {
      d = unloadable_point(targetbeach.x, targetbeach.y, 0, d);
    }
    if (d.x != -1)
    {
      action[actnum].type = action_unload2;
      action[actnum].loc = d;
    }
  }
}

bool reachable_within_one_tile(_loc d)
{
	if (worldmap.tile[d.x][d.y].get_step() < 99) return true;
	if (d.y - 1 > -1)
	{
		if (worldmap.tile[d.x][d.y - 1].get_step() < 99) return true;
	}
	if (d.y + 1 < worldmap.h)
	{
		if (worldmap.tile[d.x][d.y + 1].get_step() < 99) return true;
	}
	if (d.x - 1 > -1)
	{
		if (worldmap.tile[d.x - 1][d.y].get_step() < 99) return true;
	}
	if (d.x + 1 < worldmap.l)
	{
		if (worldmap.tile[d.x + 1][d.y].get_step() < 99) return true;
	}
	return false;
}

void check_convenient_APC(_unit *u)
{
  int real_move, i, deststep, apc_move;
  _loc d;
	_unit *apc;
  real_move = u->move;
  if (real_move > u->gas)
  {
    real_move = u->gas;
  }
	
  //if (((action[0].type == action_move) && (action[1].type == action_standby)) || (action[0].type == action_standby))
	//if it isn't moving, or moving somewhere but not doing anything when at the destination
	deststep = worldmap.tile[action[0].destination.x][action[0].destination.y].get_step();
	if ((action[0].type == action_standby) || 
		 ((action[0].type == action_move) && (deststep > real_move)))
  {  //if it isn't moving, or its destination is far away
    d = empty_APC_nearby(u, real_move);
    if (d.x != -1)
    {  //if there is an empty APC reachable this turn
      if (action[0].type == action_move)
			{  //make sure the APC can actually unload the unit at its destination
				i = worldmap.tile[d.x][d.y].unit_here();
				apc = &(player[u->color].unit[i % 100]);
				apc_move = apc->move;
				if (apc_move > apc->gas)
				{
					apc_move = apc->gas;
				}
				
				worldmap.backup_pathmap();
				worldmap.create_limited_pathmap(u->color, apc->movetype, d.x, d.y, (deststep / real_move) * apc_move);
				// (on "(deststep / real_move) * apc_move": the APC is useless if it takes more turns for it to reach
				// the destination than for the unit (real_move will never be 0 here, it's filtered for that in ai.cpp)
				if (!reachable_within_one_tile(action[0].destination))
				{  // if the APC can't get within one tile of the destination
					worldmap.restore_pathmap();
					return;
				}
				worldmap.restore_pathmap();
			}
				
			action[0].type = action_move;
      action[0].loc = d;
			action[0].destination = d;
      action[1].type = action_load;
      action[1].loc = d;
    }
  }
}

void check_available_copter(_unit *u)
{
  _loc d, dest;
  int z, real_move;
  real_move = u->move;
  if (real_move > u->gas)
  {
    real_move = u->gas;
  }
  d = closest_move_to_empty_copter(u->color, u->number, u->movetype, real_move, u->tilex, u->tiley, &dest);
  if (d.x != -1)
  {  //if there is an empty T-Copter available
    action[0].type = action_move;
    action[0].loc = d;
		action[0].destination = dest;
    z = unit_here_thorough(u->color, d.x, d.y, u->number);
    if (z != -1)
    {  //if there is a unit at the final move point, it must be the copter
      action[1].type = action_load;
      action[1].loc = d;
    }
  }
}

void check_available_lander(_unit *u)
{
  int real_move = u->move;
  int z;
  _loc d, dest;
  if (real_move > u->gas)
  {
    real_move = u->gas;
  }
  if ((u->type != APC) || (action[0].type == action_unload1))
  {  //if it isn't an APC, or is an APC with a unit loaded into it
    d = closest_move_to_available_lander(u->color, u->number, u->movetype, real_move, u->tilex, u->tiley, &dest);
    if (d.x != -1)
    {  //if there is an empty lander available
      action[0].type = action_move;
      action[0].loc = d;
			action[0].destination = dest;
      z = unit_here_thorough(u->color, d.x, d.y, u->number);
      if (z != -1)
      {  //if there is a unit at the final move point, it must be the lander
        action[1].type = action_load;
        action[1].loc = d;
      }
    }
  }
}

void check_teleports(_unit *u)
{
	bool f;
	int maxmoves = 0;
	unsigned int i = 0;
	_loc l, c;
	vector<_loc> sep;
	vector<_loc> good;
	
	if (teleports.size() < 2)
	{  //if there are no teleports on the map (or just one, which would be useless)
		return;
	}
	l = closest_teleport(u);
	if (l.x == -1)
	{
		return;
	}
	
	if ((action[0].type == action_move) && (action[0].loc.x != -1))
	{
		maxmoves = worldmap.tile[action[0].destination.x][action[0].destination.y].get_step() - 1;
		if (maxmoves <= u->move)
		{  //if the destination is within reach, no need to teleport
			return;
		}
		c = closest_teleport_to_destination(u->color, u->movetype, action[0].destination.x, action[0].destination.y, maxmoves);
		if (c.x != -1)
		{  //if there is a teleport that the unit can take to the target
			if ((c.x == l.x) && (c.y == l.y))
			{  //if the closest teleport to the unit and the closest teleport to the destination are the same
				return;  //then there's no benefit in moving to the teleport
			}
			action[0].loc = closest_move(u->color, u->number, u->movetype, u->tilex, u->tiley, l.x, l.y, -1);
			if ((action[0].loc.x == l.x) && (action[0].loc.y == l.y))
			{  //if it can reach the teleport this turn
				action[1].type = action_teleport;
				action[1].loc.x = c.x;
				action[1].loc.y = c.y;
				return;
			}
		}
	}
	else if (action[0].type == action_standby)
	{
		f = true;
		i = 0;
		
		while (i < teleports.size())
		{  //create a vector of empty teleport locations which the unit can't reach on its own
			if ((worldmap.tile[teleports[i].x][teleports[i].y].get_step() >= 999) && (any_unit_here(teleports[i].x, teleports[i].y) == -1))
			{  //if this teleport tile isn't reachable from the unit's current position
				sep.push_back(teleports[i]);
			}
			i++;
		}
		i = 0;
		while (i < sep.size())
		{
			c = reachable_enemy_building(u->color, u->movetype, sep[i].x, sep[i].y, 
			                             ((u->type == MECH) || (u->type == INFANTRY)), 0);
			if (c.x != -1)
			{  //if there is a reachable enemy building (or neutral and the unit is infantry or mech) from this teleport
				if (f)
				{  //change the unit actions to movement when the first good teleport is found
					action[0].type = action_move;
					action[0].loc = closest_move(u->color, u->number, u->movetype, u->tilex, u->tiley, l.x, l.y, -1);
					if ((action[0].loc.x != l.x) || (action[0].loc.y != l.y))
					{  //if the unit can't get to the teleport this turn
						return;  //don't bother finding any other good teleports
					}
					f = false;
				}
				good.push_back(sep[i]);  //add it to the list of good teleport locations
			}  //NOTE: THIS MEANS THE AI CURRENTLY DOESN'T TELEPORT TO GET AT ENEMY UNITS
			i++;
		}
		//if it gets to this point, either the unit can reach the teleport this turn or there's no good teleports
		if (good.size() == 0)
		{
			return;
		}
		//if it gets to this point, it's ready to teleport after moving
		i = rand()%good.size();  //just pick a random good teleport
		action[1].type = action_teleport;
		action[1].loc = good[i];
	}
}

_loc closest_teleport(_unit *u)
{
	unsigned int i = 0;
	int tempstep;
	int beststep = 999;
	_loc best;
	_loc temp;
	best.x = -1;
	best.y = -1;
	while (i < teleports.size())
	{
		temp.x = teleports[i].x;
		temp.y = teleports[i].y;
		tempstep = worldmap.tile[temp.x][temp.y].get_step();
		if (tempstep < beststep)
		{
			beststep = tempstep;
			best.x = temp.x;
			best.y = temp.y;
		}
		i++;
	}
	return best;
}

int can_unload_from_here(int x, int y, int mountains)
{
  _loc d = unloadable_point(x, y, mountains);
  if (d.x != -1)
  {
    return 1;
  }
  return 0;
}
