package  
{
	import adobe.utils.CustomActions;
	import flash.display.Bitmap;
	import flash.display.Sprite;
	import flash.events.TimerEvent;
	import flash.geom.Point;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;
	import flash.utils.Timer;
	
	/**
	 * ...
	 * @author beisik
	 */
	public class Game extends Sprite 
	{
		public static const Width: Number = 640;
		public static const Height: Number = 480;
		
		[Embed(source = 'textures/i1.png')] private const UI: Class;
		[Embed(source = 'textures/i2.png')] private const ARROW: Class;
		
		[Embed(source = 'textures/bo.png')] private const EDGE: Class;
		
		[Embed(source = 'textures/f1.png')] private const FLOWER1: Class;
		[Embed(source = 'textures/f2.png')] private const FLOWER2: Class;
		[Embed(source = 'textures/f3.png')] private const FLOWER3: Class;
		[Embed(source = 'textures/f4.png')] private const FLOWER4: Class;
		[Embed(source = 'textures/g1.png')] private const GRASS1: Class;
		[Embed(source = 'textures/g2.png')] private const GRASS2: Class;
		[Embed(source = 'textures/g3.png')] private const GRASS3: Class;
		[Embed(source = 'textures/g4.png')] private const GRASS4: Class;
		
		public var snake: Snake;
		
		public var tail: Vector.<Tail>;
		
		public var tailSprite: Sprite;
		public var shadowSprite: Sprite;
		public var applesSprite: Sprite;
		public var rocksSprite: Sprite;
		public var sawsSprite: Sprite;
		
		private var playerTF: TextField;
		
		public var level: Level;
		public var levels: Vector.<Level>;
		
		public var applesRoom: uint;
		public var applesLeft: int;
		public var currentRoom: uint;
		
		public var ui: Bitmap;
		public var arrow: Sprite;
		
		private var edges: Vector.<Sprite>;
		
		public var scores: Number;
		
		public var pebblesSprite: Sprite;
		public var pebbles: Vector.<Pebble>;
		
		public var bloodSprite: Sprite;
		public var blood: Array;
		
		public var timeLeft: Number;
		
		public var goto: Point;
		
		private var lifeTF: Vector.<TextField>;
		
		private var timer: Timer;
		
		public function Game() 
		{			
			graphics.beginFill(0x79A22B);
			graphics.drawRect(-Width, -Height, Width * 3, Height * 3);
			graphics.endFill();
			
			pebblesSprite = new Sprite();
			addChild(pebblesSprite);
			
			shadowSprite = new Sprite();
			addChild(shadowSprite);
			
			bloodSprite = new Sprite();
			addChild(bloodSprite);
			blood = new Array();
			
			rocksSprite = new Sprite();
			addChild(rocksSprite);
			
			applesSprite = new Sprite();
			addChild(applesSprite);
			
			tailSprite = new Sprite();
			addChild(tailSprite);
			
			snake = new Snake();
			addChild(snake);
			shadowSprite.addChild(snake.shadow);
			
			tail = new Vector.<Tail>();
			tail[0] = new Tail(snake);
			tailSprite.addChild(tail[0]);
			shadowSprite.addChild(tail[0].shadow);
			
			sawsSprite = new Sprite();
			addChild(sawsSprite);
			
			/* Уровни */
			levels = new Vector.<Level>(5);
			
			// центральный
			levels[0] = new Level(this, 0, 0, 0);			
			levels[0].addRock(120, 120, 1);
			levels[0].addRock(500, 350, 3);
			levels[0].addSaw(550, 90, true, false);
			levels[0].addSaw(90, 400, false, false);
			
			// верхний
			levels[1] = new Level(this, 0, -Height, 1);
			levels[1].addSaw(210, 70, false, true);
			levels[1].addSaw(390, 140, false, false);
			levels[1].addSaw(300, 210, false, true);
			levels[1].addSaw(300, 280, false, false);
			
			// нижний
			levels[2] = new Level(this, 0, Height, 2);
			levels[2].addRock(320, 120, 3);
			levels[2].addRock(320, 370, 3);
			levels[2].addRock(220, 240, 3);
			levels[2].addRock(420, 240, 3);
			levels[2].addSaw(300, 420, false, false);
			levels[2].addSaw(300, 300, false, true);
			levels[2].addSaw(300, 180, false, false);
			
			// левый
			levels[3] = new Level(this, -Width, 0, 3);
			levels[3].addRock(300, 250, 0);
			levels[3].addSaw(90, 180, false, true);
			levels[3].addSaw(510, 280, false, false);
			levels[3].addRock(100, 100, 1);
			levels[3].addRock(100, 380, 1);
			levels[3].addRock(450, 150, 2);
			levels[3].addRock(450, 350, 2);
			
			// правый
			levels[4] = new Level(this, Width, 0, 4);
			for (i = 0; i < 4; i++)
			{
				levels[4].addRock(100 + i * 150, 100 + (i % 2) * 12, 0);
				levels[4].addRock(100 + i * 150, 360 - (i % 2) * 12, 0);
				levels[4].addRock(160 + i * 130, 230, 2);
			}			
			
			// переходы между уровнями
			level = levels[0];
			levels[0].addTop(levels[1]);
			levels[0].addBottom(levels[2]);
			levels[0].addLeft(levels[3]);
			levels[0].addRight(levels[4]);
			
			// границы
			edges = new Vector.<Sprite>(4);
			for (i = 0; i < 4; i++)
			{
				var edgeImg: Bitmap = new EDGE();
				edgeImg.x = -edgeImg.width / 2;
				edgeImg.y = -edgeImg.height / 2;
				edges[i] = new Sprite();
				addChild(edges[i]);
				edges[i].addChild(edgeImg);
			}
			showEdges();
			
			// галька
			pebbles = new Vector.<Pebble>();
			for (var j: uint = 0; j < 5; j++)
			{
				for (var i: uint = 0; i < 2; i++)
				{
					var px: Number = Math.random() * Width + levels[j].x;
					var py: Number = Math.random() * Height + levels[j].y;
					for (var c: uint = 0; c < 5; c++)
					{
						pebbles[j * 10 + i * 5 + c] = new Pebble(px + Math.random() * 15, py + Math.random() * 15, Math.random() < 0.7);
						pebblesSprite.addChild(pebbles[j * 10 + i * 5 + c]);
					}
				}
			}
			var flowers: Vector.<Bitmap> = new Vector.<Bitmap>();
			for (j = 0; j < 5; j++)
			{
				for (i = 0; i < 3; i++)
				{
					c = Math.round(Math.random() * 7);
					switch (c)
					{
						case 0: flowers[j * 3 + i] = new FLOWER1(); break;
						case 1: flowers[j * 3 + i] = new FLOWER2(); break;
						case 2: flowers[j * 3 + i] = new FLOWER3(); break;
						case 3: flowers[j * 3 + i] = new FLOWER4(); break;
						case 4: flowers[j * 3 + i] = new GRASS1(); break;
						case 5: flowers[j * 3 + i] = new GRASS2(); break;
						case 6: flowers[j * 3 + i] = new GRASS3(); break;
						case 7: flowers[j * 3 + i] = new GRASS4(); break;
					}
					flowers[j * 3 + i].x = 30 + Math.random() * (Width - 60) + levels[j].x;
					flowers[j * 3 + i].y = 30 + Math.random() * (Height - 60) + levels[j].y;
					pebblesSprite.addChild(flowers[j * 3 + i]);
					if (c < 4)
					{
						var shadow: Shadow = new Shadow(4);
						shadow.move(flowers[j * 3 + i].x + flowers[j * 3 + i].width / 2, flowers[j * 3 + i].y + flowers[j * 3 + i].height / 2);
						pebblesSprite.addChildAt(shadow, 0);
					}
				}
			}
			
			applesRoom = 0;
			applesLeft = 5;
			
			currentRoom = 0;
			
			ui = new UI();
			ui.x = 0;
			ui.y = Height - ui.height;
			addChild(ui);
			
			arrow = new Sprite();
			arrow.x = 55;
			arrow.y = Height - 50;
			addChild(arrow);
			var arrowImg: Bitmap = new ARROW();
			arrowImg.x = -50;
			arrowImg.y = -75;
			arrowImg.smoothing = true;
			arrow.addChild(arrowImg);
			
			scores = 0;
			
			playerTF = new TextField();
			playerTF.autoSize = TextFieldAutoSize.LEFT;
			playerTF.embedFonts = true;
			playerTF.defaultTextFormat = new TextFormat("life-font", 42);
			playerTF.textColor = 0xFFFFFF;
			playerTF.selectable = false;
			playerTF.mouseEnabled = false;
			playerTF.alpha = 0.8;
			addChild(playerTF);
			
			lifeTF = new Vector.<TextField>(2);
			for (i = 0; i < 2; i++)
			{
				lifeTF[i] = new TextField();
				lifeTF[i].autoSize = TextFieldAutoSize.LEFT;
				lifeTF[i].embedFonts = true;
				lifeTF[i].defaultTextFormat = new TextFormat("life-font", 42);
				lifeTF[i].text = "5";
				lifeTF[i].x = 170;
				lifeTF[i].y = Height - 90;
				if (i == 0)
					lifeTF[i].textColor = 0;
				else
					lifeTF[i].textColor = 0xFFFFFF;
				lifeTF[i].selectable = false;
				lifeTF[i].mouseEnabled = false;
				addChild(lifeTF[i]);
			}
			
			timeLeft = 30;
			
			goto = new Point();
			
			timer = new Timer(25);
			timer.addEventListener(TimerEvent.TIMER, onTick);
			timer.start();
		}
		
		private function onTick(e: TimerEvent): void
		{
			var dt: Number = 0.025;
			
			/*if (x != goto.x || y != goto.y)
			{
				x = Global.Aspire(x, goto.x, 1200 * dt);
				y = Global.Aspire(y, goto.y, 800 * dt);
				return;
			}*/
			
			timeLeft -= dt;
			
			if (Math.round(timeLeft) < 0)
			{
				Timer(e.target).stop();
				Main(parent).gameOver(scores);
				return;
			}
			
			for (i = 0; i < 10; i++)
			{
				if (pebbles[level.num * 10 + i].active)
					pebbles[level.num * 10 + i].Update(dt);
				pebbles[level.num * 10 + i].collideSnake(snake);
			}
			
			underUI = false;
			
			snake.Update(dt);
			//for (var i: uint = 0; i < tail.length; i++)
				//tail[i].Update(dt);
			var tailLength: uint = 0;
			t = snake.son;
			while (t != null)
			{
				t.Update(dt);
				t = t.son;
				tailLength++;
			}
			scores += tailLength * dt * 1;	
				
			var aliveApples: uint = 0;
			var apples: Array = level.apples;
			for (var i : uint = 0; i < apples.length; i++)
				if (apples[i].alive)
				{
					if (Global.Distance(snake.x, snake.y, apples[i].x, apples[i].y) < Snake.radius + Apple.RADIUS)
					{
						apples[i].alive = false;
						applesSprite.removeChild(apples[i]);
						shadowSprite.removeChild(apples[i].shadow);
						
						scores += 2;
						
						timeLeft += 5 * (60 / Snake.speed);
						timeLeft = Math.min(timeLeft, 30);
						
						t = snake.son;
						var tp: Sprite = snake;
						while (t != null)
						{
							tp = t;
							t = t.son;
						}
						tail[tail.length] = new Tail(tp);
						tailSprite.addChildAt(tail[tail.length - 1], 0);
						shadowSprite.addChild(tail[tail.length - 1].shadow);
					}
					else
					{
						aliveApples++;
						// яблоко под интерфейсом - делаем его прозрачным					
						if (Global.collideCircleRect(apples[i].x, apples[i].y, Snake.radius, level.x + ui.width / 2, level.y + Height - ui.height / 2, ui.width / 2, ui.height / 2))
							underUI = true;
					}
				}
					
			if (aliveApples < 2 && level.num == applesRoom)
			{
				/*apples[apples.length] = new Apple(this);
				applesSprite.addChild(apples[apples.length - 1]);
				shadowSprite.addChild(apples[apples.length - 1].shadow);*/
				if (applesLeft > 0)
				{
					level.addApple();
					applesLeft--;
				}
				else
				if (aliveApples == 0)
				{
					timeLeft += 10;
					timeLeft = Math.min(timeLeft, 30);
					
					Snake.speed += 10;
					Snake.speed = Math.min(Snake.speed, 200);
					if (applesRoom != 0)
						levels[0].addApple();
					var randomRoom: uint = applesRoom;
					while (randomRoom == applesRoom)
						randomRoom = Math.round(Math.random() * 4);
					applesRoom = randomRoom;
					levels[applesRoom].addApple();
					if (applesRoom != 0)
						levels[applesRoom].addApple();
					applesLeft = 3;
					if (applesRoom == 0)
						applesLeft--;
				}	
			}
			
			var rocks: Array = level.rocks;
			for (i = 0; i < rocks.length; i++)
				if (Global.Distance(snake.x, snake.y, rocks[i].x, rocks[i].y) < Snake.radius + rocks[i].radius)
				{
					// столкновение с камнем - отбрасываем и разворачиваем змейку
					var speed: Point = Global.Speed(snake.x, snake.y, rocks[i].x, rocks[i].y);
					snake.x = rocks[i].x - speed.x * (Snake.radius + rocks[i].radius);
					snake.y = rocks[i].y - speed.y * (Snake.radius + rocks[i].radius);
					var angle: Number = Global.Angle2D(snake.x, snake.y, rocks[i].x, rocks[i].y) * 180 / Math.PI;
					snake.rotation = Global.AspireDegrees(snake.rotation, angle, 360 * dt);
				}
				
			var saws: Array = level.saws;
			for (i = 0; i < saws.length; i++)
			{				
				var killTail: Boolean = false;
				if (saws[i].updown)
				{
					var sw: Number = 20;
					var sh: Number = 70;
				}
				else
				{
					sw = 70;
					sh = 20;
				}
				var t: Tail = snake.son;
				
				if (!snake.invulnerable)
					if (Global.collideCircleRect(snake.x, snake.y, Snake.radius, saws[i].x, saws[i].y, sw, sh))
					{
						snake.life--;
						
						if (snake.life <= 0)
						{
							Timer(e.target).stop();
							Main(parent).gameOver(scores);
							return;
						}
						
						for (j = 0; j < 5; j++)
						{
							blood[blood.length] = new Blood(snake.x + (Math.random() * 2 - 1) * 16, snake.y + (Math.random() * 2 - 1) * 16);
							bloodSprite.addChild(blood[blood.length - 1]);
						}
						
						killTail = true;
						//t = snake.son;
						if (t != null)
							Snake(t.head).son = null;
						//var s: Point = new Point();
						/*if (saws[i].updown)
						{
							//var s: Point = Global.Speed(snake.x, snake.y, saws[i].x, snake.y);
							if (snake.x > saws[i].x)
								s.x = -1;
							else
								s.x = 1;
						}
						else
						{
							//s = Global.Speed(snake.x, snake.y, snake.x, saws[i].y);
							if (snake.y > saws[i].y)
								s.y = -1;
							else
								s.y = 1;
						}*/
					
						//snake.kickVelocity.x = s.x * Snake.speed * 1.5;
						//snake.kickVelocity.y = s.y * Snake.speed * 1.5;
						snake.kickVelocity.x = Math.cos(snake.rotation * Math.PI / 180) * Snake.speed;
						snake.kickVelocity.y = Math.sin(snake.rotation * Math.PI / 180) * Snake.speed;
						snake.invulnerableTime = 2;
					}
				
				while (t != null)
				{
					if (!killTail)
					{
						/*if (saws[i].updown)
						{
							var sw: Number = 20;
							var sh: Number = 70;
						}
						else
						{
							sw = 70;
							sh = 20;
						}*/
						
						if (Global.collideCircleRect(t.x, t.y, Snake.radius, saws[i].x, saws[i].y, sw, sh))
						{
							killTail = true;
							if (t.head is Tail)
							{
								Tail(t.head).son = null;
								Tail(t.head).imgs[0].visible = true;
								Tail(t.head).imgs[1].visible = false;
							}
							else
								Snake(t.head).son = null;
							//break;
						}
					}
					if (killTail)
					{
						shadowSprite.removeChild(t.shadow);
						tailSprite.removeChild(t);
						
						for (var j: uint = 0; j < 5; j++)
						{
							blood[blood.length] = new Blood(t.x + (Math.random() * 2 - 1) * 16, t.y + (Math.random() * 2 - 1) * 16);
							bloodSprite.addChild(blood[blood.length - 1]);
						}
					}
					t = t.son;
				}
				if (killTail)
					break;
			}
				
			for (i = 0; i < saws.length; i++)
			{
				saws[i].Update(dt);
				// столкновения пилы с игроком
			}
			
			// кровь
			for (i = 0; i < blood.length; i++)
				blood[i].Update(dt);
				
			// стенки (ЗАСТРЕВАЕТ В УГЛАХ)
			// верх
			if ((level.top == null) && (snake.y <= Snake.radius * 2 + level.y))
			{
				snake.y = Snake.radius * 2 + level.y;
				angle = Global.Angle2D(snake.x, snake.y, snake.x - 1, level.y) * 180 / Math.PI;
				snake.rotation = Global.AspireDegrees(snake.rotation, angle, 360 * dt);
			}
			// низ
			if ((level.bottom == null) && (snake.y >= Height - Snake.radius * 2 + level.y))
			{
				snake.y = Height - Snake.radius * 2 + level.y;
				angle = Global.Angle2D(snake.x, snake.y, snake.x - 1, Height + level.y) * 180 / Math.PI;
				snake.rotation = Global.AspireDegrees(snake.rotation, angle, 360 * dt);
			}
			// лево
			if ((level.left == null) && (snake.x <= Snake.radius * 2 + level.x))
			{
				snake.x = Snake.radius * 2 + level.x;
				angle = Global.Angle2D(snake.x, snake.y, level.x, snake.y) * 180 / Math.PI;
				snake.rotation = Global.AspireDegrees(snake.rotation, angle, 360 * dt);
			}
			// право
			if ((level.rigt == null) && (snake.x >= Width - Snake.radius * 2 + level.x))
			{
				snake.x = Width - Snake.radius * 2 + level.x;
				angle = Global.Angle2D(snake.x, snake.y, Width + level.x, snake.y) * 180 / Math.PI;
				snake.rotation = Global.AspireDegrees(snake.rotation, angle, 360 * dt);
			}
			
			if (snake.y < (level.y) && level.top != null)
			{
				level = level.top;
				this.y = -level.y;
				/*goto.x = -level.x;
				goto.y = -level.y;*/
				showEdges();
			}
			if (snake.y > (Height + level.y) && level.bottom != null)
			{
				level = level.bottom;
				this.y = -level.y;
				/*goto.x = -level.x;
				goto.y = -level.y;*/
				showEdges();
			}
			if (snake.x < (level.x) && level.left != null)
			{
				level = level.left;
				this.x = -level.x;
				/*goto.x = -level.x;
				goto.y = -level.y;*/
				showEdges();
			}
			if (snake.x > (Width + level.x) && level.rigt != null)
			{
				level = level.rigt;
				this.x = -level.x;
				/*goto.x = -level.x;
				goto.y = -level.y;*/
				showEdges();
			}
			
			lifeTF[0].text = "" + snake.life;
			lifeTF[1].text = "" + snake.life;
			ui.x = -this.x;
			ui.y = -this.y + Height - ui.height;
			arrow.x = -this.x + 55;
			arrow.y = -this.y + Height - 50;
			lifeTF[0].x = -this.x + 170 + 3;
			lifeTF[0].y = -this.y + Height - 90 - 3;
			lifeTF[1].x = -this.x + 170;
			lifeTF[1].y = -this.y + Height - 90;
			if (snake.life == 1)
				if (lifeTF[1].textColor != 0xFF0000)
					lifeTF[1].textColor = 0xFF0000;
			
			if (Global.collideCircleRect(snake.x, snake.y, Snake.radius, level.x + ui.width / 2, level.y + Height - ui.height / 2, ui.width / 2, ui.height / 2))
				var underUI: Boolean = true;
				
			if (underUI)
			{
				if (ui.alpha > 0.2)
				{
					ui.alpha -= dt;
					arrow.alpha -= dt;
					lifeTF[0].alpha -= dt;
					lifeTF[1].alpha -= dt;
				}
			}
			else
			{
				if (ui.alpha < 1)
				{
					ui.alpha += dt;
					arrow.alpha += dt;
					lifeTF[0].alpha += dt;
					lifeTF[1].alpha += dt;
				}
			}
			
			if (Math.round(timeLeft) <= 10)
			{
				if (playerTF.textColor != 0xFF0000)
				playerTF.textColor = 0xFF0000;
			}
			else
				if (playerTF.textColor != 0xFFFFFF)
					playerTF.textColor = 0xFFFFFF;
			
			var min_distance: Number = -1;
			var distance: Number;
			var apple: Apple;
			if (aliveApples > 0)
			{
				for (i = 0; i < apples.length; i++)
					if (apples[i].alive)
					{
						distance = Global.Distance(arrow.x, arrow.y, apples[i].x, apples[i].y);
						if (min_distance < 0)
						{
							min_distance = distance;
							apple = apples[i];
						}
						else
							if (min_distance > distance)
							{
								min_distance = distance;
								apple = apples[i];
							}
					}
			}
			else
			{
				/*if (currentRoom != 0)
					apples = levels[0].apples; // не работает!!!
				else
					apples = levels[applesRoom].apples;
				for (i = 0; i < apples.length; i++)
					if (apples[i].alive)
					{
						distance = Global.Distance(arrow.x, arrow.y, apples[i].x, apples[i].y);
						if (min_distance < 0)
						{
							min_distance = distance;
							apple = apples[i];
						}
						else
							if (min_distance > distance)
							{
								min_distance = distance;
								apple = apples[i];
							}
					}*/
				/*if (currentRoom != 0)
					var point: Point = new Point(levels[0].x + Width / 2, levels[0].y + Height / 2);
				else
					point = new Point(levels[applesRoom].x + Width / 2, levels[applesRoom].y + Height / 2);*/
				if (level.num != 0)
				{
					switch (level.num)
					{
						case 1: angle = -90; break;
						case 2: angle = +90; break;
						case 3: angle = -180; break;
						case 4: angle = 0; break;
					}
				}
				else
				{
					switch (applesRoom)
					{
						case 1: angle = +90; break;
						case 2: angle = -90; break;
						case 3: angle = 0; break;
						case 4: angle = -180; break;
					}
				}
			}
			if (apple != null)
			{
				angle = Global.Angle2D(arrow.x, arrow.y, apple.x, apple.y) * 180 / Math.PI - 90;
				arrow.rotation = Global.AspireDegrees(arrow.rotation, angle, 180 * dt);
			}
			else// if (point != null)
			{
				//angle = Global.Angle2D(arrow.x, arrow.y, point.x, point.y) * 180 / Math.PI - 90;
				angle -= 90;
				arrow.rotation = Global.AspireDegrees(arrow.rotation, angle, 180 * dt);
			}
			
			playerTF.text = "Время: " + Math.round(timeLeft) + "\n";
			playerTF.x = level.x + (Width - playerTF.width) / 2;
			playerTF.y = level.y + 12;
		}
		
		private function showEdges(): void
		{
			if (level.top == null)    edges[0].visible = true; else edges[0].visible = false;
			if (level.bottom == null) edges[1].visible = true; else edges[1].visible = false;
			if (level.left == null)   edges[2].visible = true; else edges[2].visible = false;
			if (level.rigt == null)   edges[3].visible = true; else edges[3].visible = false;
			// верхняя
			edges[0].x = Width / 2 + level.x;
			edges[0].y = 30 + level.y;
			edges[0].rotation = 180;
			// нижняя
			edges[1].x = Width / 2 + level.x;
			edges[1].y = Height - 30 + level.y;
			edges[1].rotation = 0;
			// левая
			edges[2].x = 30 + level.x;
			edges[2].y = Height / 2 + level.y;
			edges[2].rotation = 90;
			// правая
			edges[3].x = Width - 30 + level.x;
			edges[3].y = Height / 2 + level.y;
			edges[3].rotation = -90;
		}
		
		public function pause(p: Boolean): void
		{
			if (p)
				timer.stop();
			else
				timer.start();
		}
		
	}

}