var ctx;
var gravity = v_(0, 0.4);
var images = [];
var ninja;
var bullets = [];
var asteroids = []
var running = false;
var base = { pos: v_(178, 259) };
var earth = { pos: v_(165, 272), rad: 40 };
var asteroids_r = [30, 34, 37, 41, 46, 50, 53, 60, 80];

var asteroid_speed = null;
var asteroid_spawn_time = null;
var asteroid_respawn = null;
var ammo_need = null;
var ammo_restore = null;
var life_restore = null;
var ammo = null;
var life = null;
var wave = null;
var new_wave = null;
var wave_time = null;

var winds = [v_(0, 0), v_(0.1, 0)];
var wind = 0;
var wave_total_time = 20*60*1;
var game_time = null;

var use_sql = true;

//function create_wave(ammo_cost, ammo_restore, 

function game_menu() {
	stop_game();
	xshow("startmenu");
}

function get_game_time() {
	return Math.floor(game_time/20);
}

function game_again() {
	var name = _("defender-name").value;

	if ((name.length > 0) && (name.length < 15))
	{
		createCookie("defender-name", name);
		update_top_score(name, get_game_time());
		play_game();
	}
	else
		alert("Name should have length from 1 to 15 symbols.");
}

function update_top_score(name, score) {
	if (use_sql) {
		$.post(
			'update_top_scores.php',
			{ name: name, score: score }
		);
	}
}

// Main /////////////////////////////////////////////////////////////////////
function show_best_screen()
{
	_("score-table").style.opacity = "0";
	_("score-loading").style.display = "block";
	xshow("bestscreen");
	get_best();
}

function return_from_best()
{
	xhide("bestscreen");
}

function get_best()
{
	if (use_sql) {
		$.getJSON(
			'top_scores.php',
			{ params: "text" },
			function onAjaxSuccess(obj) { show_best(obj.top_score); }
		);
	} else {
		var toplist = [
			{ name: "A", score: 1 },
			{ name: "B", score: 2 },
			{ name: "C", score: 3 },
			{ name: "D", score: 4 },
			{ name: "E", score: 5 },
			{ name: "F", score: 6 },
			{ name: "G", score: 7 },
			{ name: "H", score: 8 },
			{ name: "I", score: 9 },
			{ name: "J", score: 10 },
		];
		show_best(toplist);
	}
}

function show_best(toplist)
{
	for (var i = 0; i < 10; ++i) {
		$("#score-name-"+(i+1)).text(toplist[i].name);
		$("#score-wave-"+(i+1)).text(toplist[i].score);
	}
	_("score-loading").style.display = "none";
	_("score-table").style.opacity = "1";
}

function xshow(e)
{
	_(e).style.opacity = 0;
	_(e).style.display = "block";
	$("#"+e).animate( { opacity: 1 }, 600 );
}

function xshowhide(e)
{
	_(e).style.opacity = 0;
	_(e).style.display = "block";
	$("#"+e).animate( { opacity: 1 }, 600, function() { setTimeout(function() { xhide(e); }, 2000 ); } );
}

function xhide(e)
{
	$("#"+e).animate( { opacity: 0 }, 600, function() {
		_(e).style.display = "none";
	} );
}

function pre_initialize_game() {
}

function play_game() {
	_("startmenu").style.display = "none";
	_("gameover").style.display = "none";
	_("gamescreen").style.display = "block";
	initialize_game();
	start_game();
}

function game_over() {
	stop_game();
	_("defender-score").innerHTML = get_game_time();
	xshow("gameover");
//	_("gamescreen").style.display = "none";
//	_("gameover").style.display = "block";
}

function do_click(e) {
	if (!running) return;
	if (ammo < ammo_need) return;

	var m = mouse_rel_pos(this, e);
	var c = v_c(base.pos);//v_(160, 300);
	var mv = v_scale(v_nor(v_sub(m, c)), 10);
	add_point(bullets, create_bullet(c, mv, 5));
	ammo -= ammo_need;
}

function create_point(pos, vel, mass, rad) {
	return { pos: pos, vel: vel, rad: rad, mass: mass, inv_mass: 1/mass, force: v_(0, 0) };
}

function create_bullet(pos, vel, mass) {
	return create_point(pos, vel, mass, mass);
}

function create_asteroid(pos, vel, mass) {
	return create_point(pos, vel, mass, mass);
}

function gen_pos(ar) {
	var r = 452.54834;
	var t = xrnd()*3.141593;
//	_("info").innerHTML = t;
	var x = Math.cos(t);
	var y = Math.sin(t);
	if (t < 0.785398) {
	  x = 320+ar; y = 160*(1-y);
	} else if (t > 2.356194) {
	  x = -ar; y = 160*(1-y);
	} else {
	  y = -ar; x = 160+160*x;
	}
	return v_(x, y);
}

function spawn_asteroid() {
	--asteroid_spawn_time;
	if (asteroid_spawn_time == 0)
	{
		var r = asteroids_r[xrand(asteroids_r.length)];
//		var xp = xrnd()*3;
		var apos = gen_pos(r);
		var cpos = v_c(base.pos);//v_add(base.pos, v_((160-apos.x)/2, 0));
		var spd = v_scale(v_nor(v_sub(cpos, apos)), 1+asteroid_speed/r);
		add_point(asteroids, create_asteroid(apos, spd, r));
		asteroid_spawn_time = Math.floor(asteroid_respawn);
	} 
}

function initialize_game() {
//	bullets[bullets.length] = create_bullet(v_(280, 280), v_(-5, -5), 10);
	_("defender-name").value = readCookie("defender-name");
	wave = 0; new_wave = 1; wave_time = 0;
	game_time = 0;
	xrnd_reset();
	asteroid_speed = 40;
	asteroid_spawn_time = 1;
	asteroid_respawn = 60;
	ammo_need = 4;
	ammo_restore = 0.1;
	life_restore = 0.0005;
	ammo = 20;
	life = 20;
	asteroids.length = 0;
	bullets.length = 0;

	paint_game(ctx);
}

function add_point(m, p)
{
	m[m.length] = p;
}

function start_game() {
//	process_game();
	if (running) stop_game();
	running = setInterval(process_game, 50);
}

function stop_game() {
	if (running) clearInterval(running);
	running = false;
}

function process_game() {
	update_game();
	paint_game(ctx);
}

function update_game() {
	++game_time;
	_("game-time").innerHTML = get_game_time();
	++wave_time;
	if (wave_time > wave_total_time) {
		++new_wave;
		wave_time = 0;
	}
	if (new_wave != wave) {
		wave = new_wave;
		asteroid_speed += 5;
//		asteroid_respawn -= 1;
		_("wave-num").innerHTML = wave;
		xshowhide("wave");
	}
	if (ammo < 20) ammo += ammo_restore;
	if (life < 20) life += life_restore;
	spawn_asteroid();
	clear_forces(bullets, false);
	clear_forces(asteroids, true);
	apply_force(bullets, winds[wind]);
	apply_force(asteroids, v_(0, 0.01));
	integrate(bullets, 0);
	integrate(asteroids, 0);
	for (var a = 0; a < asteroids.length; ++a)
		collide_earth(asteroids[a]);
	for (var a = 0; a < asteroids.length; ++a)
		for (var b = 0; b < bullets.length; ++b)
		{
			if (!a.dead) collide(asteroids[a], bullets[b]);
		}
	move(bullets);
	move(asteroids);
//	_("info").innerHTML = bullets.length + "," + asteroids.length;
	_("ammo").style.width = Math.floor(ammo)/20*80 + "px";
	_("life").style.width = Math.floor(life)/20*80 + "px";
}

function collide_earth(a)
{
	var dst = v_dist(v_add(a.pos, a.vel), earth.pos);
	if (dst > (a.rad + earth.rad)) return;
	life -= a.rad/10;
	if (Math.floor(life) <= 0) {
		life = 0;
		game_over();
	}
	a.dead = true;
}

function collide(a, b)
{
	var dst = v_dist(v_add(a.pos, a.vel), v_add(b.pos, b.vel));
	if (dst > (a.rad + b.rad)) return;

	// First, find the normalized vector n from the center of 
	// circle1 to the center of circle2
	var n = v_nor(v_sub(a.pos, b.pos));

	// Find the length of the component of each of the movement
	// vectors along n. 
	// a1 = v1 . n
	// a2 = v2 . n
	var a1 = v_dot(a.vel, n);
	var a2 = v_dot(b.vel, n);

	// Using the optimized version, 
	// optimizedP =  2(a1 - a2)
	//              -----------
	//                m1 + m2
	var optimizedP = (2.0 * (a1 - a2))/(a.mass + b.mass);

	// Calculate v1', the new movement vector of circle1
	// v1' = v1 - optimizedP * m2 * n
	var v1q = v_sub(a.vel, v_scale(n, optimizedP * b.mass));

	// Calculate v1q, the new movement vector of circle1
	// v2q = v2 + optimizedP * m1 * n
	var v2q = v_add(b.vel, v_scale(n, optimizedP * a.mass));

	a.vel = v_c(v1q);
	b.vel = v_c(v2q);
}

function paint_asteroid(ctx) {
	ctx.fillStyle = "#000";
	var CC = [];
	for (var i = 0; i < asteroids_r.length; ++i) CC[i] = "rgb("+((asteroids_r.length-1-i)*6)+", 0, 0)";
//	var CC = ["#000", "#f00", "#0f0", "#00f", "#fff"];
	ctx.strokeStyle = '#800';
	for (var k = asteroids_r.length-1; k >= 0; --k) {
		for (var i = 0; i < asteroids.length; ++i) {
			var p = asteroids[i];
			if (p.rad != asteroids_r[k]) continue;
 
			ctx.fillStyle = CC[k];
			ctx.beginPath();
			ctx.arc(p.pos.x, p.pos.y, p.rad, 0, Math.PI*2, 0);
			ctx.fill();
//			ctx.stroke();
		}
	}

	ctx.fillStyle = "#fff";
	ctx.strokeStyle = '#ff0' ;
	for (var i = 0; i < bullets.length; ++i) {
		ctx.beginPath();
		var p = bullets[i];
		ctx.arc(p.pos.x, p.pos.y, p.rad, 0, Math.PI*2, 0);
		ctx.fill();
//		ctx.stroke();
	}

//		ctx.beginPath();
//		ctx.arc(base.pos.x, base.pos.y, 5, 0, Math.PI*2, 0);
//		ctx.arc(earth.pos.x, earth.pos.y, earth.rad, 0, Math.PI*2, 0);
//		ctx.fill();
}

function paint_game(ctx) {
	ctx.clearRect(0, 0, 320, 320);
	paint_asteroid(ctx);
}

// Verlet ///////////////////////////////////////////////////////////////////

function apply_force(points, force) {
	for (var i = 0; i < points.length; ++i) {
		var p = points[i];
		v_mad_ref(p.force, force, p.mass);
	}
}

function clear_forces(points, is_asteroids) {
	for (var i = 0; i < points.length; ++i) {
		var p = points[i];
		p.force.x = p.force.y = 0.0;
/*		if (is_asteroids)
		{
			var spd = v_nor(v_sub(base.pos, p.pos));
			p.force.y = 4;//v_scale(spd, 0.1);
		}*/
	}
}

function integrate(points, friction) {
	var f = 0;//friction || 0.02;
	for (var i = 0; i < points.length; ++i) {
		var p = points[i];

		p.vel.x += p.force.x*p.inv_mass;
		p.vel.y += p.force.y*p.inv_mass;
	}
}

function move(points) {
	var n = points.length-1;
	for (var i = 0; i < points.length; ++i) {
		var p = points[i];
		p.pos.x += p.vel.x;
		p.pos.y += p.vel.y;
		var kill = p.pos.x < -p.rad || p.pos.y < -p.rad || (p.pos.x-p.rad > 320) || (p.pos.y-p.rad > 320);
		if (p.dead) kill = true;
		if (kill) {
			points[i] = points[n]; --n;
		}
	}
	points.length = n+1;
}

function satisfy(constraints) {
	for (var i = 0; i < constraints.length; ++i) satisfy_rigid_constraint(constraints[i]);
}

function satisfy2(constraints, a, s) {
	for (var i = 0; i < constraints.length; ++i) satisfy_rigid_constraint2(constraints[i], a, s);
}

function satisfy2_inv(constraints, a, s) {
	for (var i = constraints.length-1; i >= 1; --i) satisfy_rigid_constraint2(constraints[i], a, s);
}

function satisfy_inv(constraints) {
	for (var i = constraints.length-1; i >= 0; --i) satisfy_rigid_constraint(constraints[i]);
}

function paint_points(points, ctx, color) {
	ctx.fillStyle = color || '#aaa';
	for (var i = 0; i < points.length; ++i) {
		var p = points[i];
		ctx.beginPath();
		ctx.arc(p.pos.x, p.pos.y, 4, 0, Math.PI*2, 0);
		ctx.fill();
	}
}

function paint_constraints(constraints, ctx, color, w) {
	ctx.strokeStyle = color || '#fff';
	ctx.lineWidth = w || 3;
	for (var j = 0; j < constraints.length; ++j) {
		var c = constraints[j];
		if (!c.visible) continue;
		ctx.beginPath();
		ctx.arc((c.point1.pos.x+c.point2.pos.x)/2, (c.point1.pos.y+c.point2.pos.y)/2, 4, 0, Math.PI*2, 0);
		ctx.moveTo(c.point1.pos.x, c.point1.pos.y);
		ctx.lineTo(c.point2.pos.x, c.point2.pos.y);
		ctx.stroke();
	}
}

// Constraint ///////////////////////////////////////////////////////////////

function create_rigid_constraint(point1, point2, distance, type, stiffness) {
	var c = {};
	c.point1 = point1; c.point2 = point2;
	c.distance = distance || v_dist(point1.pos, point2.pos);
	c.type = type || 0.0;
	c.stiffness = stiffness || 1.0;
	c.a = point2.mass/(point1.mass+point2.mass);
	c.visible = true;
	return c;
}

function satisfy_rigid_constraint(constraint) {
	var delta = v_sub(constraint.point2.pos, constraint.point1.pos);
	var deltalength = v_len(delta);
	if (deltalength < 0.001) return;
	if (constraint.type == 1 && deltalength > constraint.distance ) return;
	if (constraint.type == 2 && deltalength < constraint.distance ) return;
	var diff = (deltalength-constraint.distance)/deltalength*constraint.stiffness;
	v_mad_ref(constraint.point1.pos, delta, diff*constraint.a);
	v_mad_ref(constraint.point2.pos, delta, -diff*(1-constraint.a));
}

function satisfy_rigid_constraint2(constraint, a, stiffness) {
	var delta = v_sub(constraint.point2.pos, constraint.point1.pos);
	var deltalength = v_len(delta);
	if (deltalength < 0.001) return;
	if (constraint.type == 1 && deltalength > constraint.distance ) return;
	if (constraint.type == 2 && deltalength < constraint.distance ) return;
	var diff = (deltalength-constraint.distance)/deltalength*stiffness;
	v_mad_ref(constraint.point1.pos, delta, diff*a);
	v_mad_ref(constraint.point2.pos, delta, -diff*(1-a));
}

////////////////////////////////////////////////////////////////////////////////
// window utils
////////////////////////////////////////////////////////////////////////////////

function mouse_rel_pos(o, ev)
{
	var x = 0, y = 0;
	while ( o != null )
	{
		x += o.offsetLeft;
		y += o.offsetTop;
		o = o.offsetParent;
	}
	return { x: ev.pageX-x, y: ev.pageY-y };
}


function _(id) { return document.getElementById(id); }

////////////////////////////////////////////////////////////////////////////////
// math.js
////////////////////////////////////////////////////////////////////////////////

function rndf(a, b)
{
	return Math.random()*(b-a) + a;
}

function rndi(a, b)
{
	return Math.floor(rndf(a,b));
}

function rand(RandSeed)
{
	var rnge = Math.pow(2, 32);
	RandSeed = ((134775813 * RandSeed + 1) % rnge);
	return [RandSeed, RandSeed/rnge];
}

// vector math

function v_(x, y) { return {x:x, y:y}; }
function v_c(a) { return {x:a.x, y:a.y}; }
function v_add(a, b) { return {x:a.x + b.x, y:a.y + b.y}; }
function v_add_ref(a, b) { a.x += b.x, a.y += b.y; }
function v_sub(a, b) { return {x:a.x - b.x, y:a.y - b.y}; }
function v_scale(a, b) { return {x:a.x * b, y:a.y * b}; }
function v_rshift(a, s) { return {x:a.x >> s, y:a.y >> s}; }
function v_mad(a, b, c) { return {x:a.x + b.x * c, y: a.y + b.y * c}; }
function v_mad_ref(a, b, c) { a.x += b.x * c; a.y += b.y * c; }
function v_dot(a, b) { return a.x * b.x + a.y * b.y; }
function v_len(a) { return Math.sqrt(a.x * a.x + a.y * a.y); }
function v_len2(a) { return a.x * a.x + a.y * a.y; }
function v_nor(a) { var inv_len = 1.0/Math.sqrt(a.x * a.x + a.y * a.y); return {x:a.x * inv_len, y:a.y * inv_len}; }
function v_norm2(a) { return a.x * a.x + a.y * a.y; }
function v_len(a) { return Math.sqrt(a.x * a.x + a.y * a.y); }
function v_crs(a) { return {x:-a.y, y:a.x}; }
function v_crs2(a) { return {x:a.y, y:a.x}; }

function v_dist2(a, b)
{
	var dx = b.x - a.x;
	var dy = b.y - a.y;
	return dx*dx + dy*dy;
}

function v_dist(a, b)
{
	var dx = b.x - a.x;
	var dy = b.y - a.y;
	return Math.sqrt(dx*dx + dy*dy);
}

////////////////////////////////////////////////////////////////////////////////
// cook.js
////////////////////////////////////////////////////////////////////////////////

var brand = "mass-";

function createCookie(name,value,days) {
  var expires = "";
 
  if (days) {}
  else days = 365;

  var date = new Date();
  date.setDate(date.getDate() + days);
  expires = "; expires=" + date.toGMTString();

  document.cookie = brand + name + "=" + value + expires + "; path=/";
}
 
function readCookie(name) {
  var nameEQ = brand + name + "=";
  var ca = document.cookie.split(';');
 
  for(var i = 0; i < ca.length; i++) {
    var c = ca[i];
    while (c.charAt(0) == ' ') c = c.substring(1, c.length);
    if (c.indexOf(nameEQ) == 0) {
      var v = c.substring(nameEQ.length, c.length);
 
      return v;
    }
  }
  
  return "Defender";
}

////////////////////////////////////////////////////////////////////////////////
// screenlayout.js
////////////////////////////////////////////////////////////////////////////////

// As seen on mediatemple account center. Thanks (mt)!

// The following code is courtesy of Joe Hewitt http://www.joehewitt.com

/*$(function() {
  updateLayout();
  window.scrollTo(0, 1);
  setInterval(updateLayout, 400);
});*/

var currentWidth = 0;
var xstopped = false;
    
function updateLayout()
{  
  if (window.innerWidth != currentWidth)
  {
    currentWidth = window.innerWidth;

    var agent = navigator.userAgent.toLowerCase();
    var isIphone = agent.indexOf('iphone') != -1;

    if (isIphone)
    {
      var orient = currentWidth == 320 ? "profile" : (currentWidth > 1000 ? "profile" : "landscape");
      if (orient=="landscape") { if (running) { xstopped = running; } stop_game(); }
      else if (xstopped) { start_game(); }
      document.body.setAttribute("orient", orient);
    } else {
      document.body.setAttribute("orient", "profile");      
    }
    window.scrollTo(0, 1);
  }
}

// end Joe Hewitt code. Thanks Joe!

var xrnd_start_seed = 0.3;
var xrnd_seed = xrnd_start_seed;

function xrnd_reset() {
	xrnd_seed = xrnd_start_seed;
}

function xrnd() {
	xrnd_seed = (xrnd_seed*9301+49297) % 233280;
	return xrnd_seed/(233280.0);
};

function xrand(number) {
	return Math.floor(xrnd()*number);
};

function xrand2(a, n) {
	return a+Math.floor(xrnd()*n);
};
