package game.towers 
{
	import com.cheezeworld.utils.Input;
	import com.cheezeworld.utils.KeyCode;
	import com.experion.utils.GetClass;
	import events.ModelEvent;
	import factories.IProjectileFactory;
	import factories.PathGridObjectFactory;
	import factories.ProjectileFactory;
	import game.build.BuildManager;
	import game.enemies.Enemy;
	import game.models.Model;
	import game.projectiles.Projectile;
	import game.projectiles.SpecialProjectile;
	import game.UpgradeManager;
	import grid.path.PathFollowUnit;
	import grid.path.PathGridObject;
	import utils.ModelUtilities;
	/**
	 * ...
	 * @author 
	 */
	public class Tower extends Model {
		static public const TOWER_FIRE:String = "towerFire";
		static public const TOWER_UPGRADE:String = "towerUpgrade";
		
		protected var _location:PathGridObject;
		protected var _target:Enemy;
		protected var _range:Number;
		protected var _fireDelay:Number;
		protected var _damage:int;
		protected var _projectileFactory:IProjectileFactory;
		
		protected var _upgradeCost:int;
		protected var _level:int;
		
		private var _currentDelay:int;
		private var _readyToFire:Boolean;
		private var _enemies:Vector.;
		
		public function Tower(location:PathGridObject/*, upgrade:UpgradeManager*/) {
			super();
			_location = location;
			position.x = _location.position.x;
			position.y = _location.position.y;
			_readyToFire = false;
			_range = 100;
			_fireDelay = 4;
			_damage = 10;
			_upgradeCost = BuildManager.COST_TOWER_BASIC * 2;
			_level = 1;
			
			_projectileFactory = new ProjectileFactory();
			
			/*if (upgrade.register(this)) {
				
			}*/
		}
		
		public function updateTarget(enemies:Vector.):void {
			/*if (_enemies == null)*/ _enemies = enemies;
			
			checkFireDelay();
			
			if (_target != null && _target.position) {
				if ( !checkRangeWith(_target) ) {
					getNewTarget(enemies);
				} else {
					if (_readyToFire) {
						shootProjectile();
						_readyToFire = false;
					}
				}
			} else {
				getNewTarget(enemies);
			}
		}
		
		/**
		 * Checks if the Tower is ready to fire.
		 */
		private function checkFireDelay():void {
			if (!_readyToFire) {
				_currentDelay++;
				if (_currentDelay > _fireDelay) {
					_readyToFire = true;
					_currentDelay = 0;
				}
			}
		}
		
		/** Shoots the projectile. */
		private function shootProjectile():void {
			if (_projectileFactory.usesSpecialProjectiles) {
				var projectile:SpecialProjectile = _projectileFactory.createProjectile(this, _target) as SpecialProjectile;
				projectile.setUpAdditionalValues(_enemies);
				dispatchEvent( new ModelEvent(TOWER_FIRE, projectile ) );
			} else {
				dispatchEvent( new ModelEvent(TOWER_FIRE, _projectileFactory.createProjectile(this, _target) ) );
			}
		}
		
		/**
		 * Gets a new target to shoot at. It'll take the closest Enemy.
		 * @param	enemies - The list with Enemies
		 */
		protected function getNewTarget(enemies:Vector.):void {
			var closestEnemy:Enemy;
			var closestDistance:Number;
			
			//Go through every existing enemy
			for (var i:int = 0; i < enemies.length; i++) {
				var currEnemy:Enemy = enemies[i];
				//Check if the current enemy we're checking for is in range
				if ( checkRangeWith(currEnemy) ) {
					var enemyDistance:Number = ModelUtilities.getRadiusDistance(this, currEnemy);
					//If the distance of this enemy is closer than the other enemies we've checked, this will become the closest.
					if ( closestEnemy == null || enemyDistance < closestDistance ) {
						closestEnemy = currEnemy;
						closestDistance = enemyDistance;
					}
				}
			}
			
			_target = closestEnemy;
		}
		
		public function checkRangeWith(enemy:Enemy):Boolean {
			return ModelUtilities.getRadiusCollision(this, enemy, _range);
		}
		
		public function upgrade():void {
			//upgrade ze stats here
			_upgradeCost *= 1.3;
			_level++;
			
			upgradeStats();
		}
		
		public function get level():int {
			return _level;
		}
		
		protected function upgradeStats():void {
			_range += 15;
			//_damage += 2;
			_damage += 3 + (level/2);
			
			if (level % 10 == 0) {
				if (_fireDelay > 2) {
					_fireDelay--;
				}
			}
		}
		
		public function get upgradeCost():int {
			return _upgradeCost;
		}
		
		public function get range():Number {
			return _range;
		}
		
		public function get location():PathGridObject {
			return _location;
		}
		
		public function get target():Enemy {
			return _target;
		}
		
		public function get damage():int {
			return _damage;
		}
		public function get fireDelay():Number {
			return _fireDelay;
		}
		
	}

}