﻿using UnityEngine;
using System.Collections;

public class Unit {
	public enum Type {
		RED,
		GREEN,
		BLUE,
		LEADER
	}
	
	private GameObject unitObject;
	private Player player;
	private Type type;
	private GridPos position;

	private float maxHealth;
	private int speed;
	private int vision;
	private int reach;

	private float health;
	private int remainingMove; // how many tiles the unit can move this turn
	

	public Unit(Player p, Type t, GridPos pos) {
		player = p;
		type = t;
		position = pos;
		
		Player.Side side = player.getSide();

		switch (type) {
			case Type.RED:
				unitObject = (GameObject)MonoBehaviour.Instantiate(GameAssets.get().getUnitRed(side));
				maxHealth = Constants.RED_MAX_HEALTH;
				speed = Constants.RED_SPEED;
				vision = Constants.RED_VISION;
				reach = Constants.RED_REACH;
				break;
			case Type.GREEN:
				unitObject = (GameObject)MonoBehaviour.Instantiate(GameAssets.get().getUnitGreen(side));
				maxHealth = Constants.GREEN_MAX_HEALTH;
				speed = Constants.GREEN_SPEED;
				vision = Constants.GREEN_VISION;
				reach = Constants.GREEN_REACH;
				break;
			case Type.BLUE:
				unitObject = (GameObject)MonoBehaviour.Instantiate(GameAssets.get().getUnitBlue(side));
				maxHealth = Constants.BLUE_MAX_HEALTH;
				speed = Constants.BLUE_SPEED;
				vision = Constants.BLUE_VISION;
				reach = Constants.BLUE_REACH;
				break;
			case Type.LEADER:
				unitObject = (GameObject)MonoBehaviour.Instantiate(GameAssets.get().getUnitLeader(side));
				maxHealth = Constants.LEADER_MAX_HEALTH;
				speed = Constants.LEADER_SPEED;
				vision = Constants.LEADER_VISION;
				reach = Constants.LEADER_REACH;
				break;
		}

		setPosition(position);
		health = maxHealth;
		
		setSelected(false);
		
		nextTurn();
	}

	public Type getType() {
		return type;
	}
	
	public bool isLeader() {
		return type == Type.LEADER;
	}
	
	public GridPos getPosition() {
		return position;
	}

	public void setPosition(GridPos pos) {
		position = pos;

		if (unitObject != null) {
			unitObject.transform.position = position.getWorldPosition();
		}
	}

	public Vector3 getWorldPosition() {
		return unitObject.transform.position;
	}

	public void setWorldPosition(Vector3 pos) {
		unitObject.transform.position = pos;
	}

	public Player getPlayer() {
		return player;
	}

	public void nextTurn() {
		remainingMove = speed;
	}

	public void walkedThisTurn(int amount) {
		remainingMove -= amount;
	}

	public bool isEnemy(Unit other) {
		return player != other.player;
	}

	public void setSelected(bool selected) {
		GameObject go = unitObject.transform.Find("Selection").gameObject;
		go.SetActive(selected);
	}
	
	public void setVisible(bool visible) {
		unitObject.SetActive(visible);
	}
	
	public void setIdentified(bool identified) {
		unitObject.transform.Find("Element").gameObject.SetActive(identified);
	}

	public void die() {
		GameObject.Destroy(unitObject);
		unitObject = null;
	}

	public bool isAlive() {
		return unitObject != null;
	}

	public int getSpeed() {
		return speed;
	}

	public int getVision() {
		return vision;
	}

	public int getReach() {
		return reach;
	}

	public float getMaxHealth() {
		return maxHealth;
	}

	public float getHealth() {
		return health;
	}

	public int getRemainingMove() {
		return remainingMove;
	}

	public void endMoveThisTurn() {
		remainingMove = 0;
	}

	public bool canMoveThisTurn() {
		return remainingMove > 0;
	}
	
	public bool canWalkOnTile(Tile tile) {
		Tile.Type t = tile.getType();
		if (t == Tile.Type.BLOCKED) return false;
		if (t == Tile.Type.NORMAL) return true;
		if (type == Type.LEADER) return false;
		
		if (type == Type.RED && t == Tile.Type.BLUE) return false;
		if (type == Type.GREEN && t == Tile.Type.RED) return false;
		if (type == Type.BLUE && t == Tile.Type.GREEN) return false;
		
		return true;
	}
	
	public bool willKillInBattle(Unit other) {
		return type == Type.RED && other.type == Type.GREEN
			|| type == Type.GREEN && other.type == Type.BLUE
			|| type == Type.BLUE && other.type == Type.RED
			|| type != Type.LEADER && other.type == Type.LEADER;
	}
	
	public bool willBattleDraw(Unit other) {
		return type == other.type;
	}
	
	public bool willDieInBattle(Unit other) {
		return !willKillInBattle(other) && !willBattleDraw(other);
	}
}
