#include "empire.h"

#include "logic.h"  //needed for the special case where a unit is teleporting
extern bool ai_unit_animating;

extern void save_pathmap_info();
extern int moves_needed(int mtype, int tx, int ty);
extern int any_unit_here(int tx, int ty);
extern bitmapdat *set_datafile(int set);

vector<animtiles> animated_tiles;

bool _tile::is_building()
{
  if (set == 4)
  {  // set 4 is the building set
    return true;
  }
  return false;
}

bool _tile::is_building(int type)
{
  if (set == 4)
  {
    if (number > 3)
    {
      if ((number - 4) / 5 == type)
      {
        return true;
      }
    }
  }
  return false;
}

int _tile::building_type()
{
  if (set == 4)
  {
    if (number > 3)
    {
      return ((number - 4) / 5);
    }
    return HQ;
  }
  return -1;
}

bool _tile::is_unit_producing()
{
  if (set == 4)
  {  //only buildings could possibly build units
    if (number > 8)
    {
      return true;
    }
  }
  return false;
}

bool _tile::is_HQ()
{
  if (set == 4)
  {
    if (number < 4)
    {
      return true;
    }
  }
  return false;
}

bool _tile::owned_by(int plyr)
{
  if (set == 4)
  {  //only buildings can be owned
    if (number < 4)
    {  //if it is an HQ
      if (number == plyr)
      {
        return true;
      }
    }
    else
    {  //if it is a city, base, port, or airport
      if ((number - 4) % 5 == plyr + 1)
      {  //it has to be plyr + 1, because of the possibility of a neutral city
        return true;
      }
    }
  }
  return false;
}

bool _tile::same_type(int t)
{
  if (set == t / 100)
  {
    if (number == t % 100)
    {
      return true;
    }
  }
  return false;
}

bool _tile::same_type(int tset, int tnum)
{
  if (set == tset)
  {
    if (number == tnum)
    {
      return true;
    }
  }
  return false;
}

void _tile::reset()
{
  unit = -1;
  set = 0;
  animated = -1;
  number = 3;  //set the tile to grass
  oldset = -1;
  oldnum = -1;
  step = 999;
  temp = 999;
  animframe = 0;
}

void _tile::change_type(int new_set, int new_number)
{
  set = new_set;
  number = new_number;
}

void _tile::change_owner(int plyr)
{
  if (set == 4)
  {
    if (number > 3)
    {  //this function should not be called for HQs
       number -= 4;  //remove the HQ numbers
       number -= (number % 5);  //revert it to its neutral type
       number += plyr + 1;  //set it to the player
       number += 4;  //reapply the HQ numbers
    }
  }
}

void _tile::change_to_city()
{
  set = 4;
  number = 4;
}

void _tile::draw(int x, int y)
{
  int i, s;
  
  if ((set != oldset) || (number != oldnum))
  {  //if this tile has changed type
    animframe = 0;
    oldset = set;
    oldnum = number;
    i = 0;
    s = animated_tiles.size();
    animated = -1;
    while (i < s)
    {
      if ((animated_tiles[i].set == set) && (animated_tiles[i].num == number))
      {
        animated = i;
        i = s;
      }
      i++;
    }
  }
  
  if (animated == -1)
  {
    buffer_draw_sprite(set_datafile(set)->bmp(number), x, y);
  }
  else
  {
    animframe += animated_tiles[animated].frameinc;
    if (int(animframe) >= animated_tiles[animated].framenum)
    {
      animframe = 0;
    }
    buffer_blit_clipped(set_datafile(set)->bmp(number), x, y, int(animframe) * MAP_TILE_SIZE, 0, MAP_TILE_SIZE, MAP_TILE_SIZE);
  }
}

void _tile::draw_unit(int x, int y, _unit *other_unit_here)
{
	int i, s;
	
	if (other_unit_here != NULL)
  {
    other_unit_here->draw();
  }
	
  if (unit != -1)
  {
    i = unit / 100;
    s = unit % 100;
    if (player[i].unit[s].exists == 1)
    {
      if (!player[i].unit[s].is_moving())
      {
        player[i].unit[s].draw();
      }
    }
	  else  //if the unit doesn't exist but still is in the tile's unit thing
	  {  //it must be about to explode (as in, the map is scrolling to the unit so it can blow up)
		  if ((var.logicstate != UNIT_TELEPORTING) && (!ai_unit_animating))
			{  //UNLESS a unit is currently teleporting, in which case the unit shouldn't appear if it doesn't exist
			  player[i].unit[s].draw();
			}
  	}
  }
}

void _tile::set_unit(int plyr, int number)
{
  if ((plyr == -1) || (number == -1))
  {
    unit = -1;
  }
  else
  {
    unit = (plyr * 100) + number;
  }
}

void _tile::set_temp(short t)
{
  temp = t;
}

void _tile::set_step(short s)
{
  step = s;
}

short _tile::get_temp()
{
  return temp;
}

short _tile::get_step()
{
  return step;
}

int _tile::unit_here()
{
  return unit;
}

int _tile::owner()
{
  if (set == 4)
  {
    if (number < 4)
    {
      return number;
    }
    else
    {
      return ((number - 4) % 5) - 1;  //returns -1 for no owner
    }
  }
  return -1;
}

int _tile::get_set()
{
  return set;
}

int _tile::get_number()
{
  return number;
}




//==========================================================
//==========================================================
//==========================================================




void _map::reset()
{
  int i, j;
  j = 0;
  while (j < MAP_MAX_H)
  {
    i = 0;
    while (i < MAP_MAX_L)
    {
      tile[i][j].reset();
      i++;
    }
    j++;
  }
  name = "";
  pathmap_limit = 12;      //the AI needs the pathmap to cover everything
  l = 640 / MAP_TILE_SIZE; //but humans only need it for unit movement
  h = 480 / MAP_TILE_SIZE;
  offset_x = 0;
  offset_y = 0;
  scroll_x = 0;
  scroll_y = 0;
}

string _map::get_name()
{
  return name;
}

void _map::set_name(string new_name)
{
  name = new_name;
}

void _map::draw_tiles(bool showunits)
{  //starts at -1 to account for scroll offset
  draw_tiles(-1, -1, (640 / MAP_TILE_SIZE) + 1, (480 / MAP_TILE_SIZE) + 1, NULL, showunits);
}

void _map::draw_tiles(int gridx, int gridy, int numx, int numy, bool showunits)
{
  draw_tiles(gridx, gridy, numx, numy, NULL, showunits);
}

void _map::draw_tiles(int gridx, int gridy, int numx, int numy, _unit *other_unit_here, bool showunits)
{
  int i;
  int j = gridy;
  int tilex, tiley;
  while (j < gridy + numy)
  {
    i = gridx;
    while (i < gridx + numx)
    {
      tilex = i + scroll_x;
      tiley = j + scroll_y;
      if ((tilex > -1) && (tilex < l) && (tiley > -1) && (tiley < h))
      {
        tile[tilex][tiley].draw(i * MAP_TILE_SIZE + offset_x, j * MAP_TILE_SIZE + offset_y);
      }
      i++;
    }
    j++;
  }
	
	if (showunits)
	{
	  j = gridy;
	  while (j < gridy + numy)
    {
      i = gridx;
      while (i < gridx + numx)
      {
        tilex = i + scroll_x;
        tiley = j + scroll_y;
        if ((tilex > -1) && (tilex < l) && (tiley > -1) && (tiley < h))
        {
          tile[tilex][tiley].draw_unit(i * MAP_TILE_SIZE + offset_x, j * MAP_TILE_SIZE + offset_y, other_unit_here);
        }
        i++;
      }
      j++;
		}
  }
}

void _map::create_pathmap(int plyr, int mtype, int startx, int starty)
{
  create_pathmap(plyr, mtype, startx, starty, false);
}

void _map::create_limited_pathmap(int plyr, int mtype, int startx, int starty, int limit)
{
  pathmap_limit = limit;
  create_pathmap(plyr, mtype, startx, starty, true);
}

void _map::create_pathmap(int plyr, int mtype, int startx, int starty, bool limited)
{
  int x, y, z;
  y = 0;
  while (y < h)
  {
    x = 0;
    while (x < l)
    {
      tile[x][y].set_step(999);
      x++;
    }
    y++;
  }
	
  z = 0;
  while (z < 4)
  {
    switch(z)
    {
      case 0:
        x = startx + 1;
        y = starty;
        break;
      case 1:
        x = startx - 1;
        y = starty;
        break;
      case 2:
        x = startx;
        y = starty - 1;
        break;
      case 3:
        x = startx;
        y = starty + 1;
        break;
    }
    if ((x >= 0) && (x < l) && (y >= 0) && (y < h))
    {
      pathmap_recursive(plyr, mtype, x, y, 0, limited);
    }
    z++;
  }
  tile[startx][starty].set_step(0);
}

void _map::pathmap_recursive(int plyr, int mtype, int ox, int oy, int moves, bool limited)
{
  int m = moves_needed(mtype, ox, oy);
  int x, y, z;
	
  z = any_unit_here(ox, oy);
  if ((z != -1) && (z / 100 != plyr) && (player[z / 100].team != player[plyr].team))
  {
    m = 99;
  }
  moves += m;
  if ((moves >= tile[ox][oy].get_step()) || (m == 99))
  {
    return;
  }
  if (limited == true)
  {
    if (moves > pathmap_limit)
    {
      return;
    }
  }

  tile[ox][oy].set_step(moves);
  z = 0;
  while (z < 4)
  {
    switch(z)
    {
      case 0:
        x = ox + 1;
        y = oy;
        break;
      case 1:
        x = ox - 1;
        y = oy;
        break;
      case 2:
        x = ox;
        y = oy - 1;
        break;
      case 3:
        x = ox;
        y = oy + 1;
        break;
    }
    if ((x >= 0) && (x < l) && (y >= 0) && (y < h))
    {
      pathmap_recursive(plyr, mtype, x, y, moves, limited);
    }
    z++;
  }
}

void _map::backup_pathmap()
{
  int i, j;
  j = 0;
  while (j < h)
  {
    i = 0;
    while (i < l)
    {
      tile[i][j].set_temp(tile[i][j].get_step());
      i++;
    }
    j++;
  }
}

void _map::restore_pathmap()
{
  int i, j;
  j = 0;
  while (j < h)
  {
    i = 0;
    while (i < l)
    {
      tile[i][j].set_step(tile[i][j].get_temp());
      i++;
    }
    j++;
  }
}

bool _map::in_bounds(int x, int y)
{
	if ((x < 0) || (y < 0) || (x >= l) || (y >= h))
	{
		return false;
	}
	return true;
}
