using UnityEngine;
using System.Collections;

public class Grid {
	private const int TILE_NORMAL = 0;
	private const int TILE_BLOCKED = 1;
	private const int TILE_RED = 2;
	private const int TILE_GREEN = 3;
	private const int TILE_BLUE = 4;
	
	private static int[,] MAP = {
		{TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_RED,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL},
		{TILE_BLOCKED,TILE_NORMAL,TILE_BLOCKED,TILE_BLOCKED,TILE_BLOCKED,TILE_BLOCKED,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL},
		{TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_GREEN,TILE_NORMAL,TILE_BLUE,TILE_BLOCKED,TILE_NORMAL,TILE_NORMAL},
		{TILE_BLUE,TILE_BLOCKED,TILE_BLOCKED,TILE_BLOCKED,TILE_BLOCKED,TILE_BLOCKED,TILE_NORMAL,TILE_NORMAL,TILE_BLOCKED,TILE_BLOCKED,TILE_GREEN},
		{TILE_NORMAL,TILE_NORMAL,TILE_BLOCKED,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_BLOCKED,TILE_NORMAL,TILE_NORMAL},
		{TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_BLOCKED,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL},
		{TILE_NORMAL,TILE_NORMAL,TILE_BLOCKED,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_BLOCKED,TILE_NORMAL,TILE_NORMAL},
		{TILE_GREEN,TILE_BLOCKED,TILE_BLOCKED,TILE_NORMAL,TILE_NORMAL,TILE_BLOCKED,TILE_RED,TILE_BLOCKED,TILE_BLOCKED,TILE_BLOCKED,TILE_BLUE},
		{TILE_NORMAL,TILE_NORMAL,TILE_BLOCKED,TILE_BLUE,TILE_NORMAL,TILE_GREEN,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL},
		{TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_BLOCKED,TILE_BLOCKED,TILE_BLOCKED,TILE_BLOCKED,TILE_NORMAL,TILE_BLOCKED},
		{TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_RED,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL,TILE_NORMAL}
	};
	
	private int gridWidth;
	private int gridHeight;
	private Tile[,] tiles;

	// Use this for initialization
	public Grid() {
		gridWidth = MAP.GetLength(0);
		gridHeight = MAP.GetLength(1);
		tiles = new Tile[gridWidth, gridHeight];
		
		for (int x = 0; x < gridWidth; ++x) {
			for (int y = 0; y < gridHeight; ++y) {
				Tile.Type type = Tile.Type.NORMAL;
				switch (MAP[y, x]) {
					case TILE_NORMAL:
						type = Tile.Type.NORMAL;
						break;
					case TILE_BLOCKED:
						type = Tile.Type.BLOCKED;
						break;
					case TILE_RED:
						type = Tile.Type.RED;
						break;
					case TILE_GREEN:
						type = Tile.Type.GREEN;
						break;
					case TILE_BLUE:
						type = Tile.Type.BLUE;
						break;
				}
				tiles[x, y] = new Tile(type, new GridPos(x, y));
			}
		}
	}

	public int getGridWidth() {
		return gridWidth;
	}

	public int getGridHeight() {
		return gridHeight;
	}

	public Tile getTile(GridPos pos) {
		return tiles[pos.getX(), pos.getY()];
	}

	public Tile getTile(Unit u) {
		GridPos pos = u.getPosition();
		if (pos.isValid()) return tiles[pos.getX(), pos.getY()];
		return null;
	}

	public void addUnit(Unit u) {
		GridPos pos = u.getPosition();
		if (pos.isValid()) tiles[pos.getX(), pos.getY()].setUnit(u);
	}

	public void removeUnit(Unit u) {
		GridPos pos = u.getPosition();
		if (pos.isValid()) {
			Tile t = tiles[pos.getX(), pos.getY()];
			if (t.getUnit() == u) t.setUnit(null);
		}
	}
	
	// NOTE we search for battles before moving the unit, use unitPos, not unit.getPosition() to calculate distance
	public ArrayList findBattles(Unit unit, GridPos unitPos) {
		ArrayList battles = new ArrayList();
		
		for (int x = 0; x < gridWidth; ++x) {
			for (int y = 0; y < gridHeight; ++y) {
				if (tiles[x, y].hasUnit() && tiles[x, y].getUnit().isEnemy(unit)) {
					float dist = unitPos.distance(tiles[x, y].getPosition()) - 1.0e-5f;
					if (dist <= tiles[x, y].getUnit().getReach() || dist <= unit.getReach()) {
						battles.Add(new Battle(unit, tiles[x, y].getUnit()));
					}
				}
			}
		}
		
		return battles;
	}
}
