package {

    import flash.display.Bitmap;
    import flash.display.MovieClip;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.TimerEvent;
    import flash.utils.Timer;
    import flash.display.BitmapData;
    import flash.geom.*;
    import flash.events.KeyboardEvent;
    import flash.events.MouseEvent;
	//** added for part 3
	import flash.utils.getTimer;
	// OIM
	import fl.motion.MatrixTransformer;
	import fl.motion.Color;
	import flash.filters.BlurFilter;
	
	//*** added for part 4
	//import FrameTimer;
	// OIM
	import com.indindi.Raster.FrameRate;
	import com.indindi.Raster.FrameRateRenderer;
	
	import com.indindi.Raster.ActiveGraphMem;
	import com.indindi.Raster.TimePerf;
	import com.indindi.Raster.ActiveGraphTimePerf;
	
	import com.indindi.StateMachine.*;
	import Specific.*;
	
	import com.indindi.Text.*;
	
	import flash.utils.getDefinitionByName;
	
	// Sound
	import flash.media.Sound;
	import flash.media.SoundChannel;
	import flash.media.SoundTransform;
	import flash.media.SoundMixer;
	
	// Flame
	import org.flintparticles.common.debug.*;
	import org.flintparticles.common.actions.*;
	import org.flintparticles.common.counters.*;
	import org.flintparticles.common.displayObjects.RadialDot;
	import org.flintparticles.common.initializers.*;
	import org.flintparticles.twoD.actions.*;
	import org.flintparticles.twoD.emitters.Emitter2D;
	import org.flintparticles.twoD.initializers.*;
	import org.flintparticles.twoD.renderers.*;
	import org.flintparticles.twoD.zones.*;	
	import org.flintparticles.common.energyEasing.TwoWay;

	
    public class Main extends MovieClip {
        
        var aRotation:Array=[]; 
        var aShipAnimation:Array=[];
        var shipAnimationArrayLength:int;
        var ship:Ship;
        var shipHolder:MovieClip;
        var animationTimer:Timer;
        var animationCounter:int;
        var playerObject:Object;
        var canvasBD:BitmapData;
        var canvasBitmap:Bitmap;
        var backgroundBD:BitmapData;
        var backgroundSource:Background;
        var gameTimer:Timer;
        var backgroundRect:Rectangle;
        var backgroundPoint:Point;
        var playerRect:Rectangle;
        var playerPoint:Point;
		
		var ringBD:BitmapData;
		var textBD:BitmapData;
        var statsRect:Rectangle;
        var statsPoint:Point;
		var fontBD:BitmapData;
		public var dText:DText;
		
		public var mainSM:StateMachine;
		
        var aKeyPress:Array=[];
        var spriteHeight:int=20;
        var spriteWidth:int=20;
		
		var popupObject:Object = new Object();

		//** part 2 variables
		var aAsteroidAnimation:Array=[];
		var asteroidAnimationTimer:Timer;
		var asteroidHolder:RockToCache;
		var asteroidFrames:int=24;
		var aRock:Array=[];
		var level:int=1;
		static const LIVES = 2;
		var rockPoint:Point=new Point(0,0);
		var rockRect:Rectangle=new Rectangle(0,0,64,64);
		var levelRocksCreated:Boolean=false;
		
		var aBallAnimation:Array=[];
		var ballHolder:BallToCache;
		var aBall:Array=[];
		var ballPoint:Point=new Point(0,0);
		var ballRect:Rectangle=new Rectangle(0,0,64,64);
		var levelBallsCreated:Boolean=false;

		//*** part 3 variables
		var missleTileSheet:BitmapData;
		var aMissileAnimation:Array;
		var aMissile:Array; //holds missile objects fires
		var missileSpeed:int=4;
		var missileWidth:int=19;
		var missileHeight:int=19;
		var missileTileSize:int=19;
		var missileArrayLength=10;
		var missilePoint:Point=new Point(0,0);
		var missileRect:Rectangle=new Rectangle(0,0,19,19);
		var missileMaxLife:int=50;
		static const MIN_FIRE_DELAY:Number=100;
		static const MAX_FIRE_DELAY:Number=400;
		static const STEP_LEVEL_FIRE_DELAY:Number=12;
		var levelMissileFireDelay:Number=MAX_FIRE_DELAY;
		var currentMissileFireDelay:Number=MAX_FIRE_DELAY;
		var lastMissileShot:Number=getTimer();
		
		//*** part 4 variables
		var missileLen:int;
		var missileCtr:int;
		var tempMissile:Object;
		var tempRock:Object;
		var rockLen:int;
		var rockCtr:int;
		var aFarmParticle:Array=[];
		var aActiveParticle:Array=[];
		var maxParticles:int=500;
		var maxPartsPerExplode:int=40;
		var explodeCtr:int;
		var tempPart:Object;
		var farmLen:int;
		var randIntVector:int;
		var randIntFrame:int;
		var activeLen:int;
		var partCtr:int;
		var partMaxSpeed:int=2;
		var partMaxLife:int=50;
		var partMinLife:int=10;
		var removePart:Boolean=false;
		var partPoint:Point=new Point(0,0);
		var partRect:Rectangle=new Rectangle(0,0,6,6);
		
		var tempBall:Object;
		var ballLen:int;
		var ballCtr:int;
		static const BOZ_LEVEL:int = 5;
		
		public var cacheGfxDone:Boolean = false;
		
		//part 4 optimizations
		var randInt:int;
		var randInt2:int;
		var ctr:int;
		//var frameTimer:FrameTimer;
		var frameRate:FrameRate;
		var frameRateRenderer:FrameRateRenderer;
		//var startBox:StartBox;
		var ag:ActiveGraphMem;
		
		var timePerf:TimePerf;
		var agtp:ActiveGraphTimePerf;
		var showHideRasters:SHRasters;
		var SHRastersBitmap:Bitmap;
		var SHRastersSprite:Sprite;
		var showRasters:Boolean = true;
		
		//part 5 optimizations ++
		public static const FRAME_RATE:int = 40;
		private var _period:Number = 1000 / FRAME_RATE;
		private var _beforeTime:int = 0;
		private var _afterTime:int = 0;
		private var _timeDiff:int = 0;
		private var _sleepTime:int = 0;
		private var _overSleepTime:int = 0;
		private var _excess:int = 0;		
	
		
		// Sons
		private var globalVol:Number = 1.0;
		
		private var sndLaserChannel:SoundChannel;
		private var sndLaser:SndLaser;
		
		private var sndMoveChannel:SoundChannel;
		private var sndMove:SndMove;
		private var sndMovePlaying:Boolean = false;
		
		private var sndExplodeChannel:SoundChannel;
		private var sndExplode:SndExplode;
		private var sndExplode2:SndExplode2;
		private var sndExplode3:SndExplode3;
		private var sndExplode4:SndExplode4;
		
		private var sndDeadStateChannel:SoundChannel;
		private var sndDeadState:SndDeadState;
		
		private var sndBackgroundChannel:SoundChannel;
		private var sndBackground:SndBackground;
		
		private var sndGameOverChannel:SoundChannel;
		private var sndGameOver:SndGameOver;
		
		private var sndScoreChannel:SoundChannel;
		private var sndScore:SndScore;
		
		// Flame
		private var flameBD:BitmapData;
        var aFlameAnimation:Array=[];
		var emitter:Emitter2D;
		var flameRenderer:BitmapRenderer;
		var flameIndex:Number = 0;
		var flameAnimationTimer:Timer;

		
		var backOptions:BackOptions;
		var backOptionsBitmap:Bitmap;
		var backOptionsSprite:Sprite;
		
		var firePercents:int=100;
		var fireBarBD:BitmapData;
		var fireBarBgBD:BitmapData;
		
		private function createObjects():void {
			//create generic object for the player
			playerObject=new Object();
			playerObject.lives = LIVES;
			playerObject.score = 0;
			playerObject.instantScore = 0;
			playerObject.arrayIndex=0;
			playerObject.x=180;
			playerObject.y=180;
			playerObject.dx=0;
			playerObject.dy=0;
			playerObject.movex=0;
			playerObject.movey=0;
			playerObject.acceleration=.3;
			playerObject.maxVelocity=8;
			playerObject.friction=.01;
			playerObject.centerx=playerObject.x+spriteWidth;
			playerObject.centery=playerObject.y+spriteHeight;
			playerRect=new Rectangle(0,0,spriteWidth*2,spriteHeight*2);
			playerPoint=new Point(playerObject.x,playerObject.y);
			
			
			
			//init canvas and display bitmap for canvas
			canvasBD=new BitmapData(400,400,false,0x000000);
			canvasBitmap=new Bitmap(canvasBD);
			
			//init background
			backgroundSource=new Background();
			backgroundBD=new BitmapData(400,400,false,0x000000);
			backgroundBD.draw(backgroundSource,new Matrix());
			backgroundRect=new Rectangle(0,0,400,400);
			backgroundPoint=new Point(0,0);
    
			//part 3 init tilesheet for missiles
			aMissile=[];
			aMissileAnimation=[];
			missleTileSheet=new MissileSheet(190,19);
			var tilesPerRow:int=10;
			for (var tileNum=0;tileNum<10;tileNum++) {
				var sourceX:int=tileNum*missileTileSize;
				var sourceY:int=0;
				var tileBitmapData:BitmapData=new BitmapData(missileTileSize,missileTileSize,true,0x00000000);
				tileBitmapData.copyPixels(missleTileSheet,
					   new Rectangle(sourceX,sourceY,missileTileSize,missileTileSize),new Point(0,0));
				aMissileAnimation.push(tileBitmapData);
				//trace("X = "+sourceX+", sourceY"+sourceY);
			}
			
			//added in part 4
			createFarmParticles();
			
			frameRate=new FrameRate(FRAME_RATE);//this,140,0,canvasBD);
			frameRate.Start();
			frameRateRenderer=new FrameRateRenderer(150,0,canvasBD,frameRate);
			showHideRasters = new SHRasters(20, 150);
			SHRastersBitmap = new Bitmap(showHideRasters);
			SHRastersSprite = new Sprite();
			SHRastersSprite.x = 0;
			SHRastersSprite.y = 125;
			SHRastersSprite.addChild(SHRastersBitmap);
			
			backOptions = new BackOptions(20, 160);
			backOptionsBitmap = new Bitmap(backOptions);
			backOptionsSprite = new Sprite();
			backOptionsSprite.x = 120;
			backOptionsSprite.y = 380;
			backOptionsSprite.addChild(backOptionsBitmap);
			
//			timePerf.TracePerfs();
			
			// Initialisation de la SM pour le joueur
			playerObject.SM = new StateMachine();
			playerObject.SM.SetInitState(new AliveState(playerObject.SM, this, "AliveState"));
			playerObject.SM.SetNextState(new DeadState(playerObject.SM, this, "DeadState"));
			ringBD = new Ring(40, 40);
			
			statsRect = new Rectangle(0, 0, stage.stageWidth, 50);
			statsPoint = new Point(0, 350);
			fontBD = new GfxFontConsole(256,96);
			dText = new DText(fontBD, 9, 16, 7);

			
			// Initialisation de la SM pour le jeu
			mainSM = new StateMachine();
			mainSM.SetInitState(new IntroState(mainSM, this, "IntroState"));
			mainSM.SetNextState(new OptionState(mainSM, this, "OptionState"));
			
			// init des sons
			sndLaser = new SndLaser();
			sndMove = new SndMove();
			sndExplode = new SndExplode();
			sndExplode2 = new SndExplode2();
			sndExplode3 = new SndExplode3();
			sndExplode4 = new SndExplode4();
			sndDeadState = new SndDeadState();
			sndBackground = new SndBackground();
			sndGameOver = new SndGameOver();
			sndScore = new SndScore();

			
			//flameBD = new Flame(30, 30);
			var flameBD:BitmapData = new Flame(27, 27);
			
			emitter = new Emitter2D();
			emitter.counter = new Steady( 600 );
			
			emitter.addInitializer( new Lifetime( 0.5 ) );
			emitter.addInitializer( new Velocity( new DiscSectorZone( new Point( 0, 0 ), 10, 5, -Math.PI * 0.75, -Math.PI * 0.25 ) ) );
			emitter.addInitializer( new Position( new BitmapDataZone( flameBD ) ) );
			emitter.addInitializer( new ImageClass( FireBlob ) );
			
			emitter.addAction( new Age( TwoWay.circular ) );
			emitter.addAction( new Move() );
			emitter.addAction( new Accelerate( 0, 50 ) );
			emitter.addAction( new ColorChange( 0xFFFF0000, 0x00fffcbc ) );
			emitter.addAction( new ScaleImage( 0.0, 1.3 ) );
			emitter.addAction( new RotateToDirection() );
			
			flameRenderer = new BitmapRenderer( new Rectangle( 0, 0, 27, 27 ) );
			flameRenderer.addEmitter( emitter );
			
			addChild( flameRenderer );
			flameRenderer.x = -50;
			flameRenderer.y = -50;
			emitter.x = 0;
			emitter.y = 0;
			emitter.start();
			
			// FireBar
			fireBarBD = new BitmapData(100, 5, false, 0x888888);
			var color:Color = new Color(1, 1, 0, 1, 255, 255, 0, 255);
			for (var i:int=0; i<100; i++) {
				color.greenOffset -= 255/100;
				fireBarBD.fillRect(new Rectangle(i, 0, 1, fireBarBD.height), color.color);
			}
			fireBarBgBD = new BitmapData(102, 7, true, 0x88FFFFFF);
			fireBarBgBD.fillRect(new Rectangle(1, 1, 100, fireBarBD.height), 0x888888);
						
		}
		
		private function createFarmParticles() {
			var particleCtr:int;
			for (particleCtr=0;particleCtr<maxParticles;particleCtr++) {
				var tempPart:Object={};
				tempPart.lifeCount=0;
				tempPart.life=0;
				tempPart.x=0;
				tempPart.y=0;
				tempPart.dx=0;
				tempPart.dy=0;
				tempPart.speed=0;
				tempPart.bitmapData=null;
				aFarmParticle.push(tempPart);
			}
		}
		
		
		private function createRotationArray():void {
			shipAnimationArrayLength=36;
			var rotation:int=0;
			for (var ctr:int=0;ctr<shipAnimationArrayLength;ctr++) {
				var tempObject:Object={};
				tempObject.dx=Math.cos(2.0*Math.PI*(rotation-90)/360.0);
				tempObject.dy=Math.sin(2.0*Math.PI*(rotation-90)/360.0);
				
				// OIM
				tempObject.rot = rotation;
				
//				trace(ctr+":dx=" + Math.cos(2.0*Math.PI*(rotation-90)/360.0));
//				trace(ctr+":dy=" + Math.sin(2.0*Math.PI*(rotation-90)/360.0));
				aRotation.push(tempObject);
				rotation+=10;
			}
		
			//trace("aRotation[5].dx=" + aRotation[5].dx);
		}	
		
		private function createShipAnimation():void {
			shipHolder=new MovieClip();
			shipHolder.x=-50;
			shipHolder.y=-50;
			ship=new Ship();
			ship.x=spriteWidth;
			ship.y=spriteHeight;
			shipHolder.addChild(ship);
			addChild(shipHolder);
			animationCounter=0;
			animationTimer=new Timer(1,36);
			animationTimer.addEventListener(TimerEvent.TIMER, cacheShip);
			animationTimer.addEventListener(TimerEvent.TIMER_COMPLETE, animationTimerCompleteHandler);
			animationTimer.start();
		}	
		
		private function cacheShip(e:TimerEvent):void {
			var spriteMapBitmap:BitmapData=new BitmapData(spriteWidth*2,spriteHeight*2,true,0x00000000);
			spriteMapBitmap.draw(shipHolder,new Matrix(), null, null, null, true);
			aShipAnimation.push(spriteMapBitmap);
			//trace("caching " + animationCounter);
			animationCounter++;
			ship.rotation+=10;
		}
			
		private function animationTimerCompleteHandler(e:TimerEvent):void {
			trace("CacheShip done ...");
    		createAsteroidAnimation();
			//startGame();
		}

		private function createAsteroidAnimation():void {
			animationCounter=1; // match frame on timeline
			asteroidHolder=new RockToCache();
			asteroidHolder.x=-100;
			asteroidHolder.y=-100;
			addChild(asteroidHolder);
			asteroidAnimationTimer=new Timer(1,asteroidFrames);
			asteroidAnimationTimer.addEventListener(TimerEvent.TIMER, cacheAsteroid);
			asteroidAnimationTimer.addEventListener(TimerEvent.TIMER_COMPLETE, 
					asteroidAnimationTimerCompleteHandler);
			asteroidAnimationTimer.start();
		}
		
		private function cacheAsteroid(e:TimerEvent):void {
			asteroidHolder.gotoAndStop(animationCounter);
			var spriteMapBitmap:BitmapData=new BitmapData(64,64,true,0x00000000);
			spriteMapBitmap.draw(asteroidHolder,new Matrix());
			aAsteroidAnimation.push(spriteMapBitmap);
			//trace("caching anim " + animationCounter);
			animationCounter++;
		}
		
		private function asteroidAnimationTimerCompleteHandler(e:TimerEvent):void {
			trace("CacheAsteroid done ...");
			removeChild(asteroidHolder);
			createBallAnimation();
		}

		private function createBallAnimation():void {
			animationCounter=1; // match frame on timeline
			ballHolder=new BallToCache();
			ballHolder.x=-100;
			ballHolder.y=-100;
			addChild(ballHolder);
			asteroidAnimationTimer=new Timer(1,asteroidFrames);
			asteroidAnimationTimer.addEventListener(TimerEvent.TIMER, cacheBall);
			asteroidAnimationTimer.addEventListener(TimerEvent.TIMER_COMPLETE, 
					ballAnimationTimerCompleteHandler);
			asteroidAnimationTimer.start();
		}
		
		private function cacheBall(e:TimerEvent):void {
			ballHolder.gotoAndStop(animationCounter);
			var spriteMapBitmap:BitmapData=new BitmapData(64,64,true,0x00000000);
			spriteMapBitmap.draw(ballHolder,new Matrix());
			aBallAnimation.push(spriteMapBitmap);
			//trace("caching anim " + animationCounter);
			animationCounter++;
		}
		
		private function ballAnimationTimerCompleteHandler(e:TimerEvent):void {
			trace("CacheBall done ...");
			removeChild(ballHolder);
			// Display Intro :
			//cacheGfxDone = true;
			//startGame();
			createFlameAnimation();
		}
		
		private function createFlameAnimation():void {
			flameIndex = 0;
			
			flameAnimationTimer = new Timer(_period, FRAME_RATE);
			flameAnimationTimer.addEventListener(TimerEvent.TIMER, cacheFlame);
			flameAnimationTimer.addEventListener(TimerEvent.TIMER_COMPLETE, 
					flameAnimationTimerCompleteHandler);
			flameAnimationTimer.start();
		}
		
		private function cacheFlame(e:TimerEvent):void {
			var spriteMapBitmap:BitmapData=new BitmapData(27,27,true,0x00000000);
			spriteMapBitmap.draw(flameRenderer);
			aFlameAnimation.push(spriteMapBitmap);
		}
		
		private function drawFlameSheet():void {
			for (var i:int=0; i<aFlameAnimation.length; i++) {
				//canvasBD.copyPixels(aFlameAnimation[i], aFlameAnimation[i].rect, new Point(27*i, 0));
				var b:Bitmap = new Bitmap(aFlameAnimation[i]);
				addChild(b);
				b.x = 27*i;   
			}
		}
		
		private function flameAnimationTimerCompleteHandler(e:TimerEvent):void {
			trace("CacheFlame done ...");
			//removeChild(flameRenderer);
			// Display Intro :
			cacheGfxDone = true;
			dispatchEvent(new Event("CacheGfxDone"));
			//drawFlameSheet();
			//startGame();
		}
		
		public function startGame():void {
			
			playerObject.score = 0;
			playerObject.lives = LIVES;
			
			// Catch Perfs
			ag=new ActiveGraphMem(0,false,true,1);			
			timePerf = new TimePerf();
			timePerf.AddPerfType("DRAW");
			timePerf.AddPerfType("CALC");	
			agtp = new ActiveGraphTimePerf(this, timePerf, 0,false,true,1);
			agtp.x = stage.stageWidth - agtp.width;

			levelRocksCreated=false;
			levelBallsCreated=false;
			
			addChild(canvasBitmap);
			addChild(ag);
			addChild(agtp);
			//addChild(getScoreBitmap());
			stage.addEventListener(KeyboardEvent.KEY_DOWN,keyDownListener);
			stage.addEventListener(KeyboardEvent.KEY_UP,keyUpListener);
			
			SHRastersSprite.addEventListener(MouseEvent.CLICK,SHRastersListener);
			addChild(SHRastersSprite);
			
			backOptionsSprite.addEventListener(MouseEvent.CLICK,backOptionsListener);
			addChild(backOptionsSprite);
			
			////////// PART 5 - OPTIMIZATIONS
			gameTimer=new Timer(_period,1); //changed in part 3 from 50
			gameTimer.addEventListener(TimerEvent.TIMER, runGame);
			gameTimer.start();			//added in part 4
			playerObject.bitmapData=aShipAnimation[playerObject.arrayIndex];
			
			playBackgroundSound();
			playGameOverSound();
			
			// Set Fire power
			var start_fire_delay:Number = MAX_FIRE_DELAY - STEP_LEVEL_FIRE_DELAY*(level-1);
			if (start_fire_delay > MIN_FIRE_DELAY) {
				levelMissileFireDelay = start_fire_delay;
			} else {
				levelMissileFireDelay = MIN_FIRE_DELAY;
			}
			currentMissileFireDelay = levelMissileFireDelay;

		}
		
		private function keyDownListener(e:KeyboardEvent) {
			//trace("down e.keyCode=" + e.keyCode);
			aKeyPress[e.keyCode]=true;
		}
		
		private function keyUpListener(e:KeyboardEvent) {
			//trace("up e.keyCode=" + e.keyCode);
			aKeyPress[e.keyCode]=false;
		}
		
		private function SHRastersListener(e:MouseEvent) {
			if (e.target == SHRastersSprite) {
				if (ag.visible) {
					ag.visible = false;
					agtp.visible = false;
					showRasters = false;
				} else {
					ag.visible = true;
					agtp.visible = true;
					showRasters = true;
				}
			}
		}
		
		private function backOptionsListener(e:MouseEvent) {
			mainSM.ChangeState(new OptionState(mainSM, this, "OptionState"));
		}
				
		private function checkKeys():void {
			if (playerObject.SM.getCurrentStateName() != "DeadState") {
				if (aKeyPress[38]){
					//trace("up pressed");
					playerObject.dx=aRotation[playerObject.arrayIndex].dx;
					playerObject.dy=aRotation[playerObject.arrayIndex].dy;
					
					var mxn:Number=playerObject.movex+playerObject.acceleration*(playerObject.dx);
					var myn:Number=playerObject.movey+playerObject.acceleration*(playerObject.dy);
				
					var currentSpeed:Number = Math.sqrt ((mxn*mxn) + (myn*myn));
					if (currentSpeed < playerObject.maxVelocity) {
						playerObject.movex=mxn;
						playerObject.movey=myn;
					} // end speed check
					
					// Jouage de son
					if (!sndMovePlaying) {
						sndMoveChannel = sndMove.play();
						sndMoveChannel.addEventListener(Event.SOUND_COMPLETE, sndMoveCompleteHandler); 
						sndMovePlaying = true;
					}
				}
				if (aKeyPress[37]){
					playerObject.arrayIndex--;
					if (playerObject.arrayIndex <0) playerObject.arrayIndex=shipAnimationArrayLength-1;
					 //added in part 4
					playerObject.bitmapData=aShipAnimation[playerObject.arrayIndex];
					
				}
				if (aKeyPress[39]){
					playerObject.arrayIndex++;
					if (playerObject.arrayIndex==shipAnimationArrayLength) playerObject.arrayIndex=0;
					 //added in part 4
					playerObject.bitmapData=aShipAnimation[playerObject.arrayIndex];
					
				}
				
				//*** added for part 3
				if (aKeyPress[32]){ // Space bar to fire
					// Firing
					fireMissile();					
					// Losing fire power
					var next_missile_fire_delay:Number = currentMissileFireDelay + (MAX_FIRE_DELAY-levelMissileFireDelay)/(10*FRAME_RATE);
					if (next_missile_fire_delay < MAX_FIRE_DELAY) {
						currentMissileFireDelay = next_missile_fire_delay;
					} else {
						currentMissileFireDelay = MAX_FIRE_DELAY;
					}
				} else {
					// Missiles Power recovering
					var next_fire_delay:Number = currentMissileFireDelay - (MAX_FIRE_DELAY - levelMissileFireDelay)/(10*FRAME_RATE);
					if (next_fire_delay < levelMissileFireDelay) {
						currentMissileFireDelay = levelMissileFireDelay;
					} else {
						currentMissileFireDelay = next_fire_delay;
					}
				}
			}
//				
//			if (aKeyPress[17]){ // Ctrl Key to go to Option Pane
//				mainSM.ChangeState(new OptionState(mainSM, this, "OptionState"));
//			}
		}
		
		private function sndMoveCompleteHandler(e:Event) {
			sndMovePlaying = false;
		}
		
		private function fireMissile():void {
			if (getTimer() > lastMissileShot + currentMissileFireDelay) {
				var tempMissile:Object=new Object();
				tempMissile.x=playerObject.centerx- missileTileSize/2;
				tempMissile.y=playerObject.centery- missileTileSize/2;
				tempMissile.dx=aRotation[playerObject.arrayIndex].dx;
				tempMissile.dy=aRotation[playerObject.arrayIndex].dy;
				tempMissile.speed=missileSpeed;
				tempMissile.life=50;
				tempMissile.lifeCount=0;
				tempMissile.animationIndex=0;
				
				// OIM
				tempMissile.rot = aRotation[playerObject.arrayIndex].rot;
				aMissile.push(tempMissile);
				lastMissileShot=getTimer();
				
				// Jouage de son
				sndLaserChannel = sndLaser.play(); 
			}
		}
		
		//added in part 4
		private function checkCollisions():void {
			missileLen=aMissile.length-1;
			rockLen=aRock.length-1;
				
			rocks: for (rockCtr=rockLen;rockCtr>=0;rockCtr--) {
				tempRock=aRock[rockCtr];
				rockPoint.x=tempRock.x;
				rockPoint.y=tempRock.y;
				missiles: for (missileCtr=missileLen;missileCtr>=0;missileCtr--) {
					tempMissile=aMissile[missileCtr];
					missilePoint.x=tempMissile.x;
					missilePoint.y=tempMissile.y;
					//trace("1");
					try{
						if (tempMissile.bitmapData.hitTest(missilePoint,255,tempRock.bitmapData,rockPoint,255)) {
						//	trace("hit!");
							// The smaller the asteroid, the higher the score !!
							playerObject.instantScore = (level+64-tempRock.size)*(aBall.length+1);
							popupObject.alpha = 1.0;
							popupObject.blur = 1.0;
							popupObject.point = new Point(tempRock.x+tempRock.size/2, tempRock.y+tempRock.size/2);
							
							playerObject.score += playerObject.instantScore;
							createExplode(popupObject.point.x,popupObject.point.y,"Yellow");
							tempMissile=null;
							tempRock=null;
							aMissile.splice(missileCtr,1);
							aRock.splice(rockCtr,1);
							break rocks;
							break missiles;
							
						}
					}catch(e:Error) {
						//trace("error in missle test");
					}
				}
				
				//trace("2");
				playerPoint.x=playerObject.x;
				playerPoint.y=playerObject.y;
				try{
					if (tempRock.bitmapData.hitTest(rockPoint,255,playerObject.bitmapData,playerPoint,255)
						 && (playerObject.SM.getCurrentStateName() != "DeadState")){
						//trace("ship hit");
						createExplode(tempRock.x+tempRock.size/2,tempRock.y+tempRock.size/2, "Yellow");
						createExplode(playerObject.centerx, playerObject.centery, "Red");
						//playerState = "dead";
						playerObject.SM.GotoNextState();
						tempRock=null;
						aRock.splice(rockCtr,1);
					}
				}catch(e:Error) {
					//trace("error in ship test");
				}
			}
		
				
			missileLen=aMissile.length-1;
			ballLen=aBall.length-1;
			
			balls: for (ballCtr=ballLen;ballCtr>=0;ballCtr--) {
				tempBall=aBall[ballCtr];
				ballPoint.x=tempBall.x;
				ballPoint.y=tempBall.y;
				missiles2: for (missileCtr=missileLen;missileCtr>=0;missileCtr--) {
					tempMissile=aMissile[missileCtr];
					missilePoint.x=tempMissile.x;
					missilePoint.y=tempMissile.y;
					//trace("1");
					try{
						if (tempMissile.bitmapData.hitTest(missilePoint,255,tempBall.bitmapData,ballPoint,255)) {
						//	trace("hit!");
							createExplode(missilePoint.x,missilePoint.y,"Blue");
							tempMissile=null;
							//tempRock=null;
							aMissile.splice(missileCtr,1);
							//aRock.splice(rockCtr,1);
							break balls;
							break missiles2;
							
						}
					}catch(e:Error) {
						//trace("error in missle test");
					}
				}
				
				//trace("2");
				playerPoint.x=playerObject.x;
				playerPoint.y=playerObject.y;
				try{
					if (tempBall.bitmapData.hitTest(ballPoint,255,playerObject.bitmapData,playerPoint,255)
						 && (playerObject.SM.getCurrentStateName() != "DeadState")){
						//trace("ship hit");
						//createExplode(tempRock.x+tempRock.size/2,tempRock.y+tempRock.size/2, "Yellow");
						createExplode(playerObject.centerx, playerObject.centery, "Red");
						//playerState = "dead";
						playerObject.SM.GotoNextState();
//						tempBall=null;
//						aBall.splice(ballCtr,1);
					}
				}catch(e:Error) {
					//trace("error in ship test");
				}
			}
		
		}
		
		private function createExplode(xval:Number, yval:Number, classPrefix:String):void {
			
			//trace("aFarmParticle.length=" + aFarmParticle.length);
			//trace("aActiveParticle.length=" + aActiveParticle.length);
			
			for (explodeCtr=0;explodeCtr<maxPartsPerExplode;explodeCtr++) {
				farmLen=aFarmParticle.length-1;
				if (farmLen >0){
					tempPart=aFarmParticle[farmLen];
					aFarmParticle.splice(farmLen,1);
					tempPart.lifeCount=0;
					tempPart.life=int(Math.random()*partMaxLife)+partMinLife;;
					tempPart.x=xval;
					tempPart.y=yval;
					tempPart.speed=(Math.random()*partMaxSpeed)+1;
					randIntFrame=int(Math.random()*10);
					
					// OIM
					//tempPart.bitmapData=aMissileAnimation[randIntFrame];
					var partClass:Class = getDefinitionByName(classPrefix+"_Particule") as Class;
					tempPart.bitmapData = new partClass(6,6);
					
					randIntVector=int(Math.random()*36);
					tempPart.dx=aRotation[randIntVector].dx;
					tempPart.dy=aRotation[randIntVector].dy;
					aActiveParticle.push(tempPart);
				}
			}
			
			if (classPrefix == "Red" || classPrefix == "Yellow") {
				var r:Number = Math.random();
				if (r < 0.33) {
					sndExplodeChannel = sndExplode.play();
				} else {
					if (r < 0.66) {
						sndExplodeChannel = sndExplode2.play();
					} else {
						sndExplodeChannel = sndExplode3.play();
					}
				}
			} else {
				sndExplodeChannel = sndExplode4.play();
			}
			
		}

		private function updatePlayer():void {
			
			//add friction
			
			if (playerObject.movex > 0) {
				playerObject.movex-=playerObject.friction;
			}else if (playerObject.movex < 0) {
				playerObject.movex+=playerObject.friction;
			}
			
			if (playerObject.movey > 0) {
				playerObject.movey-=playerObject.friction;
			}else if (playerObject.movey < 0) {
				playerObject.movey+=playerObject.friction;
			}
		
			playerObject.x+=(playerObject.movex);
			playerObject.y+=(playerObject.movey);
						
			playerObject.centerx=playerObject.x+spriteWidth;
			playerObject.centery=playerObject.y+spriteHeight;
			
			if (playerObject.centerx > stage.width) {
				playerObject.x=-spriteWidth;
				playerObject.centerx=playerObject.x+spriteWidth;
			}else if (playerObject.centerx < 0) {
				playerObject.x=stage.width - spriteWidth;
				playerObject.centerx=playerObject.x+spriteWidth;
			}
			
			if (playerObject.centery > stage.height) {
				playerObject.y=-spriteHeight;
				playerObject.centery=playerObject.y+spriteHeight;
			}else if (playerObject.centery < 0) {
				playerObject.y=stage.height-spriteHeight;
				playerObject.centery=playerObject.y+spriteHeight;
			}
			
		}
		
		private function updateRocks():void {
			if (!levelRocksCreated) {
				for (var ctr:int=0;ctr<level+3;ctr++) {/*level+2*/
					//create a rock;
					var tempRock:Object=new Object();
					var randInt:int=int(Math.random()*36);
					var randInt2:int=int(Math.random()*asteroidFrames);
					tempRock.dx=aRotation[randInt].dx;
					tempRock.dy=aRotation[randInt].dy;
					tempRock.x =  (Math.random() > 0.5) ? 20 : 380;
					tempRock.y = (Math.random() > 0.5) ? 20 : 380;
					tempRock.animationIndex=randInt2;
					tempRock.frameDelay=1;
					tempRock.frameCount=0;
					//tempRock.speed = (Math.random()*level)+1;
					tempRock.speed = (Math.random()*(level/10)+1.0);
					
					tempRock.scale = 0.3+0.7*Math.random();
					tempRock.size = Math.round(tempRock.scale*64);
					tempRock.rect = new Rectangle(0, 0, tempRock.size, tempRock.size);
					aRock.push(tempRock);
				}
				levelRocksCreated=true;
			}
			for each (tempRock in aRock) {
				tempRock.x+=tempRock.dx*tempRock.speed;
				tempRock.y+=tempRock.dy*tempRock.speed;
				
				if (tempRock.x > stage.width) {
					tempRock.x=0;
				}else if (tempRock.x < -tempRock.size) {
					tempRock.x=stage.width;
				}
				
				if (tempRock.y > stage.height) {
					tempRock.y=0;
				}else if (tempRock.y < -tempRock.size) {
					tempRock.y=stage.height;
				}
				
			}
		}

		
		private function updateBalls():void {
			if (level % BOZ_LEVEL == 0) {
				if (!levelBallsCreated) {
					var nb_balls:int = Math.round(level/BOZ_LEVEL);
					for (var ctr:int=0;ctr<nb_balls;ctr++) {/*level+2*/
						//create a rock;
						var tempBall:Object=new Object();
						var randInt:int=int(Math.random()*36);
						var randInt2:int=int(Math.random()*asteroidFrames);
						tempBall.dx=aRotation[randInt].dx;
						tempBall.dy=aRotation[randInt].dy;
						tempBall.x =  (Math.random() > 0.5) ? 20 : 380;
						tempBall.y = (Math.random() > 0.5) ? 20 : 380;
						tempBall.animationIndex=randInt2;
						tempBall.frameDelay=1;
						tempBall.frameCount=0;
						//tempRock.speed = (Math.random()*level)+1;
						tempBall.speed = (Math.random()*(level/10)+1.0);
						
						tempBall.size = 64;
	//					tempRock.scale = 0.3+0.7*Math.random();
	//					tempRock.rect = new Rectangle(0, 0, tempRock.size, tempRock.size);
						aBall.push(tempBall);
					}
					levelBallsCreated=true;
				}
				for each (tempBall in aBall) {
					tempBall.x+=tempBall.dx*tempBall.speed;
					tempBall.y+=tempBall.dy*tempBall.speed;
					
					if (tempBall.x > stage.width) {
						tempBall.x=0;
					}else if (tempBall.x < -tempBall.size) {
						tempBall.x=stage.width;
					}
					
					if (tempBall.y > stage.height) {
						tempBall.y=0;
					}else if (tempBall.y < -tempBall.size) {
						tempBall.y=stage.height;
					}
					
				}
			}
		}

		
		private function updateMissiles():void {
			var missileLen:int=aMissile.length-1;
			for (var ctr:int=missileLen;ctr>=0;ctr--) {
				var tempMissile:Object=aMissile[ctr];
				tempMissile.x+=tempMissile.dx*tempMissile.speed;;
				tempMissile.y+=tempMissile.dy*tempMissile.speed;
				
				if (tempMissile.x > stage.width) {
					tempMissile.x=0;
				}else if (tempMissile.x < 0) {
					tempMissile.x=stage.width;
				}
				
				if (tempMissile.y > stage.height) {
					tempMissile.y=0;
				}else if (tempMissile.y < 0) {
					tempMissile.y=stage.height
				}
				
				tempMissile.lifeCount++;
				if (tempMissile.lifeCount > tempMissile.life) {
					aMissile.splice(ctr,1);
					tempMissile=null;
				}
				
			}
		}
		
		
		private function drawBackground():void {
			canvasBD.copyPixels(backgroundBD, backgroundRect, backgroundPoint);
			//canvasBD.fillRect(backgroundRect, 0x000000);
		}
		
		public function drawPlayer():void {
			playerPoint.x=playerObject.x;
			playerPoint.y=playerObject.y;
			
			if (sndMovePlaying) {
				var tempFlameBD:BitmapData = new BitmapData(27, 27, true, 0x0000000);
				//var mtx_transformer:MatrixTransformer = new MatrixTransformer();
				var mtx:Matrix = new Matrix();
				//MatrixTransformer.setRotation(mtx, tempMissile.rot);
				MatrixTransformer.rotateAroundInternalPoint(mtx, 13,  13, aRotation[playerObject.arrayIndex].rot);
				
				tempFlameBD.draw(aFlameAnimation[flameIndex], mtx, null, null, null, true);
				if (flameIndex < aFlameAnimation.length-1) {
					flameIndex++;
				} else {
					flameIndex = 0;
				}

				var u:Number = -aRotation[playerObject.arrayIndex].dx;
				var v:Number = -aRotation[playerObject.arrayIndex].dy;
				var p:Point = new Point(playerObject.centerx-13+Math.floor(20*u), playerObject.centery-13+Math.floor(20*v));
				canvasBD.copyPixels(tempFlameBD, tempFlameBD.rect, p);
				
			} else {
				//flameIndex = 0;
			}
			canvasBD.copyPixels(aShipAnimation[playerObject.arrayIndex],playerRect, playerPoint);
			
		}
		
		public function drawRing():void {
			playerObject.x=180;
			playerObject.y=180;
			canvasBD.copyPixels(ringBD, playerRect, new Point(180, 180));				
		}
		
		private function drawRocks() {
			var rockLen:int=aRock.length-1;
			var ctr:int;
		
			for each (var tempRock:Object in aRock) {
			
				rockPoint.x=tempRock.x;
				rockPoint.y=tempRock.y;
				
				var mtx:Matrix = new Matrix();
				var rockScaled:BitmapData = new BitmapData(tempRock.size, tempRock.size, true, 0x00000000);
				var rockScaledTemp:BitmapData = new BitmapData(64, 64, true, 0x00000000);
				rockScaledTemp.draw(aAsteroidAnimation[tempRock.animationIndex], mtx);
				MatrixTransformer.setScaleX(mtx, tempRock.scale);
				MatrixTransformer.setScaleY(mtx, tempRock.scale);
				rockScaled.draw(rockScaledTemp, mtx);
				canvasBD.copyPixels(rockScaled, rockScaled.rect, rockPoint);
//				canvasBD.copyPixels(aAsteroidAnimation[tempRock.animationIndex],rockRect, rockPoint);
				
				tempRock.frameCount++;
				if (tempRock.frameCount > tempRock.frameDelay){
				
					tempRock.animationIndex++;
					if (tempRock.animationIndex > asteroidFrames-1) {
						tempRock.animationIndex = 0;
					}
					tempRock.frameCount=0;
					//added in part 4
					tempRock.bitmapData = rockScaled;
					//tempRock.bitmapData=aAsteroidAnimation[tempRock.animationIndex];
				}
			}
			
		}		
		
		private function drawBalls() {
			var ballLen:int=aBall.length-1;
			var ctr:int;
		
			for each (var tempBall:Object in aBall) {
			
				ballPoint.x=tempBall.x;
				ballPoint.y=tempBall.y;
				
				canvasBD.copyPixels(aBallAnimation[tempBall.animationIndex],ballRect, ballPoint);
				
				tempBall.frameCount++;
				if (tempBall.frameCount > tempBall.frameDelay){
				
					tempBall.animationIndex++;
					if (tempBall.animationIndex > asteroidFrames-1) {
						tempBall.animationIndex = 0;
					}
					tempBall.frameCount=0;
					//added in part 4
					tempBall.bitmapData=aBallAnimation[tempBall.animationIndex];
				}
			}
			
		}		

		
		private function drawMissiles():void {
			var missileLen:int=aMissile.length-1;
		
			for each (var tempMissile:Object in aMissile) {
			
				
				missilePoint.x=tempMissile.x;
				missilePoint.y=tempMissile.y;
				
				// OIM
				var tempMissileBitmap:BitmapData = new BitmapData(missileTileSize,missileTileSize,true,0x00000000);
				//var mtx_transformer:MatrixTransformer = new MatrixTransformer();
				var mtx:Matrix = new Matrix();
				//MatrixTransformer.setRotation(mtx, tempMissile.rot);
				MatrixTransformer.rotateAroundInternalPoint(mtx, missileTileSize/2,  missileTileSize/2, tempMissile.rot);
				tempMissileBitmap.draw(aMissileAnimation[tempMissile.animationIndex], mtx);
				
				canvasBD.copyPixels(tempMissileBitmap, missileRect, missilePoint);
				
//				canvasBD.copyPixels(aMissileAnimation[tempMissile.animationIndex],
//						  missileRect, missilePoint);
				
				tempMissile.animationIndex++;
				if (tempMissile.animationIndex > missileArrayLength-1) {
					tempMissile.animationIndex = 0;
				}
				
				//added in part 4
				tempMissile.bitmapData = tempMissileBitmap;
				
				
			}
			
		}
		
		private function drawParts():void {
			
			activeLen=aActiveParticle.length-1;
			
			for (partCtr=activeLen;partCtr>=0;partCtr--) {
				removePart=false;
				tempPart=aActiveParticle[partCtr];
				tempPart.x+=tempPart.dx*tempPart.speed;
				tempPart.y+=tempPart.dy*tempPart.speed;
				
				if ((tempPart.x > stage.width) || (tempPart.x < 0)) {
					removePart=true;
				}
				
				if ((tempPart.y > stage.height) || (tempPart.y < 0)){
					removePart=true;
				}
				
				tempPart.lifeCount++;
				if (tempPart.lifeCount > tempPart.life) {
					
				}
			
				if (removePart) {
					aFarmParticle.push(tempPart);
					aActiveParticle.splice(partCtr,1);
					
				}else{
					//trace("tempRock.animationIndex=" + tempRock.animationIndex);
					//trace("aAsteroidAnimation[tempRock.animationIndex]=" + aAsteroidAnimation[tempRock.animationIndex].width);
					partPoint.x=tempPart.x;
					partPoint.y=tempPart.y;
					
					canvasBD.copyPixels(tempPart.bitmapData,partRect, partPoint);
				}
				
			}
			
		}
		
		public function getScore():int {
			return playerObject.score;
		}
		
		public function setScore(scr:int) {
			if (playerObject) {
				playerObject.score = scr;
			}
		}
		
		private function drawStats() {
			// Font console
			var len:int = (""+playerObject.score).length;
			var str0:String = ((""+level).length == 1) ? "0" : "";
			var str1:String = ((""+playerObject.lives).length == 1) ? "0" : "";;
			var str2:String = "";
			for (var i:int=0; i<5-len; i++) str2 += "0";
			textBD = new BitmapData(stage.stageWidth, 50, true, 0x55000000);
			dText.draw(textBD, "< Level : "+str0+level+" >  < Lives : "+str1+playerObject.lives+" >  < Score : "+str2+playerObject.score+" >", 3, 7);			

			canvasBD.copyPixels(textBD, statsRect, statsPoint);
		}
		
		private function drawPopupScore():void {
			if (popupObject.alpha > 0.0) {
				var str:String = String(playerObject.instantScore);
				var a_textBD:BitmapData = new BitmapData(str.length*9, 16, true, 0x00000000);
				dText.draw(a_textBD, str, 0, 0);
				a_textBD.applyFilter(a_textBD, a_textBD.rect, new Point(0,0), new BlurFilter(popupObject.blur, popupObject.blur));
				
				var ct:ColorTransform = new ColorTransform();
				ct.alphaMultiplier = popupObject.alpha;
				a_textBD.colorTransform(a_textBD.rect, ct);

				canvasBD.copyPixels(a_textBD, a_textBD.rect, popupObject.point);
				
				popupObject.blur += 0.05;
				popupObject.alpha -= 0.01;
				popupObject.point.y -= 1.0;
			}
		}
		
		private function drawFireBar():void {
			var denom:int = MAX_FIRE_DELAY - levelMissileFireDelay;
			if (denom != 0) {
				firePercents = Math.round(100*(1-(currentMissileFireDelay-levelMissileFireDelay)/denom));
			} else {
				firePercents = 100;
			}
			canvasBD.copyPixels(fireBarBgBD, fireBarBgBD.rect, new Point(9, 381));
			canvasBD.copyPixels(fireBarBD, new Rectangle(0, 0, firePercents, fireBarBD.height), new Point(10, 382));
		}
		
		public function resetStats() {
			level = 1;
			playerObject.lives = LIVES;
			playerObject.score = 0;
		}
		
		public function resetObjects(reset_player:Boolean = true) {
			// Clear Rocks
			aRock = new Array();
			levelRocksCreated = false;
			// Clear Rocks
			aBall = new Array();
			levelBallsCreated = false;
			// Clear Asteroids
			aMissile = new Array();
			// Clear Missiles
			aActiveParticle = new Array();
			// Reset Player
			if (reset_player) {
				resetPlayer();
			}

		}
		
		public function resetPlayer():void {
			playerObject.arrayIndex=0;
			playerObject.x=180;
			playerObject.y=180;
			playerObject.dx=0;
			playerObject.dy=0;
			playerObject.movex=0;
			playerObject.movey=0;
		}
		
		public function getFontBD():BitmapData {
			return fontBD;
		}
		
		public function getPlayerObj():Object {
			return playerObject;
		}
		
		public function getStateMachine():StateMachine {
			return mainSM;
		}
		
		public function playDeadStateSound() {
			sndDeadStateChannel = sndDeadState.play(0, 1, new SoundTransform(0.1));
		}
		
		public function playGameOverSound() {
			sndGameOverChannel = sndGameOver.play();
		}
		
		public function stopGameOverSound() {
			if (sndGameOverChannel) {
				sndGameOverChannel.stop();
			}
		}
		
		// Score Loop
		public function playScoreSound() {
			sndScoreChannel = sndScore.play();
			sndScoreChannel.addEventListener(Event.SOUND_COMPLETE, sndScoreCompleteHandler); 
		}
		
		private function sndScoreCompleteHandler(e:Event) {
			playScoreSound();
		}
		
		public function stopScoreSound() {
			sndScoreChannel.stop();
		}
		
		// Wind Loop
		private function playBackgroundSound() {
			sndBackgroundChannel = sndBackground.play();
			sndBackgroundChannel.addEventListener(Event.SOUND_COMPLETE, sndBackgroundCompleteHandler); 
		}
		
		private function sndBackgroundCompleteHandler(e:Event) {
			playBackgroundSound();
		}
		
		public function setLevel(l:int) {
			level = l;
		}
		
		public function setGlobalVol(vol:Number) {
			//level = l;
			SoundMixer.soundTransform = new SoundTransform(vol);
			globalVol = vol;
		}
		
		public function getLevel():int {
			return level;
		}
		
		public function getGlobalVol():Number {
			return globalVol;
		}
		
		public function getFrameRate():int {
			return FRAME_RATE;
		}
		
		
		
		/////////////////////////////////////////////////////////////////
		/////////////////////////////////////////////////////////////////
		
		private function runGame(e:TimerEvent) {
			mainSM.Update(FRAME_RATE);
			e.updateAfterEvent();
		}
		
		public function gameLoop(gameIsRunning:Boolean = true) {
			//trace("running : "+getTimer());
			if (gameIsRunning) {
			/////// PART 5 - OPTIMIZATION
			/////////////////////////////////////////////////////////////////
				// get loop duration and calculate excess
				_beforeTime = getTimer();
				_overSleepTime = (_beforeTime - _afterTime) - _sleepTime;
			/////////////////////////////////////////////////////////////////
				
				var _beforeCalculating:Number = getTimer();
					checkKeys();
					updatePlayer();
					updateRocks();
					updateBalls();
					updateMissiles();
					checkCollisions();
				var _afterCalculating:Number = getTimer();
				timePerf.UpdatePerfByType("CALC", _afterCalculating-_beforeCalculating);
				
				var _beforeDrawing:Number = getTimer();
					canvasBD.lock();
						drawBackground();
						//drawPlayer();
						playerObject.SM.Update(FRAME_RATE);
						drawBalls();
						drawRocks();
						drawMissiles();
						drawParts();
						drawPopupScore();
						drawStats();
						drawFireBar();
					canvasBD.unlock();
				var _afterDrawing:Number = getTimer();
				timePerf.UpdatePerfByType("DRAW", _afterDrawing-_beforeDrawing);
				
	//			frameTimer.countFrames();
	//			frameTimer.render();
				frameRate.AddAFrame();
				if (showRasters) {
					frameRateRenderer.render();
				}
				
			/////// PART 5 - OPTIMIZATION
			/////////////////////////////////////////////////////////////////
				_afterTime = getTimer();
				_timeDiff = _afterTime - _beforeTime;
				//trace("_timeDiff = "+_timeDiff);
				_sleepTime = (_period - _timeDiff) - _overSleepTime;        
				if (_sleepTime <= 0) {
					_excess -= _sleepTime
					_sleepTime = 2;
				}
				
				gameTimer.reset();
				gameTimer.delay = _sleepTime;
				gameTimer.start();
			
				// Drop Frames if necessary !!
				while (_excess > _period) {
					_beforeCalculating = getTimer();
						checkKeys();
						updatePlayer();
						updateRocks();
						updateBalls();
						updateMissiles();
						checkCollisions();
						_excess -= _period;
					_afterCalculating = getTimer();
					timePerf.UpdatePerfByType("CALC", _afterCalculating-_beforeCalculating);
				}
			/////////////////////////////////////////////////////////////////
			
				//if (aRock.length ==0 && aActiveParticle.length==0) stopRunningGame();
				// Next Level
				if (aRock.length == 0 && aActiveParticle.length == 0) {
					level++;
					playerObject.lives++;
					
					var next_fire_delay:Number = MAX_FIRE_DELAY - STEP_LEVEL_FIRE_DELAY*level;
					if (next_fire_delay > MIN_FIRE_DELAY) {
						levelMissileFireDelay = next_fire_delay;
					} else {
						levelMissileFireDelay = MIN_FIRE_DELAY;
					}
					currentMissileFireDelay = levelMissileFireDelay;
					resetObjects(false);
				}
				
			/////// PART 5 - OPTIMIZATION
			/////////////////////////////////////////////////////////////////
				//e.updateAfterEvent();
			/////////////////////////////////////////////////////////////////
			
				var theTotalTime:int = getTimer() - _beforeTime;
			
				timePerf.PerformPerfs(theTotalTime);
				agtp.drawTimePerfs();
				//timePerf.TracePerfs();
				timePerf.ReinitPerfs();
			} else {
				gameTimer.reset();
				gameTimer.delay = FRAME_RATE;
				gameTimer.start();
			}
		}	
		
		public function stopRunningGame():void {
			stage.removeEventListener(KeyboardEvent.KEY_DOWN,keyDownListener);
			stage.removeEventListener(KeyboardEvent.KEY_UP,keyUpListener);
			gameTimer.removeEventListener(TimerEvent.TIMER, runGame);
			removeChild(canvasBitmap);
			removeChild(ag);
			removeChild(agtp);
			//startBoxOn();
		}
		
		public function Main() {
			trace("Main Init...");
			createObjects();
			createRotationArray();
			createShipAnimation();
			//startBox=new StartBox(this);
		}
	
//		private function startBoxOn():void{
//			startBox.startit();
//		}
		
	}
}
	
	
	