var msgcount = 0;

var objs = Array();
var lastx = Array(-10,0,10,20);

var paused = true;
var running = false;
var drift = 0;

var shake = 0;
var shakeflag = false;
var fuel = 100;
var fuelcount = 10;
var shield = 100;
var wide = false;
var pow = false;
var widecount = 0;
var powcount = 0;
var points=0;
var hiscore=0;
var hieasy=0;
var hinormal=0;
var hihard=0;
var hilast="";
var difflevel=0;
var shipcount = 90;
var level=1;

var sprite_fuel;
var sprite_sheild;
var sprite_message;
var sprite_score;
var sprite_hiscore;
var sprite_pause;
var sprite_music;
var sprite_left;
var sprite_right;
var sprite_site;

var scorecanvas;
var scoregc;
var tex_score;
var mat_score;

var hiscorecanvas;
var hiscoregc;
var tex_hiscore;
var mat_hiscore;

function init_app()
{
	var c = 0;
	for (var i=0;i<10; i++) // init asteroids //
	{ for (var j=0;j<4; j++) { add_asteroid(); objs[c].z+=(10*i); c++; } }
	// init ship //
	add_ship();
	// init a few projectiles //
	for (var i=0;i<20; i++) { find_empty_proj().state=1; }

	// load high scores //
	var t = getCookie("easy");
	if (t=="") { setCookie("easy","0"); } else { hieasy = parseInt(t); } 
	var t = getCookie("normal");
	if (t=="") { setCookie("normal","0"); } else { hinormal = parseInt(t); } 
	var t = getCookie("hard");
	if (t=="") { setCookie("hard","0"); } else { hihard = parseInt(t); } 
	var t = getCookie("last");
	if (t=="0") { setCookie("last","0"); hilast=""; } else { hilast = trim(t); } 

	showScore(0);

	// setup HUD sprites //
	sprite_fuel = new THREE.Sprite(mat_blue);
	sprite_fuel.position.set(ahres*0.25, avres-(avres/40), 0 );
	sprite_fuel.scale.set( ahres/2, avres/20, 0 );
	sceneHUD.add(sprite_fuel);

	sprite_shield = new THREE.Sprite(mat_yellow);
	sprite_shield.position.set(ahres*0.75, avres-(avres/40), 0);
	sprite_shield.scale.set(ahres/2, avres/20, 0 );
	sceneHUD.add(sprite_shield);

	sprite_message = new THREE.Sprite(mat_yellow);
	sprite_message.position.set(ahres/2, 0-avres, 0);
	sprite_message.scale.set(ahres*0.45, (ahres*0.45)*0.25, 0 );
	sceneHUD.add(sprite_message);

	sprite_pause = new THREE.Sprite(mat_pause);
	sprite_pause.position.set((ahres/2)-(ahres*0.125), ahres*0.075, 0);
	sprite_pause.scale.set(ahres*0.1, (ahres*0.1)*0.8, 0 );
	sceneHUD.add(sprite_pause);

	sprite_music = new THREE.Sprite(mat_music);
	sprite_music.position.set((ahres/2)+(ahres*0.175), ahres*0.075, 0);
	sprite_music.scale.set(ahres*0.1, (ahres*0.1)*0.8, 0 );
	sceneHUD.add(sprite_music);

	sprite_left = new THREE.Sprite(mat_left);
	sprite_left.position.set(ahres*0.06, avres/2, 0);
	sprite_left.scale.set(ahres*0.06, (ahres*0.06)*1.25, 0 );
	sceneHUD.add(sprite_left);

	sprite_right = new THREE.Sprite(mat_right);
	sprite_right.position.set(ahres-(ahres*0.06), avres/2, 0);
	sprite_right.scale.set(ahres*0.06, (ahres*0.06)*1.25, 0 );
	sceneHUD.add(sprite_right);

	sprite_site = new THREE.Sprite(mat_site);
	sprite_site.position.set(ahres/2, avres/2, 0);
	sprite_site.scale.set(ahres*0.125, (ahres*0.125)*0.8, 0 );
	sceneHUD.add(sprite_site);

	// dynamic textures for score text //
	scorecanvas = document.createElement("canvas");
	scorecanvas.width=192; scorecanvas.height=32;
	scoregc = scorecanvas.getContext("2d");
	tex_score = new THREE.Texture(scorecanvas); updatescore(0, 256);
	mat_score = new THREE.SpriteMaterial({map: tex_score });

	hiscorecanvas = document.createElement("canvas");
	hiscorecanvas.width=192; hiscorecanvas.height=32;
	hiscoregc = hiscorecanvas.getContext("2d");
	tex_hiscore = new THREE.Texture(hiscorecanvas);
	mat_hiscore = new THREE.SpriteMaterial({map: tex_hiscore });

	sprite_score = new THREE.Sprite(mat_score);
	sprite_score.position.set(ahres*0.875, avres-(avres*0.90), 0);
	sprite_score.scale.set(ahres*0.25, avres*0.08, 0);
	sceneHUD.add(sprite_score);

	sprite_hiscore = new THREE.Sprite(mat_hiscore);
	sprite_hiscore.position.set(ahres*0.125, avres-(avres*0.90), 0);
	sprite_hiscore.scale.set(ahres*0.25, avres*0.08, 0);
	sceneHUD.add(sprite_hiscore);

	showPanel("panel_title");
}

function init_play()
{
	var ship=40;
	running = true;
	drift = 0;
	
	// reset objs & projs
	var row = 0;
	var rowobj = 0;
	for (var i=0;i<40; i++)
	{
		reset_asteroid(objs[i]);
		objs[i].z = -200;
		rowobj++; if (rowobj==4) { rowobj=0; row++; }
		objs[i].z += (row*10);
	}
	objs[ship].state=1; hide(objs[ship]);
	for (var i=41;i<objs.length;i++) { objs[i].state=1; hide(objs[i]); }

	shipcount = 150-((difflevel+1)*10);
	fuel = 100; fuelcount = 10;
	shield = 100;
	shake = 0;
	msgcount = 0;
	points=0;
	updatehiscore(hiscore);
	level = 1;
	background.style.backgroundImage = "url("+background_images[1].src+")";
	showPanel("panel_main");
	paused = false;
	wide = false; widecount = 0; 
	pow = false; powcount = 0;

	if (sound_on)
	{ 
		try { sound.background.currentTime=0; } catch (ex) { }
		play_sound(sound.background);
	}

	setTimeout(start_game, 100);
}
function start_game()
{
	pow = true; fire(0);
	pow = false; powcount = 0;
	timer.onTick = move;
	setTimeout(timer.start, 100);
}

function hide(obj)
{
	if (obj.mesh.length)
	{
		scene.remove(obj.mesh[obj.cmesh]);
	}
	else
	{ 
		scene.remove(obj.mesh);
	}
}
function show(obj)
{
	if (obj.mesh.length)
	{
		scene.add(obj.mesh[obj.cmesh]);
	}
	else
	{ 
		scene.add(obj.mesh);
	}
}

var movenext = movea;
function move()
{
	var t = Date.now();
	movenext();
	if (Date.now()-t<=17) { movenext(); }
	renderframe();
}

function movea()
{
	var score = points;
	var mul = timer.mul;
	var ship, rock, proj;

	fuelcount -=1 * mul;
	if (fuelcount<1) { fuelcount=16-(difflevel); fuel--; }
	shipcount -=1 * mul;
	if (shipcount < 1) { shipcount = 250-(difflevel*50); reset_ship(); }
	if (shake>0) {  shake-= 1 * mul; shield-= 1 * mul; }
	
	// Update Ship //
	ship = objs[40];
	ship.z += ship.movez * mul;
	ship.y += ship.movey * mul;
	ship.x += ship.movex * mul;
	ship.x += drift * mul;

	if (ship.x > 210) { ship.x = -210; } if (ship.x < -210) { ship.x = 210; } // Wrap
	if (ship.z < -50) { ship.state=1; hide(ship); } // Off-Screen
	
	// Rotate Ship
	if (ship.state>0) { ship.mesh.rotation.x-=(Math.PI/8)*mul; } else { ship.mesh.rotation.y-=(Math.PI/32)*mul; }

	// Update Mesh Position
	ship.mesh.position.set(ship.x,ship.y,ship.z);

	if ((ship.x>=30 && ship.movex>0) || (ship.x<=-30 && ship.movex<0)) // AI
	{ 
		ship.movex = 0-ship.movex; // turn around
		if (ship.state==0) { shipfire(); }
	}
	else // randomly fire
	{ if (rnd(1,(((45-(difflevel*2))/mul)|0))==20 && ship.movez>0 && ship.state==0) { shipfire(); } }
	
	// Collision Detection //
	if (ship.z >= 95 && ship.state==0) // Check For Collision With Player
	{ 
		if ((ship.x > -5 && ship.x < 5) && (ship.y > -4 && ship.y < 4) )
		{
			shield -= difflevel * difflevel;
			powcount = 0; pow = false;
			widecount = 0; wide = false;
			shake = 10; // shield will reduce by shake
			showmessage("hit");
		}
		ship.state=1; hide(ship);
	}

	// Update  Asteroids
	for(var i=0; i<40; i++) 
	{
		rock = objs[i];
		// Update Position
		rock.z += rock.movez * mul; rock.x += drift * mul;
		// Wrap Around Scene
		if (rock.x > 210) { rock.x = -210; } if (rock.x < -210) { rock.x = 210; }
		
		// Update Mesh 
		rock.mesh[0].position.set(rock.x,rock.y,rock.z);	
		if (rock.state==0) { rock.mesh[0].rotation.y+=(Math.PI/32)*mul; }
		else { rock.mesh[rock.cmesh].rotation.z+=(Math.PI/64)*mul; }

		// Collision Detection //
		if (rock.z >= 95) // Check For Collision With Player
		{ 
			if ((rock.x+rock.w > -2 && rock.x-rock.w < 2) &&
				(rock.y+rock.h > -3 && rock.y-rock.h < 3) && rock.z<105)
			{
				switch(rock.state)
				{
					case 0:
						shield -= difflevel * difflevel;
						powcount = 0; pow = false;
						widecount = 0; wide = false;
						shake = 10; // shield will reduce by shake
						showmessage("hit");
						break;
					case -2:
						play_sound(sound.beepup);
						fuel += (11-level);
						showmessage("fuel");
						if (fuel>100) { shield+=(6-level); fuel=(101-level); showmessage("shield"); points+=100;}
						if (shield>100) { shield = 100; }
						points += 20;
						break;
					case -3:
						play_sound(sound.beepup);
						widecount+=10; wide = true;
						if (widecount>15) { widecount = 15; }
						showmessage("wide");
						points+=30;
						break;
					case -4:
						play_sound(sound.beepup);
						powcount+=3; pow = true;
						if (powcount > 5) { powcount=5; }
						showmessage("pow");
						points+=50;
						break;
				}
			}
			reset_asteroid(rock); // went off screen
		}
		if (rock.state>0) { update_asteroid_state(rock); }
	}
	movenext = moveb;
}

function moveb()
{
	var score = points;
	var mul = timer.mul;
	var ship, rock, proj;

	// Update Projectiles //
	for (var i=41;i<objs.length;i++)
	{
		proj = objs[i];
		if (proj.state==0)
		{ 
			proj.mesh.rotation.z-=(Math.PI/16)*mul;

			// Update Position
			proj.z += proj.movez * mul; proj.x += drift * mul;
			// Wrap Around Scene
			if (proj.x > 210) { proj.x = -210; } if (proj.x < -210) { proj.x = 210; }
			// Update Mesh 
			proj.mesh.position.set(proj.x,proj.y,proj.z);	

			// Collision Detection //
			if (proj.z < -100) { proj.z.state=1; hide(proj); } // Out of bounds
			if (proj.z >= 95 && proj.movez>0) // Check For Collision With Player
			{ 
				if ((proj.x > -4 && proj.x < 4) && (proj.y > -4 && proj.y < 4) )
				{
					shield -= difflevel * difflevel;
					powcount = 0; pow = false;
					widecount = 0; wide = false;
					shake = 10; // shield will reduce by shake
					showmessage("hit");
				}
				proj.state=1;
				hide(proj);
			}
			
			// Check for Collision with Asteroids / ship //
			var x1 = proj.x - 2;  var x2 = proj.x + 2;
			var y1 = proj.y - 2;  var y2 = proj.y + 2;
			var z1 = proj.z - 2;  var z2 = proj.z + 2;

			for (var j=0; j<41; j++)
			{
				rock = objs[j];
				if (rock.state==0)
				{
					var px1 = rock.x - 4;  var px2 = rock.x + 4;
					var py1 = rock.y - 4;  var py2 = rock.y + 4;
					var pz1 = rock.z - 4;  var pz2 = rock.z + 4;
					if ( (!(py1>y2 || py2<y1)) && (!(px1>x2 || px2<x1)) && (!(pz1>z2 || pz2<z1)) )
					{
						// obj hit //
						if (j<40)
						{ 
							rock.state=1;
							play_sound(sound.explosion);
							if (proj.movez<0) { points+=10; } // our proj?
							if (!proj.pow) { proj.state=1; hide(proj); } // remove proj
						}
						else // ship hit //
						{
							if (proj.movez<0) // ship hit by us
							{ 
								play_sound(sound.explosion);
								if (rock.z<70) { shipfire(); }
								rock.state = 1;
								rock.movez = -2;
								rock.movey = 1;
								proj.state=1; hide(proj);
							}
						}
						j=62; // we hit something, just get out of the loop
					}
				}
			} // end obj/proj collision checks
		}
	} // end projectile update

	updatescore(points, score);
	sprite_fuel.scale.x = (ahres/2) * (fuel/100) * (fuel>0);
	sprite_shield.scale.x = (ahres/2) * (shield/100) * (shield>0);
	
	movenext = movea;
}

function update_asteroid_state(obj)
{
	// Animate Asteroids / Rings
	if (obj.state==1) // Asteroid Recently Hit //
	{
		hide(obj);
		obj.cmesh = 1;
		show(obj);
	}

	if (obj.state < 3) // Animate Explosion
	{
		obj.state += 0.5 * timer.mul;
		obj.mesh[obj.cmesh].rotation.x = rnd(-6,6)*(Math.PI/6);
		obj.mesh[obj.cmesh].rotation.y = rnd(-6,6)*(Math.PI/6);
		obj.mesh[obj.cmesh].rotation.z = rnd(-6,6)*(Math.PI/6);
	}
	else  // Animation is Over, create powerup? //
	{
		hide(obj);
		// create new item object //
		var item = rnd(1,40);
		if (item>(13-difflevel))
		{
			obj.state = -1; // Give them nothing //
		}
		else // Make a Ring
		{
			obj.w = 10;
			obj.h = 10;

			if (item>3)
			{
				obj.state = -2; //fuel
				obj.mesh[2].material = mat_ring_blue;
				obj.cmesh = 2;
				show(obj);
			}

			if (item>=2 && item<=3)
			{
				obj.state = -3; //wide
				obj.mesh[2].material = mat_ring_green;
				obj.cmesh = 2;
				show(obj);

			}
			if (item==1)
			{
				obj.state = -4; //pow
				obj.mesh[2].material = mat_ring_yellow;
				obj.cmesh = 2;
				show(obj);
			}
		}
	}
}

function add_asteroid()
{
	var obj = {};
	obj.z = -50;
	obj.mesh = [];
	obj.mesh[0] = mesh_asteroid(mat_rock[rnd(0,2)]);
	obj.mesh[1] = mesh_exp(mat_exp);
	obj.mesh[2] = mesh_ring(mat_ring_blue);
	obj.cmesh = 0;
	obj.mesh[1].position = obj.mesh[2].position = obj.mesh[0].position;
	reset_asteroid(obj);
	obj.mesh[0].rotation.z += Math.PI/rnd(4, 16);
	obj.mesh[0].rotation.x += Math.PI/rnd(4, 16);
	objs.push(obj);
}

function reset_asteroid(obj)
{
	obj.cmesh = 2; hide(obj);
	obj.cmesh = 1; hide(obj);
	obj.cmesh = 0; hide(obj);
	var t = (rnd(0,40) * 10)-200;
	while (t==lastx[0] || t==lastx[1] || t==lastx[2] || t==lastx[3] ) { t = (rnd(0,40) * 10)-200; }
	lastx[0] = lastx[1]; lastx[1] = lastx[2]; lastx[2] = lastx[3]; lastx[3] = t;
	obj.x = t;
	if (obj.z>=95) { obj.z-=145; } else { obj.z = -100; }
	obj.y = rnd(-3,3);
	obj.w = 5;
	obj.h = 5;
	obj.state = 0;
	obj.movez = 1+(difflevel*0.25);
	p = rnd(0,30);
	if (p>27) { obj.y -= 20; }
	if (p<3) { obj.y += 20; }
	obj.mesh[0].position.set(obj.x, obj.y, obj.z);
	show(obj);
} 

function find_empty_proj()
{
	var found = false; // find empty proj //
	var i = 41; // skip over asteroids, ship //
	while (!found && i<objs.length)
	{ if (objs[i].state!=0) { found=true; } else { i++; } }
	if (!found) // create one!
	{ 
		i=objs.length; objs[i] = new Object();
		objs[i].mesh = mesh_proj(mat_fire_blue);
		objs[i].state=0;
		objs[i].x=0;
		objs[i].y=0;
		objs[i].z=0;
		objs[i].mesh.position.z = 200;
	}
	return objs[i];
}

function fire2() { fire(0); }
function fire(offset)
{
	if (running && !paused)
	{
		//updatehiscore(1000/(60*timer.mul));
		play_sound(sound.laser2);
		if (wide && offset==0) { fire(-10); fire(12); }
	
		var proj = find_empty_proj();

		proj.state = 0;
		proj.pow = false;
		proj.x = 0 + offset;
		proj.y = 0;
		proj.z = 95;
		proj.w = 4;
		proj.h = 4;
		proj.movez = -2;
		
		proj.mesh.material = mat_fire_blue;
		proj.mesh.rotation.y = 0;

		if (wide && !pow) { proj.mesh.material = mat_fire_green; }
		if (pow) { proj.pow = true; proj.mesh.material = mat_fire_yellow; }

		show(proj);
		
		if (offset==0)
		{
			if (pow) { powcount--; if (powcount < 1) { powcount = 0; pow = false; }}
			if (wide) { widecount--; if (widecount < 1) { widecount = 0; wide = false; }}
		}
	}
}

function add_ship()
{
	objs[40] = { mesh: mesh_ship() };
	reset_ship();
	hide(objs[40]);
}

function reset_ship()
{
	var ship = objs[40];
	hide(ship);
	ship.pow = true;
	ship.x = -30;
	ship.y = 0;
	ship.z = -50;
	ship.w = 5;
	ship.h = 5;
	ship.state = 0;
	ship.movez = 1;
	ship.movey = 0;
	ship.movex = 1.5;
	ship.mesh.rotation.x = 0;
	show(ship);
}

function shipfire()
{
	var ship = 40;
	var proj = find_empty_proj();

	play_sound(sound.laser);
	
	proj.pow = true;
	proj.x = objs[ship].x;
	proj.y = 0;
	proj.z = objs[ship].z;
	proj.w = 4;
	proj.h = 4;
	proj.state = 0;
	proj.movez = 1.5+(difflevel*0.25);

	proj.mesh.material = mat_fire_red;
	proj.mesh.rotation.y = Math.PI;

	show(proj);
}

function renderframe()
{
	// Check for End of Game
	if (fuel<1)
	{
		showmessage("nofuel");
		setTimeout(endgame, 2000);
		timer.stop();
	}
	if (shield<1 && shake<=0)
	{
		showmessage("noshield");
		setTimeout(endgame, 2000);
		timer.stop();
	}

	var shakedist = 0;
	if (points>(level*2000))
	{
		level++;
		fuel+=25; if (fuel>100) { fuel=100; }
		showmessage("level");
		if (level<=25)
		{
			background.style.backgroundImage = "url("+background_images[level].src+")";
		}
		else
		{ 
			background.style.backgroundImage ="url("+ background_images[rnd(1,25)].src+")";
		}
	}
	if (shake>0)
	{
		play_sound(sound.explosion);
		shakedist = shake;
		shakeflag = !shakeflag;
		if (shakeflag) { shakedist = 0-shakedist; }
	}
	if (msgcount>0)
	{
		msgcount-= 1 * timer.mul;
		if (msgcount<=5)
		{
			sprite_message.position.y = (avres/2) + ((5-msgcount) * (avres/5));
		}
	}

	camera.position.y = shakedist;
	renderer.clear();
	renderer.render(scene, camera);
	renderer.render(sceneHUD, cameraHUD);
}

// SCORE UPDATE //
function updatescore(newscore, oldscore)
{
	if (newscore!=oldscore)
	{
		scorecanvas.width = scorecanvas.width; // clear
		scoregc.font = "Bold 32px Courier";
		scoregc.fillStyle="#00FF00";
		scoregc.strokeStyle = "#000000";
		scoregc.textAlign = "right";
		scoregc.fillText(newscore, 187, 24);
		scoregc.strokeText(newscore, 187, 24);
		tex_score.needsUpdate = true;
	}
}

function updatehiscore(score)
{
	hiscorecanvas.width = hiscorecanvas.width; // clear
	hiscoregc.font = "Bold 32px Courier";
	hiscoregc.fillStyle="#0000FF";
	hiscoregc.strokeStyle = "#000000";
	hiscoregc.fillText(score, 5, 24);
	hiscoregc.strokeText(score, 5, 24);
	tex_hiscore.needsUpdate = true;
}

// Messages and End Game Sequence //

function showmessage(m)
{
	msgcount = 15;
	if (m=="level") { msgcount = 25; }
	sprite_message.position.y = avres/2;
	sprite_message.material = mat_pop[m];
}

var endmessagelist;
var endmessageindex = 0;

function endgame()
{
	endmessagelist = ["end"];
	if (points>hiscore) // new high score? //
	{
		hiscore = points;
		endmessagelist[endmessagelist.length] = "hiscore";
		switch (difflevel)
		{
			case 0: hieasy = hiscore; setCookie("easy", hiscore); break;
			case 1: hinormal = hiscore; setCookie("normal", hiscore); break;
			case 2: hihard = hiscore; setCookie("hard", hiscore); break;
		}
	}
	switch (difflevel) // last score //
	{
		case 0: hilast = points+" (Easy)"; break;
		case 1: hilast = points+" (Normal)"; break;
		case 2: hilast = points+" (Hard)"; break;
	}
	setCookie("last", hilast);

	msgcount = 15;
	endmessageindex = endmessagelist.length-1;
	timer.onTick = endmessage;
	timer.start();
}

function endmessage()
{
	var t=1;
	renderer.clear();
	renderer.render(scene, camera);
	renderer.render(sceneHUD, cameraHUD);
	if (msgcount>0)
	{
		msgcount -= timer.mul;
		t = sound.background.volume - ( ((1/(endmessagelist.length+1))/15) * timer.mul );
		sound.background.volume = t * (t>=0 && t<=1);
		sprite_message.position.y += (avres/15)*timer.mul;
	}
	else
	{
		timer.stop();
		if (endmessageindex >= 0)
		{
			showmessage(endmessagelist[endmessageindex]);
			msgcount = 15;
			renderer.clear();
			renderer.render(scene, camera);
			renderer.render(sceneHUD, cameraHUD);
			setTimeout(timer.start, 2500);
			endmessageindex--;
		}
		else
		{ 
			sound.background.pause();
			sound.background.volume = 1;
			running = false; showPanel("panel_title");
		}
	}
}