if(window.Asteroids == null)
	window.Asteroids= {};

///////////////////////////////////////////////////////////////////////////////
// Asteroids.Scene

Asteroids.Scene= function() 
{
	this.beatIndex= 0;
	this.isPaused= false;
	this.renderRepeat= 0;
}

Asteroids.Scene.prototype.handleLoad= function(control, userContext, rootElement)
{
	this.control= control;
	control.focus();
	this.rootElement= rootElement;
	rootElement.width= EDGE_WIDTH;
	rootElement.height= EDGE_HEIGHT;
	rootElement.background= BACKGROUND_COLOR;
	rootElement.addEventListener("LostFocus", $delegate(this, this.handleLostFocus));
	this.gameOverCanvas= rootElement.findName("gameOverCanvas");
	this.alienFireSound= rootElement.findName("alienFireSound");
	this.fireSound= rootElement.findName("fireSound");
	this.hearbeatClock= this.getElement("hearbeatClock");
	this.hearbeatClock.addEventListener("Completed", $delegate(this, this.playNextBeat));
	this.heartbeatSounds= [ rootElement.findName("heartbeatSound1"), rootElement.findName("heartbeatSound2") ];
	this.downloadCount= 5;
	
	// Get the XAML for the bullets, particle clouds, digits, rocks, and ship.
	this.download(control, "Bullet.xaml", $delegate(this, this.handleDownloadBulletCompleted));
	this.download(control, "Cloud.xaml", $delegate(this, this.handleDownloadCloudCompleted));
	this.download(control, "Digits.xaml", $delegate(this, this.handleDownloadDigitsCompleted));
	this.download(control, "Rock.xaml", $delegate(this, this.handleDownloadRockCompleted));
	this.download(control, "Ship.xaml", $delegate(this, this.handleDownloadShipCompleted));
}

Asteroids.Scene.prototype.handleAllDownloadsCompleted= function()
{
	this.keyDownEventToken= this.rootElement.addEventListener("KeyDown", $delegate(this, this.handleAttractKeyDown));
	this.keyUpEventToken= this.rootElement.addEventListener("KeyUp", $delegate(this, this.handleAttractKeyUp));
	this.engine= new Asteroids.Engine(this);
	this.engine.attract();
}

Asteroids.Scene.prototype.handleAttractKeyDown= function(sender, eventArgs)
{
	var key= eventArgs.key;
	if(key >= 21 && key <= 29)
		START_LIVES= key - 20;
}

Asteroids.Scene.prototype.handleAttractKeyUp= function(sender, eventArgs)
{
	switch(eventArgs.key)
	{
	case 9: // SP
		$get("attractInstructionsElement").style.display= "none";
		$get("gameInstructionsElement").style.display= "";
		this.rootElement.cursor= "None";
		this.rootElement.removeEventListener("KeyDown", this.keyDownEventToken);
		this.rootElement.removeEventListener("KeyUp", this.keyUpEventToken);
		this.keyDownEventToken= this.rootElement.addEventListener("KeyDown", $delegate(this, this.handleGameKeyDown));
		this.keyUpEventToken= this.rootElement.addEventListener("KeyUp", $delegate(this, this.handleGameKeyUp));
		this.gameOverCanvas.visibility= "Collapsed";
		this.engine.startGame();
		break;
	}
}

Asteroids.Scene.prototype.handleDownloadBulletCompleted= function(sender)
{
	// Add all bullets to the scene.
	var content= sender.getHost().content;
	var responseText= sender.ResponseText;
	for(var i= 0; i < MAX_BULLETS; ++i)
	{
		var s= responseText.replace(/#/g, i);
		var bullet= content.createFromXaml(s);
		this.rootElement.children.add(bullet);
	}
	if(--this.downloadCount == 0)
		this.handleAllDownloadsCompleted();
}

Asteroids.Scene.prototype.handleDownloadCloudCompleted= function(sender)
{
	// Add all particle clouds to the scene.
	var content= this.control.content;
	var cloudParts= sender.ResponseText.split("<!-- -->");
	Debug.assert(cloudParts.length == 5);
	for(var i= 0; i < MAX_PARTICLE_CLOUDS; ++i)
	{
		var particleXaml= "", storyboardXaml= "", angle= 0;
		var n= MIN_CLOUD_PARTICLES + Math.floor(CLOUD_PARTICLE_RANGE * Math.random());
		for(var j= 0; j < n; ++j)
		{
			particleXaml += cloudParts[1].replace(/#/g, i + "_" + j).replace(/@/g, angle.toString().substr(0, 7));
			var particleDuration= MIN_PARTICLE_DURATION + PARTICLE_DURATION_RANGE * Math.random();
			storyboardXaml += cloudParts[3].replace(/#/g, i + "_" + j)
				.replace(/@/g, particleDuration.toString().substr(0, 7))
				.replace("^", MIN_PARTICLE_EXTENT + Math.floor(PARTICLE_EXTENT_RANGE * Math.random()));
			angle += (360 * Math.random() + 180) / n;
		}
		var cloudXaml= cloudParts[0].replace(/#/g, i) + particleXaml
			+ cloudParts[2].replace(/#/g, i) + storyboardXaml + cloudParts[4];
		var cloud= content.createFromXaml(cloudXaml);
		this.rootElement.children.add(cloud);
	}
	if(--this.downloadCount == 0)
		this.handleAllDownloadsCompleted();
}

Asteroids.Scene.prototype.handleDownloadDigitsCompleted= function(sender)
{
	var content= sender.getHost().content;
	var responseText= sender.ResponseText;
	for(var i= 0; i < SCORE_DIGITS; ++i)
	{
		var digitXaml= responseText.replace(/#/g, SCORE_DIGITS - 1 - i);
		var digit= content.createFromXaml(digitXaml);
		this.rootElement.children.add(digit);
		digit["Canvas.Left"]= 60 + i * 16;
		digit["Canvas.Top"]= 30;
	}
	if(--this.downloadCount == 0)
		this.handleAllDownloadsCompleted();
}

Asteroids.Scene.prototype.handleDownloadRockCompleted= function(sender)
{
	var rockPoints= [
		"-25,-50 -2,-36 24,-50 49,-25 24,-13 49,12 24,49 -14,38 -25,49 -50,26 -37,1 -50,-25",
		"-25,-50 0,-25 24,-50 49,-25 37,-2 49,24 12,49 -25,49 -50,24 -50,-25",
		"-27,-50 11,-50 49,-25 49,-13 11,-2 49,24 24,49 11,38 -27,49 -50,12 -50,-25 -14,-25",
		"-15,-50 24,-50 49,-11 49,11 24,49 0,49 0,11 -25,49 -50,11 -25,0 -50,-11"
	];
	
	// Add all possible rocks to the scene.
	var content= sender.getHost().content;
	var responseText= sender.ResponseText;
	for(var i= 0; i < TOTAL_ROCKS; ++i)
	{
		var rockXaml= responseText.replace(/#/g, i);
		rockXaml= rockXaml.replace("$", rockPoints[i % rockPoints.length]);
		var rock= content.createFromXaml(rockXaml);
		this.rootElement.children.add(rock);
	}
	if(--this.downloadCount == 0)
		this.handleAllDownloadsCompleted();
}

Asteroids.Scene.prototype.handleDownloadShipCompleted= function(sender)
{
	// Add the available ships to the scene.
	var content= sender.getHost().content;
	var responseText= sender.ResponseText;
	for(var i= 0; i < 9; ++i)
	{
		var s= responseText.replace(/#/g, i);
		var ship= content.createFromXaml(s);
		s= ship.findName("shipTranslateTransform" + i);
		s.x= 15 * i + 20;
		s.y= 20;
		s= ship.findName("shipTranslateStoryboard" + i).children;
		s.getItem(0).to= 15 * i + 20;
		s.getItem(1).to= 20;
		this.rootElement.children.add(ship);
	}
	// Add one more ship as the player's ship.
	s= responseText.replace(/#/g, "");
	var ship= content.createFromXaml(s);
	this.rootElement.children.add(ship);
	if(--this.downloadCount == 0)
		this.handleAllDownloadsCompleted();
}

Asteroids.Scene.prototype.handleError= function(sender, eventArgs)
{
	debugger;
}

Asteroids.Scene.prototype.handleGameKeyDown= function(sender, eventArgs)
{
	if(this.isPaused && eventArgs.key != 45)
		return;
	switch(eventArgs.key)
	{
	case 9: // SP = Hyperspace
		this.engine.jumpShip();
		break;
	case 33: // D = Left
		this.engine.turnShip(-1);
		break;
	case 35: // F = Right
		this.engine.turnShip(1);
		break;
	case 38: // I = Toggle instructions
		this.toggleInstructionsDisplay();
		break;
	case 39: // J = Thrust
		this.engine.thrustShip(true);
		break;
	case 40: // K = Fire
		this.engine.shoot();
		break;
	case 45: // P = Pause
		this.pause(!this.isPaused);
		break;
	}
}

Asteroids.Scene.prototype.handleGameKeyUp= function(sender, eventArgs)
{
	switch(eventArgs.key)
	{
	case 30: // A = small alien
		this.engine.showAlien(true);
		break;
	case 33: // D = Left
	case 35: // F = Right
		this.engine.turnShip(0);
		break;
	case 39: // J = Thrust
		this.engine.thrustShip(false);
		break;
	case 48: // S = large alien
		this.engine.showAlien(false);
		break;
	}
}

Asteroids.Scene.prototype.handleLostFocus= function(sender)
{
	// If I'm in the middle of a game, pause it.
	if(this.rootElement.cursor == "None")
		this.pause(true);
}

///////////////////////////////////////////////////////////////////////////////
// public methods

Asteroids.Scene.prototype.download= function(control, filename, handler)
{
	var downloader= control.createObject("downloader");
	downloader.addEventListener("completed", handler);
	downloader.open("GET", filename);
	downloader.send();
}

Asteroids.Scene.prototype.endGame= function()
{
	this.rootElement.cursor= "Default";
	this.rootElement.removeEventListener("KeyDown", this.keyDownEventToken);
	this.rootElement.removeEventListener("KeyUp", this.keyUpEventToken);
	this.keyDownEventToken= this.rootElement.addEventListener("KeyDown", $delegate(this, this.handleAttractKeyDown));
	this.keyUpEventToken= this.rootElement.addEventListener("KeyUp", $delegate(this, this.handleAttractKeyUp));
	this.gameOverCanvas.visibility= "Visible";
	this.stopHeartbeat();
}

Asteroids.Scene.prototype.getElement= function(name)
{
	return this.rootElement.findName(name);
}

Asteroids.Scene.prototype.pause= function(pausing)
{
	if(this.isPaused != pausing)
	{
		if(this.isPaused= pausing)
		{
			this.heartbeatSounds[0].volume= this.heartbeatSounds[1].volume= 0;
			this.engine.pause();
			this.rootElement.cursor= "Default";
		}
		else
		{
			this.rootElement.cursor= "None";
			this.heartbeatSounds[0].volume= this.heartbeatSounds[1].volume= 1;
			this.engine.resume();
		}
	}
}

Asteroids.Scene.prototype.playNextBeat= function()
{
	this.restartSound(this.heartbeatSounds[this.beatIndex]);
	this.beatIndex ^= 1;
	this.hearbeatClock.begin();
}

Asteroids.Scene.prototype.playShotSound= function(isForAlien)
{
	this.restartSound(isForAlien ? this.alienFireSound : this.fireSound);
}

Asteroids.Scene.prototype.restartSound= function(sound)
{
	sound.source= sound.source;
	sound.autoPlay= true;
}

Asteroids.Scene.prototype.startHeartbeat= function()
{
	this.beatIndex= 0;
	this.hearbeatClock.duration.seconds= 1;
	this.playNextBeat();
}

Asteroids.Scene.prototype.stopHeartbeat= function()
{
	this.hearbeatClock.stop();
}

Asteroids.Scene.prototype.toggleInstructionsDisplay= function()
{
	var gameInstructionsElement= $get("gameInstructionsElement");
	gameInstructionsElement.style.display= gameInstructionsElement.style.display == "" ? "none" : "";
}

Asteroids.Scene.prototype.updateProgress= function(progress)
{
	this.hearbeatClock.duration.seconds= Math.max(.2, 1 - progress);
}

Asteroids.Scene.prototype.updateScore= function(score)
{
	score %= MAX_SCORE;
	for(var i= 0; i < SCORE_DIGITS; ++i)
	{
		var digit= this.getElement("digits" + i);
		var children= digit.children;
		var digitValue= score % 10;
		if(score > 0 || i < 2)
		{
			for(var j= 0; j < 10; ++j)
				children.getItem(j).visibility= digitValue == j ? "Visible" : "Collapsed";
			digit.visibility= "Visible";
		}
		else
			digit.visibility= "Collapsed";
		score= Math.floor(score / 10);
	}
}

Asteroids.Scene.prototype.updateShipsAvailable= function(count)
{
	for(var i= 0; i < START_LIVES; ++i)
	{
		var ship= this.rootElement.findName("ship" + i);
		ship.visibility= i < count ? "Visible" : "Collapsed";
	}
}

