package Game{
	import flash.display.*;
	import flash.events.*;
	import fl.transitions.Tween;
	import fl.transitions.easing.*;
	import fl.transitions.TweenEvent;
	
	/**
	 Базовый класс привидения
	 **/
	public class Ghost extends MovieClip{
		public var initSpeed:Number = 1.5;
		var speed:Number = 1.5;
		var TargetPoint:Object = new Object();
		
		public var CanPassHome:Boolean = false;		
		public var pm:PacMan;
		
		var Tweens:Array = new Array();
		
		/** callback функции **/
		public var onEnemyEaten:Function;
		public var onPacManEaten:Function;
		public var onPacManDeath:Function;
		
		public var Mode:Number = -1; // 0 = Home
		// 1 = Chase - Погоня
		// 2 = Scatter - Рассредоточение
		// 3 = FRIGHTENED - Испуг
		// 4 = RUNAWAY - Убегает в дом
		// 5 = EXIT - Выходим из домика
		
		public var NextMode:Number = 1;
		
		public var Direction:Number = 0;
		// 1 - left
		// 2 - right
		// 3 - up
		// 4 - down
		
		public function Ghost(){
			TargetPoint.x = 0;
			TargetPoint.y = 0;
		}
		
		function startChaseTween(e:TweenEvent):void{
			var ti:Number = Tweens.indexOf(e.target);
			Tweens[ti] = Tweens[Tweens.length - 1];
			Tweens.pop();
			
			CanPassHome = false;
			Direction = 1;
			SwitchMode(NextMode);
		}
		
		function getOutTween(e:TweenEvent):void {
			var ti:Number = Tweens.indexOf(e.target);
			Tweens[ti] = Tweens[Tweens.length - 1];
			Tweens.pop();
			
			var newY:Number = ((parent as Level).Map.GhostHouse.y - 3) * 8-4;
			var t:Tween = new Tween(this, 'y', None.easeNone, y, newY, 1.5, true);
			t.addEventListener(TweenEvent.MOTION_FINISH, startChaseTween);
			Tweens[Tweens.length] = t;
		}
		
		/**
		  Смена режима действий привидения
		**/
		public function SwitchMode(mod:Number):void {
			if (Mode == mod) {
				return;
			}
			
			switch (mod){
				case 0: // HOME
					speed = initSpeed;
					gotoAndStop(0);
					Mode = mod;
				break;
				
				case 1: // CHASE
					if((Mode != 0) && (Mode != 4)){						
						gotoAndStop(0);
						Mode = mod;
						makeTarget();
						speed = initSpeed;
					}
				break;
				
				case 2: // SCATTER
					gotoAndStop(0);
					Mode = mod;
					makeTarget();
					speed = initSpeed;
					Direction = Backword();
				break;
				
				case 3: // FRIGHTENED
					if((Mode != 0) && (Mode != 5) && (Mode != 4)){
						Direction = Backword();
						gotoAndStop('Spook');
						Mode = mod;
						speed = 0.7;
					}
				break;
				
				case 4: // RUNAWAY
					gotoAndStop('Eyes');
					Mode = mod;
					makeTarget();
					speed = 4;
					CanPassHome = true;
				break;
				
				case 5: // EXIT
					gotoAndStop(0);
					Mode = mod;
					new Tween(this, 'x', None.easeNone, x, (parent as Level).Map.GhostHouse.x * 8, 1/2, true);
					var t:Tween = new Tween(this, 'y', None.easeNone, y, (parent as Level).Map.GhostHouse.y * 8, 1/2, true);
					t.addEventListener(TweenEvent.MOTION_FINISH, getOutTween);
					Tweens[Tweens.length] = t;
				break;
			}
		}

		function Distance(x1:Number, y1:Number, x2:Number, y2:Number):Number{
			return Math.sqrt(Math.pow(x2-x1, 2) + Math.pow(y2-y1, 2));
		}
		
		function Backword():Number{
			switch(Direction){
				case 1: return 2;
				case 2: return 1;
				case 3: return 4;
				case 4: return 3;
				default: return 0;
			}
		}
		
		/**
		  Движение к цели
		 **/ 
		function MoveToTarget(home:Boolean=false):void{
			var Xcell:Number = Math.floor(x / 8);
			var Ycell:Number = Math.floor(y / 8);
			
			if(Direction == 0){
				return;
			}
			
			if(isLeavingCell())
			{
				if(!isNextMoveable(home) || isDecisionCell(home))
				{
					Direction = ChooseBestTurnToTarget(home);
				}					
			}
		}
		
		function isNextMoveable(home:Boolean=false):Boolean{
			var X:Number = Math.floor(x / 8);
			var Y:Number = Math.floor(y / 8);
			
			switch(Direction){
				case 1:
					return (parent as Level).Map.Moveable(X-1, Y, home);
				break;
				
				case 2:
					return (parent as Level).Map.Moveable(X+1, Y, home);
				break;
				
				case 3:
					return (parent as Level).Map.Moveable(X, Y-1, home);
				break;
				
				case 4:
					return (parent as Level).Map.Moveable(X, Y+1, home);
				break;
				
				default:
					return false;
			}
		}
		
		function isMoveableByDirection(Dir:Number):Boolean{
			
			switch(Dir){
				case 1: return (parent as Level).Map.Moveable(Math.floor(x / 8) - 1, Math.floor(y / 8));
				case 2: return (parent as Level).Map.Moveable(Math.floor(x / 8) + 1, Math.floor(y / 8));
				case 3: return (parent as Level).Map.Moveable(Math.floor(x / 8), Math.floor(y / 8) - 1);
				case 4: return (parent as Level).Map.Moveable(Math.floor(x / 8), Math.floor(y / 8) + 1);
				default: return false;
			}
		}
		
		function ChooseBestTurnToTarget(home:Boolean=false):Number{
			var newDirection:Number = 0;
			var test_newDirValue:Number = 0;
			var newDirValue:Number = 16540215410;
			var Xcell:Number = Math.floor(x / 8);
			var Ycell:Number = Math.floor(y / 8);
			
			if((parent as Level).Map.Moveable(Xcell-1, Ycell, home))
			{
				if(Backword() != 1){
					newDirection = 1;
					newDirValue = Distance(Xcell-1, Ycell, TargetPoint.x, TargetPoint.y);
				}
			}
			
			if((parent as Level).Map.Moveable(Xcell+1, Ycell, home))
			{
				test_newDirValue = Distance(Xcell+1, Ycell, TargetPoint.x, TargetPoint.y);
				if((test_newDirValue < newDirValue) && (Backword() != 2)){
					newDirValue = test_newDirValue;
					newDirection = 2;
				}
			}
			
			if((parent as Level).Map.Moveable(Xcell, Ycell-1, home))
			{
				test_newDirValue = Distance(Xcell, Ycell-1, TargetPoint.x, TargetPoint.y);
				if((test_newDirValue < newDirValue) && (Backword() != 3)){
					newDirValue = test_newDirValue;
					newDirection = 3;
				}
			}
			
			if((parent as Level).Map.Moveable(Xcell, Ycell+1, home))
			{
				test_newDirValue = Distance(Xcell, Ycell+1, TargetPoint.x, TargetPoint.y);
				if((test_newDirValue < newDirValue) && (Backword() != 4)){
					newDirValue = test_newDirValue;
					newDirection = 4;
				}
			}
			
			return newDirection;
		}
		
		function ChooseRandomTurn():Number{
			var Xcell:Number = Math.floor(x / 8);
			var Ycell:Number = Math.floor(y / 8);
			var Dir:Number;
			
			Dir = 1 + Math.floor(Math.random() * 4);
			while(!isMoveableByDirection(Dir) || (Dir == Backword())){
				Dir = 1 + Math.floor(Math.random() * 4);
			}
			
			return Dir;
		}
		
		// Перекресток ли текущая точка
		function isDecisionCell(home:Boolean=false):Boolean{
			var X:Number = Math.floor(x / 8);
			var Y:Number = Math.floor(y / 8);
			var TursnNum:Number = 0;
			
			if((parent as Level).Map.Moveable(X+1, Y, home)){
				TursnNum++;
			}
			
			if((parent as Level).Map.Moveable(X, Y+1, home)){
				TursnNum++;
			}
			
			if((parent as Level).Map.Moveable(X-1, Y, home)){
				TursnNum++;
			}
			
			if((parent as Level).Map.Moveable(X, Y-1, home)){
				TursnNum++;
			}
			
			return (TursnNum > 2);
		}
		
		function isLeavingCell():Boolean{
			switch(Direction){
				case 0: return false;				
				case 1:
					return Math.floor((x-4-speed) / 8) != Math.floor((x-4) / 8);
				break;
				
				case 2:
					return Math.floor((x+4+speed) / 8) != Math.floor((x+4) / 8);
				break;
				
				case 3:
					return Math.floor((y-4-speed) / 8) != Math.floor((y-4) / 8);
				break;
				
				case 4:
					return Math.floor((y+4+speed) / 8) != Math.floor((y+4) / 8);				
				break;
				
				default:
					return false;
			}
		}
		
		// Движение в домике
		function HomeMove():void{
			if(Direction == 3){
				if(!(parent as Level).Map.Moveable(Math.floor(x / 8), Math.floor(((y - 4) - speed) / 8))){
					Direction = 4;
				}
			}else{
				if(!(parent as Level).Map.Moveable(Math.floor(x / 8), Math.floor(((y + 4) - speed) / 8))){
					Direction = 3;
				}
			}
		}
		
		function RandMove():void{
			if(Direction == 0){
				return;
			}
			
			if(isLeavingCell())
			{
				if(!isNextMoveable() || isDecisionCell())
				{
					Direction = ChooseRandomTurn();
				}					
			}
		}
		
		public function makeTarget():void{
			switch (Mode){
				case 0: // HOME
				break;
				
				case 1: // CHASE
					TargetPoint.x = Math.floor(pm.x / 8);
					TargetPoint.y = Math.floor(pm.y / 8);
				break;
				
				case 2: // SCATTER
					TargetPoint.x = 0;
					TargetPoint.y = 0;
				break;
				
				case 3: // FRIGHTENED
				break;
				
				case 4: // RUNAWAY
					TargetPoint.x = (parent as Level).Map.GhostHouse.x;
					TargetPoint.y = (parent as Level).Map.GhostHouse.y;
				break;
			}			
		}
		
		public function Move():void{			
		
			var Blood:MovieClip;
			
			makeTarget();
			
			switch(Mode){
				case 0:
					HomeMove();
					break;
				case 1:
				case 2:
				case 4:
					MoveToTarget(CanPassHome);
					break;
				case 3:
					RandMove();
					break;
				case 5: return;
			}
			
			var X:Number = Math.floor(x / 8);
			var Y:Number = Math.floor(y / 8);
			var i:Number = 0;
			var a_speed:Number = speed;
			
			/*if(Mode == 4){
				trace(X, Y);
			}*/

			switch(Direction){
				case 1:				
					x = x - a_speed;
					if(x < 0){
						x = (parent as Level).MapWidth*8;
					}
				break;
				
				case 2:
					if(speed > 1){

					}
					
					x = x + a_speed;
					if(x > (parent as Level).MapWidth*8){
						x = 0;
					}
				break;
				
				case 3:
					y = y - a_speed;
				break;
				
				case 4:
					y = y + a_speed;
				break;
			}
			
			if((Mode == 4) && ((parent as Level).Map.GhostHouse.x == Math.floor((x) / 8)) && ((parent as Level).Map.GhostHouse.y == Math.floor((y) / 8))){
				SwitchMode(5);
			}
			
			if(Math.floor(x / 8) == Math.floor(pm.x / 8))
			{
				if(Math.floor(y / 8) == Math.floor(pm.y / 8))
				{
					if((Mode == 1) || (Mode == 2)){
						onPacManDeath();
					}
					
					if(Mode == 3){
						onEnemyEaten();
						switch (1 + Math.floor(Math.random() * 3)){
							
							case 1:
								Blood = new tile_18();
							break;
							
							case 2:
								Blood = new tile_19();
							break;
							
							case 3:
								Blood = new tile_20();
							break;
						}
						
						(parent as Level).replaceTile(Math.floor(x / 8), Math.floor(y / 8), Blood);
						SwitchMode(4);
					}
				}
			}
		}
	}
}