package com.sarmatianHeroes 
{
	import flash.display.*;
	import flash.events.*;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.KeyboardEvent;
	import flash.ui.Keyboard;
	import flash.ui.Mouse;
	import fl.motion.MotionEvent;
	import flash.geom.Point;
	
	import com.coreyoneil.collision.*;
	import com.sarmatianHeroes.objects.*
	import com.antkarlov.math.*;
	import com.greensock.*; 
	import com.greensock.easing.*;
	import com.greensock.plugins.*;
	
	public class Map extends Sprite
	{
		public var currentLevel:String;
		
		private var _balls:Array;
		private static var _instance:Map = null;
		public var _layerBack:Sprite;
		public var _layerBackObjects:Sprite;
		public var _layerMain:Sprite;
		public var _layerForward:Sprite;
		public var _layerUI:Sprite;
		public var _obstacles:Array=[];
		var _obstaclesH:Array=[];
		public var _heroAll:Array=[];
		public var _squadAll:Array=[];
		var _hero:HeroBase;
		var _squad:Squad;
		var _boundMove:Ball;
		var _boundAttack:Ball;
		var _levelCollision:MovieClip;
		private var _collisionList	:CollisionGroup ;
		private var _speed			:Number;
		var _targetHero:Point = new Point();
		var _isNewTarget:Boolean = false;
		var _controledUnit:int = 1;// 1 - Hero 2 - Squad
		var _lacursore:MovieClip;
		var _UI:MovieClip;
		var _victory:MovieClip;
		var _toMapBtn:SimpleButton;
		
		private var _game:Game = Game.getInstance();

		private const FRICTION:Number = 1;
		private const EASING:Number = 0.02;

		public function Map() 
		{
            if (_instance != null)
            {
                throw "Map.as is a singleton class. Use Map.getInstance();";
            }
            _instance = this;
            if (stage)
            {
                init();
            }
            else
            {
                addEventListener(Event.ADDED_TO_STAGE, init);
            }
		}
		
        private function init(event:Event = null) : void
        {
            TweenPlugin.activate([GlowFilterPlugin]);
			
			_layerBack = new Sprite();
            _layerBackObjects = new Sprite();
            _layerMain = new Sprite();
			_layerForward = new Sprite();
			_layerUI = new Sprite();
			
            addChild(_layerBack);
            addChild(_layerBackObjects);
            addChild(_layerMain);
			addChild(_layerForward);
			addChild(_layerUI);
			
			_UI = new UIPanel();
			_layerUI.addChild(_UI);
			_UI.alpha = 0.5;
			_lacursore = new lacursore();
			_lacursore.gotoAndStop("cursor");
			_lacursore.mouseEnabled = false;
			_lacursore.x = mouseX;
			_lacursore.y = mouseY;
			_layerUI.addChild(_lacursore);
			TweenMax.to(_lacursore, 0, {glowFilter:{color:0xffffff, alpha:1, blurX:2, blurY:2, strength:2, quality:1}});
			Mouse.hide();
			
			switch(currentLevel)
			{
				case "Level1":
					_levelCollision = new Level1_mc();
					//_collisionList = new CollisionGroup(_levelCollision.Collision);
					_layerBack.addChild(_levelCollision.Back);
					_layerForward.addChild(_levelCollision.Forward);
					_layerForward.addChild(_levelCollision.Dinamic_obj);
					//_levelCollision.Collision.alpha = 0.01;
				
					addSquad("HazarSword",12,300,100);
					addSquad("HazarBow",56,400,300);
					addSquad("HazarSpear",22,500,500);
					
					addHero(new HeroSword(),80,500);
					addHero(new HeroClub(),700,100);
					addHero(new HeroBow(),700,500);
					addHero(new HeroMag(),80,100);
					break;
					
				case "Level2":
					_levelCollision = new Level1_mc();
					//_collisionList = new CollisionGroup(_levelCollision.Collision);
					_layerBack.addChild(_levelCollision.Back);
					_layerForward.addChild(_levelCollision.Forward);
					//_layerForward.addChild(_levelCollision.Dinamic_obj);
					//_levelCollision.Collision.alpha = 0.01;
				
					addSquad("HazarSword",36,120,120);
					addSquad("HazarBow",36,680,120);
					addSquad("HazarBow",36,680,480);
					addSquad("HazarSpear",36,120,480);
					
					addHero(new HeroSword(),350,300);
					addHero(new HeroClub(),450,300);
					addHero(new HeroBow(),350,400);
					addHero(new HeroMag(),450,400);
					break;
			}
			
			_hero = _heroAll[0];
			makeBounds();
			TweenMax.to(_hero, 0.5, {glowFilter:{color:0x88ff00, alpha:0.8, blurX:12, blurY:12, strength:1, quality:1}});
			
			if(_layerForward.contains(_levelCollision.Dinamic_obj))
			{
				for(var i:int = 0; i < _levelCollision.Dinamic_obj.numChildren; i++)
				{
					var ob = _levelCollision.Dinamic_obj.getChildAt(i);
					if(ob is MovieClip)
					{
						_obstacles.push(ob);
						_obstaclesH.push(ob);
					}
				}
			}
			
			for(var j:int = 0; j < _squadAll.length; j++)
			{
				doMagnet(_obstacles, _squadAll[j]);
			}
			
			//removeEventListener(Event.ADDED_TO_STAGE, init);
			stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
			stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
			stage.addEventListener(MouseEvent.MOUSE_MOVE, showAction);
			
			_game.inGame = true;
		}
		
		function addSquad(squadName:String,squadQ:int,posX:int,posY:int):void
		{
			switch(squadName)
			{
				case "HazarSword": _squad = new Squad(squadName,squadQ); break;
				case "HazarBow": _squad = new SquadBow(squadName,squadQ); break;
				case "HazarSpear": _squad = new SquadSpear(squadName,squadQ); break;
			}
			_squadAll.push(_squad);
			_squad.x = posX;
			_squad.y = posY;
			//_collisionList.addItem(_squad.collision);
			_layerMain.addChild(_squad);
		}
		
		function addHero(hero:HeroBase,posX:int,posY:int):void
		{
			_hero = hero;
			_heroAll.push(_hero);
			_obstacles.push(_hero);
			_hero.x = posX;
			_hero.y = posY;
			//_collisionList.addItem(_hero.collision);
			_layerMain.addChild(_hero);
		}
		
		function removeBounds():void
		{
			if (_boundAttack)
			{
				_layerBackObjects.removeChild(_boundAttack);
				_boundAttack = null;
			}
			if (_boundMove)
			{
				_layerBackObjects.removeChild(_boundMove);
				_boundMove = null;
			}
		}
		
		function makeBounds():void
		{
			if (_hero.walked < _hero.speed*2)
			{
				_boundAttack = new Ball(_hero.speed*2 - _hero.walked,0xff0000);
				_boundAttack.alpha = 0.1;
				_layerBackObjects.addChild(_boundAttack);
				_boundAttack.x = _hero.x;
				_boundAttack.y = _hero.y;
				//_hero.setChildIndex(_boundAttack, 0);
			}
			
			if (_hero.walked < _hero.speed)
			{
				_boundMove = new Ball(_hero.speed - _hero.walked,0x00ff00);
				_boundMove.alpha = 0.1;
				_layerBackObjects.addChild(_boundMove);
				_boundMove.x = _hero.x;
				_boundMove.y = _hero.y;
			}
		}
		
		function mouseUpHandler(e:MouseEvent):void
		{
			
			var buttonTarget:Object = e.target;
			var btClick:Boolean = false;
			
			trace(buttonTarget,buttonTarget.parent);
			if (buttonTarget is bt_Next)
			{
				btClick = true;
				nextHero();
			}
			else if (buttonTarget is bt_EndTurn)
			{
				btClick = true;
				endTurn();
			}
			else if (buttonTarget is UIPanel)
			{
				btClick = true;
			}
			
			for (var k:int = _layerMain.numChildren - 1; k >=0; k--)
			{
				var sq = _layerMain.getChildAt(k);
				if (sq is Squad)
				{
					
					if (sq.hitTestPoint(e.stageX, e.stageY))
					{
						var dist:Number = Math.sqrt((_hero.x-sq.x)*(_hero.x-sq.x)+(_hero.y-sq.y)*(_hero.y-sq.y));
						if ((dist <= sq.toCenterOffset + _hero.attackRadius) && (_hero.walked <= _hero.speed))
						{
							_hero.attack(sq);
							
							//_collisionList.removeItem(sq.collision);
							
							if(_hero is HeroBow)
							{
								
							}
							else
							{
								var _killed:int = sq.takeDamage(_hero.Damage);
							}
							
							if(_hero.walked == 0)
							{
								_hero.walked += _hero.speed;
							}
							else
							{
								_hero.walked += _hero.speed *2;
								nextHero();
							}
							removeBounds();
							makeBounds();
							btClick = true;
							
							
							{
								//_collisionList.addItem(sq.collision);
								doMagnet(_obstacles, sq);
							}
						}
					}
				}
				else if (sq is HeroBase)
				{
					
					if (sq.hitTestPoint(e.stageX, e.stageY))
					{
						btClick = true;
						if(_hero is HeroMag)
						{
							trace("heal");
							var _heart:Heart = new Heart(sq);
							stage.addChild(_heart);
							sq.heal();
							if(_hero.walked == 0)
							{
								_hero.walked += _hero.speed;
							}
							else
							{
								_hero.walked += _hero.speed *2;
								nextHero();
							}
							removeBounds();
							makeBounds();
						}
					}
				}
			}
			if(_lacursore.currentFrameLabel == "not")
			{
				btClick = true;
			}
			if (!btClick)
			{
				_targetHero.x = mouseX;
				_targetHero.y = mouseY;
				_isNewTarget = true;
				switch (_controledUnit)
				{   
					case 1 :						// Hero
							_hero.vx = (_targetHero.x - _hero.x) * EASING;
							_hero.vy = (_targetHero.y - _hero.y) * EASING;
							var angleTo = Amath.getAngle(_hero.x,_hero.y,_targetHero.x,_targetHero.y);
							var frameTo = 1 + Math.floor(angleTo/Math.PI/2*8);
							_hero.gotoAndStop(frameTo);
							//trace(_hero.walked, Math.sqrt(_hero.vx*_hero.vx+_hero.vy*_hero.vy));
							break;
					case 2 :						// Squad
							_squad.vx = (_targetHero.x - _squad.x) * EASING;
							_squad.vy = (_targetHero.y - _squad.y) * EASING;
							angleTo = Amath.getAngle(_squad.x,_squad.y,_targetHero.x,_targetHero.y);
							frameTo = 1 + Math.floor(angleTo/Math.PI/2*8);
							for(var i:uint = 0; i < _squad.quantity; i++)
							{
								_squad.vis[i].gotoAndStop(frameTo);
							}
							break;
				}
			}
		}
		
		function endTurn():void
		{
			_controledUnit = 2;
			var sq:Squad;
			var dist:Number;
			var target:HeroBase;
			
			if(_heroAll.length == 0)
			{
				mapDefeat();
			}
			else
			{
				for(var i:int = 0; i<_squadAll.length; i++)
				{
					sq = _squadAll[i] as Squad;
					sq.moveFinished = false;
					dist = Math.sqrt((_heroAll[0].x-sq.x)*(_heroAll[0].x-sq.x)+(_heroAll[0].y-sq.y)*(_heroAll[0].y-sq.y));
					target = _heroAll[0];
					
					//find nearest hero
					for(var j:int = 1; j<_heroAll.length; j++)
					{
						var temp_dist = Math.sqrt((_heroAll[j].x-sq.x)*(_heroAll[j].x-sq.x)+(_heroAll[j].y-sq.y)*(_heroAll[j].y-sq.y));
						if(temp_dist < dist)
						{
							dist = temp_dist;
							target = _heroAll[j];
						}
					}
					
					//rotate squad
					var angleTo = Amath.getAngle(sq.x,sq.y,target.x,target.y);
					var frameTo = 1 + Math.floor(angleTo/Math.PI/2*8);
					for(var ii:uint = 0; ii < sq.quantity; ii++)
					{
						sq.vis[ii].gotoAndStop(frameTo);
					}
					
					_isNewTarget = true;
					//if dist - attack
					if ((dist <= target.radius + sq.attackRadius))
					{
						sq.moveFinished = true;
						sq.attack(target);
						if(sq is SquadBow)
						{
							
						}
						else
						{
							target.takeDamage(sq.Damage*sq.quantity);
						}
					}
					else //move to hero
					{
						sq.vx = (target.x - sq.x) * EASING;
						sq.vy = (target.y - sq.y) * EASING;
						sq.target = target;
						
					}
				}
				
			}
			
			if(_heroAll.length == 0)
			{
				mapDefeat();
			}
			
			if(_squadAll.length == 0)
			{
				mapComplit();
			}
		}
		
		public function mapComplit():void
		{
			mapDefeat();
			_victory.gotoAndStop("victory");
			if(currentLevel == "Level1")
			{
				_game._opened[1] = 1;
			}
		}
		
		public function mapDefeat():void
		{
			
			Mouse.show();
			_game.inGame = false;
			_victory = new victory();
			_victory.gotoAndStop("defeat");
			addChild(_victory);
			_toMapBtn = _victory.toMap_btn;
			_toMapBtn.addEventListener(MouseEvent.CLICK, this.onPlayBtn);
			stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
			stage.removeEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
			stage.removeEventListener(MouseEvent.MOUSE_MOVE, showAction);
		}
		
		function free():void
		{
			removeChild(_layerBack);
            removeChild(_layerBackObjects);
            removeChild(_layerMain);
			removeChild(_layerForward);
			removeChild(_layerUI);
			
			_layerBack = null;
            _layerBackObjects = null;
            _layerMain = null;
			_layerForward = null;
			_layerUI = null;
			
			while(_obstacles.length > 0)
			{
				_obstacles.pop();
			}
			while(_heroAll.length > 0)
			{
				_heroAll.pop();
			}
			while(_squadAll.length > 0)
			{
				_squadAll.pop();
			}
		}
		
		function onPlayBtn(event:MouseEvent) : void
		{
			removeChild(_victory);
			_victory = null;
			_toMapBtn.removeEventListener(MouseEvent.CLICK, this.onPlayBtn);
			free();
			parent.removeChild(this);
			_game.init();
		}
		
		function beginTurn():void
		{
			
			_controledUnit = 1;
			for(var i:int = 0; i<_heroAll.length; i++)
			{
				if(_heroAll[i].heroHP <=0)
				{
					
				}
				else
				{
					trace();
					_heroAll[i].walked = 0;
				}
			}
			
			if(_heroAll.length == 0)
			{
				mapDefeat();
			}
			else
			{
				_hero = _heroAll[0];
				removeBounds();
				makeBounds();
			}
			
		}
		
		function nextHero():void
		{
			TweenMax.to(_hero, 0, {glowFilter:{color:0xff2222, alpha:1, blurX:30, blurY:30, strength:0.5, quality:1, remove:true}});
			var _index:int = _heroAll.indexOf(_hero);
			trace(_index);
			if(_index == _heroAll.length - 1)
			{
				_index = 0;
			}
			else
			{
				_index++;
			}
			var foundHero: Boolean = false;
			removeBounds();
			for(var i:int = 0; i < _heroAll.length; i++)
			{
				if(_heroAll[i].walked - _heroAll[i].speed*2 < 0)
				{
					foundHero = true;
					_hero = _heroAll[_index];
					TweenMax.to(_hero, 0.5, {glowFilter:{color:0x88ff00, alpha:1, blurX:12, blurY:12, strength:1, quality:1}});
					makeBounds();
					_isNewTarget = false;
					break;
				}
			}
			if(!foundHero)
			{
				endTurn();
			}
			
			if(_squadAll.length == 0)
			{
				mapComplit();
			}
		}
		
		function showAction(e:MouseEvent):void
		{
			_lacursore.x = mouseX;
			_lacursore.y = mouseY;
			_lacursore.gotoAndStop("walk");
			
			
			for (var k:int = _layerMain.numChildren - 1; k >=0; k--)
			{
				var sq = _layerMain.getChildAt(k);
				if (sq is Squad)
				{
					if (sq.hitTestPoint(e.stageX, e.stageY))
					{
						
						TweenMax.to(sq, 0.5, {glowFilter:{color:0xff4444, alpha:0.8, blurX:15, blurY:15, strength:1, quality:1}});
						
						var dist:Number = Math.sqrt((_hero.x-sq.x)*(_hero.x-sq.x)+(_hero.y-sq.y)*(_hero.y-sq.y));
						if ((dist <= sq.toCenterOffset + _hero.attackRadius) && (_hero.walked <= _hero.speed))
						{
							if(_hero is HeroSword)
							{
								_lacursore.gotoAndStop("sword");
							}
							else if(_hero is HeroClub)
							{
								_lacursore.gotoAndStop("club");
							}
							else if(_hero is HeroBow)
							{
								_lacursore.gotoAndStop("bow");
							}else if(_hero is HeroMag)
							{
								_lacursore.gotoAndStop("lightning");
							}
						}
						else
						{
							_lacursore.gotoAndStop("not");
						}
					}
					else
					{
						TweenMax.to(sq, 0, {glowFilter:{color:0xff2222, alpha:1, blurX:30, blurY:30, strength:0.5, quality:1, remove:true}});
					}
				}
				else if (sq is HeroBase)
				{
					if (sq.hitTestPoint(e.stageX, e.stageY))
					{
						if(_hero is HeroMag)
						{
							_lacursore.gotoAndStop("heal");
						}
						else
						{
							_lacursore.gotoAndStop("not");
						}
					}
				}
			}
			if (_UI.hitTestPoint(e.stageX, e.stageY))
			{
				_lacursore.gotoAndStop("cursor");
			}
		}
		
		function keyUpHandler(e:KeyboardEvent):void
		{
			
			switch (e.keyCode)
			{   
				case 49 : 		_controledUnit = 1;							break;	 		// 1
				case 50 : 		_controledUnit = 2;	_squad = _squadAll[0];	break;	 		// 2	
				case 51 : 		trace(e.keyCode);nextHero();	break;	 		// 3	
			}
		}
		
		function doMagnet(_magnets:Array, _target:Squad):void
		{
			var x1,y1,x2,y2,a,b,r,ax,ay,bx,by,dist,sumX,sumY;
			
			sumX = [];
			sumY = [];
			dist = 8000;
			for(var i:uint = 0; i < _target.quantity; i++)
			{
				sumX.push(0);
				sumY.push(0);
				for(var j:int = 0; j < _magnets.length; j++)
				{
					x2 = _magnets[j].x;
					y2 = _magnets[j].y;
					x1 = _target.x + _target._balls[i].x;
					y1 = _target.y + _target._balls[i].y;
					a = x2 - x1;
					b = y2 - y1;
					r = Math.sqrt(a * a + b * b);
					ax = x1 - a / r * dist / r;
					ay = y1 - b / r * dist / r;
					bx = _target.x + _target._balls[i].x0 - x1;
					by = _target.y + _target._balls[i].y0 - y1;
					sumX[i] += ax + bx - _target.x;
					sumY[i] += ay + by - _target.y;
				}
				_target._balls[i].x = sumX[i]/_magnets.length;
				_target._balls[i].y = sumY[i]/_magnets.length;
				_target.vis[i].x = _target._balls[i].x;
				_target.vis[i].y = _target._balls[i].y;
			}
		} // End of the function
		
		function doHeroMagnet(_magnets:Array, _target:Object):void
		{
			var x1,y1,x2,y2,a,b,r,ax,ay,bx,by,dist,sumX,sumY;
			
			sumX = 0;
			sumY = 0;
			dist = 500;
			for(var j:int = 0; j < _magnets.length; j++)
			{
				x2 = _magnets[j].x;
				y2 = _magnets[j].y;
				x1 = _target.x;
				y1 = _target.y;
				a = x2 - x1;
				b = y2 - y1;
				r = Math.sqrt(a * a + b * b);
				ax = x1 - a / r * dist / r;
				ay = y1 - b / r * dist / r;
				bx = _target.x0 - x1;
				by = _target.y0 - y1;
				sumX += ax + bx;
				sumY += ay + by;
			}
			_target.x = sumX/_magnets.length;
			_target.y = sumY/_magnets.length;
		} // End of the function
		
		public function process():void
		{
			
			if (_isNewTarget)
			{
				var dx:Number;
				var dy:Number;
				var distance;
				//var collisions:Array = _collisionList.checkCollisions();
				var collision:Object;
				var angle:Number;
				var overlap:int;
				
				for(var j:int = 0; j < _squadAll.length; j++)
				{
					doMagnet(_obstacles, _squadAll[j]);
				}
				
				if(_layerForward.contains(_levelCollision.Dinamic_obj))
				{
					for(var n:int = 0; n < _levelCollision.Dinamic_obj.numChildren; n++)
					{
						var ob = _levelCollision.Dinamic_obj.getChildAt(n);
						var colided:int = 0;
						if(ob is MovieClip)
						{
							for (var m:int = 0; m < _heroAll.length; m++)
							{
								var her = _heroAll[m];
								if (ob.hitTestObject(her))
								{
									colided++;
								}
							}
							for (m = 0; m < _squadAll.length; m++)
							{
								her = _squadAll[m];
								if (ob.hitTestObject(her))
								{
									colided++;
								}
							}
							if(colided > 0)
							{
								ob.alpha = 0.5;
							}
							else
							{
								ob.alpha = 1;
							}
						}
					}
				}
				/*_hero.x0 = _hero.x;
				_hero.y0 = _hero.y;
				doHeroMagnet(_obstaclesH, _hero);*/
				
				switch (_controledUnit)
				{   
					case 1 :						// Hero
							dx = _targetHero.x - _hero.x;
							dy = _targetHero.y - _hero.y;
							distance = Math.sqrt(dx * dx + dy * dy);
							if (distance >= 5 && _hero.walked < _hero.speed*2)
							{
								/*for(var i:int = 0; i < collisions.length; i++)
								{
									collision = collisions[i];
									angle = collision.angle;
									//trace(angle, collision.object1.parent ,collision.object2.parent);
									//if (collision.object1 is HeroBall || collision.object2  is HeroBall )
									{
										_isNewTarget = false;
										_hero.vx = -_hero.vx/FRICTION;
										_hero.vy = -_hero.vy/FRICTION;
									}
								}*/
								_hero.vx *= FRICTION;
								_hero.vy *= FRICTION;
								_hero.x += _hero.vx;
								_hero.y += _hero.vy;
								_hero.walked += Math.sqrt(_hero.vx*_hero.vx+_hero.vy*_hero.vy);
								removeBounds();
								makeBounds();
							}
							else
							{
								_isNewTarget = false;
							}
							if (_hero.walked >= _hero.speed*2)
							{
								nextHero();
							}
							break;
					case 2 :						// Squad
							for(var i:int = 0; i<_squadAll.length; i++)
							{
								var sq = _squadAll[i] as Squad;
								if (!sq.moveFinished)
								{
									dx = sq.target.x - sq.x;
									dy = sq.target.y - sq.y;
									distance = Math.sqrt(dx * dx + dy * dy);
									if (distance > sq.target.radius && sq.walked < sq.speed)
									{
										/*for(j = 0; j < collisions.length; j++)
										{
											collision = collisions[j];
											{
												_isNewTarget = false;
												sq.vx = -sq.vx/FRICTION;
												sq.vy = -sq.vy/FRICTION;
											}
										}*/
										sq.vx *= FRICTION;
										sq.vy *= FRICTION;
										sq.x += sq.vx;
										sq.y += sq.vy;
										sq.walked += Math.sqrt(sq.vx*sq.vx+sq.vy*sq.vy);
									}
									else
									{
										sq.moveFinished = true;
										sq.walked = 0;
										//trace(sq,"moveFinished");
									}
								}
							}
							var _allfinished:Boolean = true;
							for(i = 0; i<_squadAll.length; i++)
							{
								_allfinished = _allfinished && _squadAll[i].moveFinished;
							}
							if(_allfinished)
							{
								
								_isNewTarget = false;
								beginTurn();
							}
							break;
					}
			}
		}

        public static function getInstance() : Map
        {
            return _instance ? (_instance) : (new Map);
        }// end function


	}
	
}
