package game.GameMain
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.geom.Point;
	import flinjin.events.FlinjinCollisionEvent;
	import flinjin.Flinjin;
	import flinjin.graphics.Layer;
	import flinjin.input.Input;
	import flinjin.types.BoundingRect;
	import flinjin.types.FlinjinVector;
	import game.GameMain.Mobs.Mob;
	
	/**
	 * @todo DRY!
	 * @author Michael Miriti
	 */
	public class AntPlayer extends Mob
	{
		[Embed(source="../../assets/ant-anim.png")]
		private static var _antBitmap:Class;
		
		private static const ACC_Y:Number = 1;
		private static const ACC_X:Number = 0.8;
		private static const EXT_X:Number = 0.5;
		private static const MAX_SX:Number = 5.0;
		private static const MAX_SY:Number = 17.5;
		
		private var _inJump:Boolean = false;
		
		private var _leftSup:Point = new Point();
		private var _rightSup:Point = new Point();
		
		// скорость по Y
		private var _sY:Number = 0;
		// скорость по X
		private var _sX:Number = 0;
		
		private var _chv:int;
		
		public function get pX():Number
		{
			return _position.x;
		}
		
		public function set pX(value:Number):void
		{
			_position.x = value;
		}
		
		public function get pY():Number
		{
			return _position.y;
		}
		
		public function set pY(value:Number):void
		{
			_position.y = value;
		}
		
		private function _adjustSupport(sup:Point):void
		{
			if ((_parentSprite != null) && (_parentSprite.parent != null))
			{
				var _b:LevelScroll = (_parentSprite.parent as TileLevel).LevelLayer;
				
				if (_b != null)
				{
					var _nx:int = Math.floor(sup.x);
					var _ny:int = Math.floor(sup.y);
					var _px:uint = _b.getMapPixel(_nx, _ny);
					
					var i:int = 0;
					
					if (_px != 0)
					{
						while ((_px = _b.getMapPixel(_nx, _ny)) != 0)
						{
							_ny--;
							i++;
							
							if (i == 10)
								return;
						}
					}
					else
					{
						while ((_px = _b.getMapPixel(_nx, _ny)) == 0)
						{
							_ny++;
							i++;
							
							if (i == 10)
								return;
						}
					}
					
					sup.x = _nx;
					sup.y = _ny;
				}
			}
		}
		
		private function _adjustSupports():void
		{
			if (!_inJump)
			{
				_adjustSupport(_leftSup);
				_adjustSupport(_rightSup);
			}
		}
		
		override public function get x():Number
		{
			return super.x;
		}
		
		override public function set x(value:Number):void
		{
			var _cy:int = Math.floor(super.y);
			var _cx:int = Math.floor(super.x);
			var _nx:int = Math.floor(value);
			
			if (_cx == _nx)
				return;
			
			if ((_parentSprite != null) && (_parentSprite.parent != null))
			{
				var _b:LevelScroll = (_parentSprite.parent as TileLevel).LevelLayer;
				
				if (_b != null)
				{
					
					var _dirX:int = _nx > _cx ? 1 : -1;
					
					while (_cx != _nx)
					{
						_cx += _dirX;
						
						var _offset:int = 0;
						var _offUp:Boolean = false;
						var _offDw:Boolean = false;
						
						while ((_offUp = (_b.getMapPixel(_cx, _cy - _offset) != 0)) && (_offDw = (_b.getMapPixel(_cx, _cy + _offset) != 0)))
						{
							_offset++;
							
							if (_offset == 10)
							{
								
								break;
							}
						}
						
						if (!_offUp)
							_cy -= _offset;
						else if (!_offDw)
							_cy += _offset;
						else
						{
							_cx = super.x;
							break;
						}
					}
				}
			}
			else
			{
				_cx = _nx;
			}
			
			super.x = _cx;
			super.y = _cy;
			
			_leftSup.x = _cx - 10;
			_leftSup.y = _cy;
			
			_rightSup.x = _cx + 10;
			_rightSup.y = _cy;
			
			_adjustSupports();
		}
		
		override public function get y():Number
		{
			return super.y;
		}
		
		override public function set y(value:Number):void
		{
			if (value == super.y)
				return;
			
			if ((_parentSprite != null) && (_parentSprite.parent != null))
			{
				var _b:LevelScroll = (_parentSprite.parent as TileLevel).LevelLayer;
				
				if (_b != null)
				{
					var px:uint;
					var _ny:int = Math.floor(value);
					var _cy:int = Math.floor(super.y);
					
					if (_cy == _ny)
						return;
					
					var _dy:int = _cy - _ny;
					
					if (_dy < 0)
						_chv = 1;
					else
						_chv = -1;
					
					while (_cy != _ny)
					{
						if (_b.getMapPixel(x, _cy + _chv) == 0)
						{
							_cy += _chv;
						}
						else
						{
							_sY = 0;
							if (_chv == 1)
								_inJump = false;
							break;
						}
					}
					
					/*if ((_cy == _ny) && (!_inJump))
						_inJump = true;*/
					
					value = _cy;
				}
			}
			
			super.y = value;
			_leftSup.y = value;
			_rightSup.y = value;
			
			_adjustSupports();
		}
		
		override public function Move():void
		{
			if (Input.isLeft() || Input.isRight())
			{
				if (Input.isLeft())
				{
					flipHorizontal = true;
				}
				
				if (Input.isRight())
				{
					flipHorizontal = false;
				}
			}
			
			if (Input.isLeft())
				_sX -= ACC_X;
			if (Input.isRight())
				_sX += ACC_X;
			
			if (Input.isUp() && !_inJump)
			{
				_sY = -MAX_SY;
				_inJump = true;
			}
			
			if (!_inJump && (_sX != 0))
			{
				if (currentAnimation != "run")
				{
					setNamedAnimationRegion("run");
				}
			}
			else
			{
				if (currentAnimation != "stand")
				{
					setNamedAnimationRegion("stand");
				}
			}
			
			x += _sX;
			y += _sY;
			
			if (!_inJump)
			{
				if (_sX < 0)
				{
					if (_sX + EXT_X >= 0)
						_sX = 0;
					else
						_sX += EXT_X;
				}
				else
				{
					if (_sX - EXT_X <= 0)
						_sX = 0;
					else
						_sX -= EXT_X;
				}
			}
			
			if (Math.abs(_sX) > MAX_SX)
			{
				if (_sX < 0)
					_sX = -MAX_SX;
				else
					_sX = MAX_SX;
			}

			if (y + (_parentSprite as Layer).shiftY > Flinjin.sceneHeight + 30)
			{
				Fail();
				return;
			}
			
			_sY += ACC_Y;
			
			if (_sY >= ACC_Y * 3) _inJump = true;
			
			if (_sY > MAX_SY)
				_sY = MAX_SY;
			
			if (!_inJump)
			{
				angle = FlinjinVector.angle(_leftSup, _rightSup);
			}
			else
			{
				angle = _flipHorizontal ? (Math.PI / 8) : -(Math.PI / 8);
			}
			
			super.Move();
		}
		
		override protected function _Draw(surface:BitmapData, shiftVector:Point = null):void
		{
			super._Draw(surface, shiftVector);
			if (Flinjin.Debug)
			{
				surface.setPixel32(_position.x + shiftVector.x, _position.y + shiftVector.y, 0xffff0000);
				surface.setPixel32(_leftSup.x + shiftVector.x, _leftSup.y + shiftVector.y, 0xffff0000);
				surface.setPixel32(_rightSup.x + shiftVector.x, _rightSup.y + shiftVector.y, 0xffff0000);
			}
		}
		
		public function AntPlayer()
		{
			super(new _antBitmap() as Bitmap, new Point(25, 23), true, 45, 26, 1 / 2);
			
			x = Flinjin.sceneWidth / 2;
			y = Flinjin.sceneHeight - height - 30;
			
			setBoundingShape(new BoundingRect(this, 20, 10));
			
			addNamedAnimationRegion("run", 0, 3);
			addNamedAnimationRegion("stand", 4, 7);
			setNamedAnimationRegion("stand");
			
			addEventListener(FlinjinCollisionEvent.COLLISION, onCollision);
		}
		
		private function onCollision(e:FlinjinCollisionEvent):void 
		{
			Fail();
		}
		
		private function Fail():void {
			(_parentSprite.parent.parent as GameMain).startNewLevel();
		}
	
	}

}