#include "empire.h"
#include "logic.h"

int moves_needed(int mtype, int tx, int ty, int plyr)
{                     //Infantry,    Tires,       Tread,       Air,         Mech,        Sea,         Lander
	int movegrid[70] = {1,           1,           1,           1,           1,           UNREACHABLE, UNREACHABLE,  //Buildings        0
	                    1,           1,           1,           1,           1,           UNREACHABLE, UNREACHABLE,  //Plains           1
	                    1,           1,           1,           1,           1,           UNREACHABLE, 1,            //Shoal            2
	                    1,           3,           2,           1,           1,           UNREACHABLE, UNREACHABLE,  //Forest           3
	                    2,           UNREACHABLE, UNREACHABLE, 1,           2,           UNREACHABLE, UNREACHABLE,  //Mountain         4
	                    2,           UNREACHABLE, UNREACHABLE, 1,           1,           UNREACHABLE, UNREACHABLE,  //River            5
	                    1,           1,           1,           1,           1,           UNREACHABLE, UNREACHABLE,  //Road             6
	                    UNREACHABLE, UNREACHABLE, UNREACHABLE, 1,           UNREACHABLE, 1,           1,            //Sea              7
	                    1,           1,           1,           1,           1,           UNREACHABLE, UNREACHABLE,  //Special 1        8
	                    UNREACHABLE, UNREACHABLE, UNREACHABLE, UNREACHABLE, UNREACHABLE, UNREACHABLE, UNREACHABLE}; //Special 2        9
	int ltype;
	
	if (!worldmap.tile_in_bounds(tx, ty))
		return UNREACHABLE;
	
	ltype = get_ltype(tx, ty);
	if (ltype == 0)
	{
		if ((mtype == M_SEA) || (mtype == M_LANDER))  //sea units can go to ports
		{
			if (worldmap.get_tile(tx, ty)->is_building(PORT))
			{
				return 1;
			}
		}
	}
	else if ((ltype == 3) && (player[plyr].number == 2))
	{  //pine army movement is uninhibited by forests
		return 1;
	}
	return movegrid[mtype + (ltype * 7)];
}

int get_ltype(int tx, int ty)
{
	int s;
	int z;
	s = worldmap.get_tile(tx, ty)->get_set();
	z = worldmap.get_tile(tx, ty)->get_number();
	if (s == 4)  //buildings
	{
		return 0;
	}
	else if (s == 0)  //land
	{
		if ((z == 2) || (z == 20))  //forest or burnt forest
		{
			return 3;
		}
		else if (z == 4)  //mountain
		{
			return 4;
		}
		else if (z == 3)  //plains
		{
			return 1;
		}
		else  //road
		{
			return 6;
		}
	}
	else if (s == 3)  //shoal
	{
		if (z < 25)
		{
			return 2;
		}
		else  //tiles 25 through 28 are sea tiles, but are transitions from shoals
		{
			return 7;
		}
	}
	else if (s == 1)  //river
	{
		return 5;
	}
	else if (s == 6)  //special
	{
		if (z == 0)  //teleport tile
		{
			return 8;
		}
		else if (z == 1)  //barrier tile
		{
			return 9;
		}
	}
	return 7;  //sea
}

int do_moveselect(int plyr, int u, int tx, int ty)
{
	static bool first = true;
	static int lastx;
	static int lasty;
	bool findpath = false;
	int dir;

	if (!worldmap.tile_in_bounds(tx, ty))  //if tx and ty aren't in bounds, reset the static ints
	{
		first = true;
		return 0;
	}
	
	_unit *theunit = &player[plyr].unit[u];
	if (first)
	{
		movelist.resize(0);
		lastx = theunit->tilex;
		lasty = theunit->tiley;
		findpath = true;
		first = false;
	}
	else if ((tx != lastx) || (ty != lasty))
	{
		findpath = false;
		if (tile_distance(lastx, lasty, tx, ty) == 1)
		{  //if the mouse hasn't skipped a tile or anything like that
			if (list_distance(theunit) + moves_needed(unitstats[theunit->type].movetype, tx, ty, plyr) <= theunit->move)
			{  //if the movement is still within the unit's range
				if (worldmap.get_tile(tx, ty)->get_step() <= theunit->move)
				{
					if      (ty == lasty + 1) dir = DOWN;
					else if (ty == lasty - 1) dir = UP;
					else if (tx == lastx + 1) dir = RIGHT;
					else if (tx == lastx - 1) dir = LEFT;
					
					movelist.push_back(dir);
					if (move_overlap(theunit))
					{
						findpath = true;
					}
				}
			}
			else
			{  //can't reach this tile with the moves taken by the current path
				findpath = true;
			}
		}
		else
		{  //if the path is not connected
			findpath = true;
		}
		if ((tx == theunit->tilex) && (ty == theunit->tiley))
		{  //if the mouse is over the unit's original position, reset the movelist
			findpath = false;  //also, don't bother getting a best path
			movelist.resize(0);
		}
		if (findpath && (worldmap.get_tile(tx, ty)->get_step() <= theunit->move))
		{  //find the best path from (tx, ty) to the unit's location
			vector<_aipath> t = best_aipath(plyr, unitstats[theunit->type].movetype, theunit->tilex, theunit->tiley, tx, ty);
			
			movelist.resize(0);
			for (unsigned int i = 0; i < t.size(); i++)
				movelist.push_back(t[i].dir);
		}
		if (worldmap.get_tile(tx, ty)->get_step() <= theunit->move)
		{
			lastx = tx;
			lasty = ty;
		}
	}
	
	show_movable_tiles(theunit);
	draw_path(theunit);
	theunit->draw(false);
	return u;
}

void show_movable_tiles(_unit *u, float alpha)
{
	int i, j;
	int ymin = u->tiley - u->move;
	int ymax = u->tiley + u->move;
	int xmin = u->tilex - u->move;
	int xmax = u->tilex + u->move;
	int x, y, z;
	j = ymin;
	if (j < 0) j = 0;
	while ((j <= ymax) && (j < worldmap.get_height()))
	{
		i = xmin;
		while ((i <= xmax) && (i < worldmap.get_length()))
		{
			if (worldmap.get_tile(i, j) == 0)
			{
				i++;
				continue;
			}
			
			if (worldmap.get_tile(i, j)->get_step() <= u->move)
			{
				//this unit can be moved through, but only highlight the tile if the unit can actually stop on it
				z = any_unit_here(i, j);
				if (z == -1 ||
						((z / 100 == u->owner) &&
							((can_merge(u, &player[z / 100].unit[z % 100])) || (player[z / 100].unit[z % 100].can_load_unit(u) == 1)) ) )
				{
					x = (i - worldmap.camera.get_scroll_x()) * MAP_TILE_SIZE + worldmap.camera.get_offset_x();
					y = (j - worldmap.camera.get_scroll_y()) * MAP_TILE_SIZE + worldmap.camera.get_offset_y();
					buffer_rectfill(x, y, x + MAP_TILE_SIZE, y + MAP_TILE_SIZE, WHITE, alpha);
				}
			}
			i++;
		}
		j++;
	}
}

void draw_path(_unit *u)
{
	int tx = u->tilex;
	int ty = u->tiley;
	int x = (u->tilex - worldmap.camera.get_scroll_x()) * MAP_TILE_SIZE + worldmap.camera.get_offset_x();
	int y = (u->tiley - worldmap.camera.get_scroll_y()) * MAP_TILE_SIZE + worldmap.camera.get_offset_y();
	buffer_rectfill(x, y, x + MAP_TILE_SIZE, y + MAP_TILE_SIZE, YELLOW, 0.66);
	
	for (unsigned int i = 0; i < movelist.size(); i++)
	{
		switch(movelist[i])
		{
			case LEFT:
				tx -= 1;
				break;
			case RIGHT:
				tx += 1;
				break;
			case UP:
				ty -= 1;
				break;
			case DOWN:
				ty += 1;
				break;
		}
		x = (tx - worldmap.camera.get_scroll_x()) * MAP_TILE_SIZE + worldmap.camera.get_offset_x();
		y = (ty - worldmap.camera.get_scroll_y()) * MAP_TILE_SIZE + worldmap.camera.get_offset_y();
		buffer_rectfill(x, y, x + MAP_TILE_SIZE, y + MAP_TILE_SIZE, YELLOW, 0.47);
	}
}

int list_distance(_unit *u)
{
	unsigned int i = 0;
	int moves = 0;
	int x = u->tilex;
	int y = u->tiley;
	while (i < movelist.size())
	{
		switch(movelist[i])
		{
			case UP:
				y -= 1;
				break;
			case DOWN:
				y += 1;
				break;
			case LEFT:
				x -= 1;
				break;
			case RIGHT:
				x += 1;
				break;
		}
		moves += moves_needed(unitstats[u->type].movetype, x, y, u->owner);
		i++;
	}
	return moves;
}

bool move_overlap(_unit *u)
{
	unsigned int i = 0, j = 0;
	int tx, ty;
	int x = u->tilex;
	int y = u->tiley;
	vector<_loc> a;
	_loc l;
	tx = x;
	ty = y;
	while (i < movelist.size())
	{
		switch(movelist[i])
		{
			case UP:
				y -= 1;
				break;
			case DOWN:
				y += 1;
				break;
			case LEFT:
				x -= 1;
				break;
			case RIGHT:
				x += 1;
				break;
		}
		j = 0;
		while (j < a.size())
		{
			if ((x == a[j].x) && (y == a[j].y))
			{
				return true;
			}
			j++;
		}
		l.x = x;
		l.y = y;
		a.push_back(l);
		i++;
	}
	return false;
}
