var gameLevel = 1,
	increaseLevel,
	highScore = localStorage.getItem('highScore') || 0;;

//Define an object to hold all our images for the game
var imageRepository = new function() {
 	this.background = new Image();
 	this.spaceship = new Image();
 	this.bullet = new Image();
	this.enemy = new Image();
	this.enemyBullet = new Image();

 	// Ensures all images have loaded before starting the game
 	var numImages = 5;
 	var numLoaded = 0;
 	function imageLoaded() {
 		numLoaded++;
 		if(numLoaded === numImages) {
 			window.init();
 		}
 	}

 	this.background.onload = function() {
 		imageLoaded();
 	}
 	this.spaceship.onload = function() {
 		imageLoaded();
 	}
 	this.bullet.onload = function() {
 		imageLoaded();
 	}
	this.enemy.onload = function() {
		imageLoaded();
	}
	this.enemyBullet.onload = function() {
		imageLoaded();
	}

 	// Set images src
 	this.background.src = "images/bg.png";
 	this.spaceship.src = "images/ship.png";
 	this.bullet.src = "images/bullet.png";
	this.enemy.src = "images/enemy.png";
	this.enemyBullet.src = "images/bullet_enemy.png";
}


/**
 * Creates the Drawable object which will be the base class for all 
 * drawable objects in the game. Sets up default variables that 
 * all child objects will inherit, as well as the default functions.
 */
function Drawable() {
	this.init = function(x, y, width, height) {
		// Defualt variables
		this.x = x;
		this.y = y;
		this.width = width;
		this.height = height;
	}
	this.speed = 0;
	this.canvasWidth = 0;
	this.canvasHeight = 0;
	this.collidableWith = "";
	this.isColliding = false;
	this.type = "";
	
	// Define abstract function to be implemented in child objects
	this.draw = function() {
	};
	this.move = function() {
	};
	this.isCollidableWith = function(object) {
		return (this.collidableWith === object.type);
	};
}


/**
 * Custom Pool object. Holds Bullet objects to be managed to prevent
 * garbage collection.
 */
function Pool(maxSize) {
	var size = maxSize;
	var pool = [];

	// Populates the pool array with objects
	this.init = function(object) {
		if (object == "bullet") {
			for (var i = 0; i < size; i++) {
				var bullet = new Bullet("bullet");
				bullet.init(0,0, imageRepository.bullet.width, imageRepository.bullet.height);
				bullet.collidableWith = "enemy";
				bullet.type = "bullet";
				pool[i] = bullet;
			}
		}
		else if (object == "enemy") {
			for (var i = 0; i < size; i++) {
				var enemy = new Enemy();
				
				enemy.collidableWith ="ship";
				enemy.type = "enemy";
				enemy.init(0,0,Enemy.prototype.canvasWidth*.13, Enemy.prototype.canvasHeight*.13);
				pool[i] = enemy;
			}
		}
		else if (object == "enemyBullet") {
			for (var i = 0; i < size; i++) {
				var bullet = new Bullet("enemyBullet");
				bullet.init(0,0, imageRepository.enemyBullet.width, imageRepository.enemyBullet.height);
				bullet.collidableWith ="ship";
				bullet.type = "enemyBullet";
				pool[i] = bullet;
			}
		}
	};
	this.getPool = function() {
		var obj = [];
		for (var i = 0; i < size; i++) {
			if (pool[i].alive) {
				obj.push(pool[i]);
			}
		}
		return obj;
	}

	/**
	 * Grabs the last item in the list and initializes it
	 * and pushes it to the front of the array.
	 */
	this.get = function(x, y, speed) {
		if(!pool[size-1].alive) {
			pool[size-1].spawn(x, y, speed);
			pool.unshift(pool.pop());
		}
	};

	//Used for the ship to be able to get two bullets at once.
	this.getTwo = function(x1, y1, speed1, x2, y2, speed2) {
		if(!pool[size-1].alive &&
			!pool[size-2].alive) {
			this.get(x1, y1, speed1);
			this.get(x2, y2, speed2);
		}
	};

	/*
	 * Draws any in use Bullets. If a bullet goes off the screen,
	 * clears it and pushes it to the front of the array.
	 */
	this.animate = function() {
		for (var i = 0; i < size; i++) {
			if(pool[i].alive) {
				if (pool[i].draw()) {
					pool[i].clear();
					pool.push((pool.splice(i,1))[0]);
				}
			} else {
				break;
			}
		}
	};
}

function Enemy() {
	var percentFire = .01;
	var chance = 0;
	this.alive = false;
	
	// Sets the Enemy values
	this.spawn = function(x, y, speed) {
		this.x = x;
		this.y = y;
		this.speed = speed;
		this.alive = true;
	};
	
	// Move the enemy
	this.draw = function() {
		this.context.clearRect(this.x-1, this.y-1, this.width + 1, this.height + 1);
		this.y += this.speed;
		
		chance = Math.floor(Math.random()*101);
		if (chance/100 < percentFire) {
			this.fire();
		}
		
		if (this.isColliding){
			if(game.ship.isColliding) {
				game.gameOver();
			} else {
				game.explosion.get();
				game.playerScore+= gameLevel;
			}
			return true;
		} else if(this.y >= this.canvasHeight) {
			return true;
		}
		else{
			this.context.drawImage(imageRepository.enemy, this.x, this.y, this.width, this.width);
			return false;
		}
	};
	
	// Fires a bullet
	this.fire = function() {
		game.enemyBulletPool.get(this.x+this.width/2, this.y+this.height, (-3-gameLevel));
		game.laser.get();
	}
	
	//Resets the enemy values
	this.clear = function() {
		this.x = 0;
		this.y = 0;
		this.speed = 0;
		this.alive = false;
		this.isColliding = false;
	};
}
Enemy.prototype = new Drawable();

/**
 * Creates the Bullet object which the ship fires. The bullets are
 * drawn on the "main" canvas.
 */
function Bullet(object) {
	this.alive = false;
	var self = object;

	// Sets the bullet values
	this.spawn = function(x, y, speed) {
		this.x = x;
		this.y = y;
		this.speed = speed;
		this.alive = true;
	};

	/*
	 * Uses a "drity rectangle" to erase the bullet and moves it.
	 * Returns true if the bullet moved off the screen, indicating that
	 * the bullet is ready to be cleared by the pool, otherwise draws
	 * the bullet.
	 */
	this.draw = function() {
		this.context.clearRect(this.x-1, this.y-1, this.width+2, this.height+2);
		this.y -= this.speed;
		if (this.isColliding) {
			return true;
		}
		else if (self === "bullet" && this.y <= 0 - this.height) {
			return true;
		}
		else if (self === "enemyBullet" && this.y >= this.canvasHeight) {
			return true;
		}
		else {
			if (self === "bullet") {
				this.context.drawImage(imageRepository.bullet, this.x, this.y);
			}
			else if (self === "enemyBullet") {
				this.context.drawImage(imageRepository.enemyBullet, this.x, this.y);
			}
			return false;
		}
	};

	// Reset the bullet values
	this.clear = function() {
		this.x = 0;
		this.y = 0;
		this.speed = 0;
		this.alive = false;
		this.isColliding = false;
	};
}
Bullet.prototype = new Drawable();


/**
 * Create the Ship object that the player controls. The ship is
 * drawn on the "ship" canvas and uses dirty rectangles to move
 * around the screen.
 */
function Ship() {
	this.speed = 3;
	this.bulletpool = new Pool(30);
	this.bulletpool.init("bullet");
	this.collidableWith = "enemyBullet";
	this.type = "ship";

	var fireRate = 15;
	var counter = 0;

	this.draw = function() {
		this.context.drawImage(imageRepository.spaceship, this.x, this.y, this.width, this.height);
	};

	this.move = function() {
		counter++;
		// Determine if the action is move action
		if(KEY_STATUS.left || KEY_STATUS.right) {
			this.context.clearRect(this.x - 2, this.y - 2, this.width+2, this.height+4);
			// Update x and y according to the direction to move and redraw the ship
			if(KEY_STATUS.left) {
				this.x -= this.speed;
				if(this.x <= 0) {
					this.x = 0;
				}
			} else if(KEY_STATUS.right) {
				this.x += this.speed;
				if(this.x >= this.canvasWidth - this.width) {
					this.x = this.canvasWidth - this.width;
				}
			}
			this.draw();
		}
		
		if (this.isColliding && game.ship.alive) {
			
			game.playerLife--;
			
			if (game.playerLife){
				
				$('.heart:eq('+game.playerLife+')').hide();
				this.isColliding = false;
			}
			else {
				game.gameOver();
			}
		} 
			
		if(KEY_STATUS.space && counter >= fireRate) {
			this.fire();
			counter = 0;
		}
	};

	// Fires the bullets
	this.fire = function() {
		var bullePosX = this.x + (this.width/2);
		this.bulletpool.get(bullePosX, this.y, 5);
		game.laser.get();
	};
}
Ship.prototype = new Drawable();

// The keycodes that will be mapped when a user presses a button.
// Original code by Doug McInnes
KEY_CODES = {
  32: 'space',
  37: 'left',
  38: 'up',
  39: 'right',
  40: 'down',
}

// Creates the array to hold the KEY_CODES and sets all their values
// to false. Checking true/flase is the quickest way to check status
// of a key press and which one was pressed when determining
// when to move and which direction.
KEY_STATUS = {};
for (code in KEY_CODES) {
  KEY_STATUS[ KEY_CODES[ code ]] = false;
}
/**
 * Sets up the document to listen to onkeydown events (fired when
 * any key on the keyboard is pressed down). When a key is pressed,
 * it sets the appropriate direction to true to let us know which
 * key it was.
 */
document.onkeydown = function(e) {
  // Firefox and opera use charCode instead of keyCode to
  // return which key was pressed.
  var keyCode = (e.keyCode) ? e.keyCode : e.charCode;
  if (KEY_CODES[keyCode]) {
    e.preventDefault();
    KEY_STATUS[KEY_CODES[keyCode]] = true;
  }
}
/**
 * Sets up the document to listen to ownkeyup events (fired when
 * any key on the keyboard is released). When a key is released,
 * it sets teh appropriate direction to false to let us know which
 * key it was.
 */
document.onkeyup = function(e) {
  var keyCode = (e.keyCode) ? e.keyCode : e.charCode;
  if (KEY_CODES[keyCode]) {
    e.preventDefault();
    KEY_STATUS[KEY_CODES[keyCode]] = false;
  }
}

var onlongtouch; 
var timer;
var touchduration = 200;

function handleStart(evt) {
  	evt.preventDefault();
  	var touches = evt.changedTouches;

	if (touches[0].pageX < game.shipCanvas.width /2){
		timer = setTimeout(moveLeft, touchduration);
	}
	else{
		timer = setTimeout(moveRight, touchduration);
	}
}
moveLeft = function(direction) { 
	KEY_STATUS[KEY_CODES[37]] = true;
}
moveRight = function(direction) { 
	KEY_STATUS[KEY_CODES[39]] = true;
}

function handleEnd(evt) {
	evt.preventDefault();
	if (timer){ clearTimeout(timer); }
	
	if (KEY_STATUS[KEY_CODES[39]] || KEY_STATUS[KEY_CODES[37]]){
		KEY_STATUS[KEY_CODES[39]] = false;
		KEY_STATUS[KEY_CODES[37]] = false;
	} else {
		game.ship.fire();
	}
	
}


 /**
 * Creates the Background object which will become a child of
 * the Drawable object. The background is drawn on the "background" canvas.
 */
function Background() {
	this.speed = gameLevel;
	
	// Implement abstract function
	this.draw = function() {
		this.y += this.speed;
		this.context.drawImage(imageRepository.background, this.x, this.y, this.canvasWidth, this.canvasHeight);
 		this.context.drawImage(imageRepository.background, this.x, this.y - this.canvasHeight, this.canvasWidth, this.canvasHeight);

		// If the image scrolled off the screen, reset
		if (this.y >= this.canvasHeight)
			this.y = 0;
	};
}
Background.prototype = new Drawable();


/**
 * QuadTree object.
 *
 * The quadrant indexes are numbered as below:
 *     |
 *  1  |  0
 * —-+—-
 *  2  |  3
 *     |
 */
function QuadTree(boundBox, lvl) {
	var maxObjects = 10;
	this.bounds = boundBox || {
		x: 0,
		y: 0,
		width: 0,
		height: 0
	};
	var objects = [];
	this.nodes = [];
	var level = lvl || 0;
	var maxLevels = 5;
	
	// Clears the quadTree and all nodes of objects
	this.clear = function() {
		objects = [];
		for (var i = 0; i < this.nodes.length; i++) {
			this.nodes[i].clear();
		}
		this.nodes = [];
	};
	
	// Get all objects in the quadTree
	this.getAllObjects = function(returnedObjects) {
		for (var i = 0; i < this.nodes.length; i++) {
			this.nodes[i].getAllObjects(returnedObjects);
		}
		for (var i = 0, len = objects.length; i < len; i++) {
			returnedObjects.push(objects[i]);
		}
		return returnedObjects;
	};
	
	// Return all objects that the object could collide with
	this.findObjects = function(returnedObjects, obj) {
		if (typeof obj === "undefined") {
			return;
		}
		var index = this.getIndex(obj);
		if (index != -1 && this.nodes.length) {
			this.nodes[index].findObjects(returnedObjects, obj);
		}
		for (var i = 0, len = objects.length; i < len; i++) {
			returnedObjects.push(objects[i]);
		}
		return returnedObjects;
	};
	
	/*
	 * Insert the object into the quadTree. If the tree
	 * excedes the capacity, it will split and add all
	 * objects to their corresponding nodes.
	 */
	this.insert = function(obj) {
		if (typeof obj === "undefined") {
			return;
		}
		if (obj instanceof Array) {
			for (var i = 0, len = obj.length; i < len; i++) {
				this.insert(obj[i]);
			}
			return;
		}
		if (this.nodes.length) {
			var index = this.getIndex(obj);
			// Only add the object to a subnode if it can fit completely
			// within one
			if (index != -1) {
				this.nodes[index].insert(obj);
				return;
			}
		}
		objects.push(obj);
		// Prevent infinite splitting
		if (objects.length > maxObjects && level < maxLevels) {
			if (this.nodes[0] == null) {
				this.split();
			}
			var i = 0;
			while (i < objects.length) {
				var index = this.getIndex(objects[i]);
				if (index != -1) {
					this.nodes[index].insert((objects.splice(i,1))[0]);
				}
				else {
					i++;
				}
			}
		}
	};
	/*
	 * Determine which node the object belongs to. -1 means
	 * object cannot completely fit within a node and is part
	 * of the current node
	 */
	this.getIndex = function(obj) {
		var index = -1;
		var verticalMidpoint = this.bounds.x + this.bounds.width / 2;
		var horizontalMidpoint = this.bounds.y + this.bounds.height / 2;
		// Object can fit completely within the top quadrant
		var topQuadrant = (obj.y < horizontalMidpoint && obj.y + obj.height < horizontalMidpoint);
		// Object can fit completely within the bottom quandrant
		var bottomQuadrant = (obj.y > horizontalMidpoint);
		// Object can fit completely within the left quadrants
		if (obj.x < verticalMidpoint &&
				obj.x + obj.width < verticalMidpoint) {
			if (topQuadrant) {
				index = 1;
			}
			else if (bottomQuadrant) {
				index = 2;
			}
		}
		// Object can fix completely within the right quandrants
		else if (obj.x > verticalMidpoint) {
			if (topQuadrant) {
				index = 0;
			}
			else if (bottomQuadrant) {
				index = 3;
			}
		}
		return index;
	};
	/*
	 * Splits the node into 4 subnodes
	 */
	this.split = function() {
		// Bitwise or [html5rocks]
		var subWidth = (this.bounds.width / 2) | 0;
		var subHeight = (this.bounds.height / 2) | 0;
		this.nodes[0] = new QuadTree({
			x: this.bounds.x + subWidth,
			y: this.bounds.y,
			width: subWidth,
			height: subHeight
		}, level+1);
		this.nodes[1] = new QuadTree({
			x: this.bounds.x,
			y: this.bounds.y,
			width: subWidth,
			height: subHeight
		}, level+1);
		this.nodes[2] = new QuadTree({
			x: this.bounds.x,
			y: this.bounds.y + subHeight,
			width: subWidth,
			height: subHeight
		}, level+1);
		this.nodes[3] = new QuadTree({
			x: this.bounds.x + subWidth,
			y: this.bounds.y + subHeight,
			width: subWidth,
			height: subHeight
		}, level+1);
	};
}

/**
 * A sound pool to use for the sound effects
 */
function SoundPool(maxSize) {
	var size = maxSize;
	var pool = [];
	this.pool = pool;
	var currSound = 0;
	/*
	 * Populates the pool array with the given sound
	 */
	this.init = function(object) {
		if (object == "laser") {
			for (var i = 0; i < size; i++) {
				// Initalize the sound
				laser = new Audio("sounds/laser.wav");
				laser.volume = .12;
				laser.load();
				pool[i] = laser;
			}
		}
		else if (object == "explosion") {
			for (var i = 0; i < size; i++) {
				var explosion = new Audio("sounds/explosion.mp3");
				explosion.volume = .2;
				explosion.load();
				pool[i] = explosion;
			}
		}
	};
	
	// Plays a sound
	this.get = function() {
		if(pool[currSound].currentTime == 0 || pool[currSound].ended) {
			pool[currSound].play();
		}
		currSound = (currSound + 1) % size;
	};
}


/**
 * Creates the Game object which will hold all objects and data for the game.
 */
function Game() {
	this.init = function() {
		// Get the canvas element
		this.bgCanvas = document.getElementById('background');
		this.shipCanvas = document.getElementById('ship');
		this.mainCanvas = document.getElementById('main');
		this.playerScore = 0;
		this.playerLife = 5;

		// Test to see if canvas is supported
		if(this.bgCanvas.getContext) {
			var w = $('#game_screen').width();
			var h = $('#game_screen').height()
			this.played = false;
			this.bgCanvas.height = h;
			this.bgCanvas.width = w;
			this.shipCanvas.height = this.bgCanvas.height;
			this.shipCanvas.width = this.bgCanvas.width;
			this.mainCanvas.height = this.bgCanvas.height;
			this.mainCanvas.width = this.bgCanvas.width;
			
			this.bgContext = this.bgCanvas.getContext('2d');
			this.shipContext = this.shipCanvas.getContext('2d');
			this.mainContext = this.mainCanvas.getContext('2d');

			this.shipCanvas.addEventListener("touchstart", handleStart, false);
			this.shipCanvas.addEventListener("touchend", handleEnd, false);
			this.shipCanvas.addEventListener("touchleave", handleEnd, false);
			
			// Initialize objects to contain their context and canvas information
			Background.prototype.context = this.bgContext;
			Background.prototype.canvasWidth = this.bgCanvas.width;
			Background.prototype.canvasHeight = this.bgCanvas.height;

			Ship.prototype.context = this.shipContext;
			Ship.prototype.canvasWidth = this.shipCanvas.width;
			Ship.prototype.canvasHeight = this.shipCanvas.height;

			Bullet.prototype.context = this.mainContext;
			Bullet.prototype.canvasWidth = this.mainCanvas.width;
			Bullet.prototype.canvasHeight = this.mainCanvas.height;
			
			Enemy.prototype.context = this.mainContext;
			Enemy.prototype.canvasWidth = this.mainCanvas.width;
			Enemy.prototype.canvasHeight = this.mainCanvas.height;

			// Initialize the object;
			this.background = new Background();
			this.background.init(0,0);
			
			this.ship = new Ship();
			// Set the ship to start near the bottom middle of the canvas
			var shipStartX = this.shipCanvas.width/2 - imageRepository.spaceship.width/2;
			var shipStartY = this.shipCanvas.height *.85;
			this.ship.init(shipStartX, shipStartY, this.shipCanvas.width * .15, this.shipCanvas.height * .13);
			

			this.enemyPool = new Pool(30);
			this.enemyPool.init("enemy");
			this.spawnWave(gameLevel);
			
			
			this.enemyBulletPool = new Pool(50);
			this.enemyBulletPool.init("enemyBullet");
			
			this.quadTree = new QuadTree({x:0,y:0,width:this.mainCanvas.width,height:this.mainCanvas.height});
			
			// Audio files
			this.laser = new SoundPool(20);
			this.laser.init("laser");
			this.explosion = new SoundPool(30);
			this.explosion.init("explosion");
			this.backgroundAudio = new Audio("sounds/back.mp3");
			this.backgroundAudio.loop = true;
			this.backgroundAudio.volume = .5;
			this.backgroundAudio.load();
			this.gameOverAudio = new Audio("sounds/game_over.mp3");
			this.gameOverAudio.loop = true;
			this.gameOverAudio.volume = .5;
			this.gameOverAudio.load();
			
			this.checkAudio = window.setInterval(function(){checkReadyState()},1000);
			
			
			
			return true;
		} else {
			return false;
		}
	};
	
	this.spawnWave = function(need_enemy) {
		var e_x = this.mainCanvas.width - Enemy.prototype.canvasWidth*.13;
		e_x=Math.floor(Math.random() * e_x +1);
		for (var i = 1; i <= need_enemy; i++) {
			this.enemyPool.get(e_x, -Enemy.prototype.canvasWidth*.13, gameLevel);
		}
	}
	// Start the animation loop
	this.start = function() {
		if(this.played){
			this.restart();
		} else {
			gameLevel = 1;
			this.playerScore = 0;
			
			this.background.speed = gameLevel;
			this.ship.draw();
			
			this.backgroundAudio.currentTime = 0;
			this.backgroundAudio.play();
			this.played = true;
			this.ship.alive = true;
			animate();
			increaseLevel = setInterval(function(){
				levelUp();
			},30000);
			this.playerLife = 5;
			$('.heart').show();
		}
	};
	
	// Game over
	this.gameOver = function() {
		this.ship.alive = false;
		
		if (this.playerScore > highScore){
			highScore = this.playerScore;
			localStorage.setItem('highScore',highScore);
			$('#highScoreVal').html(highScore);
		}
		
		this.backgroundAudio.pause();
		this.gameOverAudio.currentTime = 0;
		this.gameOverAudio.play();
		$('#game_over').fadeIn('fast').siblings().fadeOut('fast');
		$('#final_score').html('Score : ' +this.playerScore);
		window.clearInterval(increaseLevel);
	};
	
	// Restart the game
	this.restart = function() {
		this.played = false;
		
		this.gameOverAudio.pause();
		document.getElementById('game_over').style.display = "none";
		this.bgContext.clearRect(0, 0, this.bgCanvas.width, this.bgCanvas.height);
		this.shipContext.clearRect(0, 0, this.shipCanvas.width, this.shipCanvas.height);
		this.mainContext.clearRect(0, 0, this.mainCanvas.width, this.mainCanvas.height);
		this.quadTree.clear();
		
		this.background.init(0,0);
		
		var shipStartX = this.shipCanvas.width/2 - imageRepository.spaceship.width/2;
		var shipStartY = this.shipCanvas.height *.85;
		this.ship.init(shipStartX, shipStartY, this.shipCanvas.width*.15, this.shipCanvas.height*.13);
		
		this.enemyPool.init("enemy");
		this.enemyBulletPool.init("enemyBullet");
		this.ship.bulletpool.init("bullet");
		
		this.backgroundAudio.currentTime = 0;
		this.backgroundAudio.play();

		this.start();
	};
}

/**
 * Ensure the game sound has loaded before starting the game
 */
function checkReadyState() {
	if (game.gameOverAudio.readyState === 4 && game.backgroundAudio.readyState === 4) {
		window.clearInterval(game.checkAudio);
		$('#splash').fadeOut('fast');
	}
}
function levelUp() {
	if(game.ship.alive) {
		gameLevel++;
		game.background.speed = gameLevel;
	}
}


/**
 * The animation loop. Calls the requestAnimationFrame shim to
 * optimize the game loop and draws all game objects.
 */
function animate() {
	if (game.ship.alive) {
		requestAnimFrame( animate );
		game.background.draw();
		
		game.enemyPool.animate();
		game.enemyBulletPool.animate();
		game.ship.move();
		game.ship.bulletpool.animate();
		document.getElementById('score').innerHTML = game.playerScore;
		document.getElementById('level').innerHTML = gameLevel;
		
		if (game.enemyPool.getPool().length < gameLevel) {
			game.spawnWave(gameLevel - game.enemyPool.getPool().length);
		}
		
		// Insert objects into quadtree
		game.quadTree.clear();
		game.quadTree.insert(game.ship);
		game.quadTree.insert(game.ship.bulletpool.getPool());
		game.quadTree.insert(game.enemyPool.getPool());
		game.quadTree.insert(game.enemyBulletPool.getPool());
		detectCollision();
	}	
}


/**
 * requestAnim shim layer by Paul Irish
 * Finds the first API that works to optimize the animation loop,
 * otherwise defaults to setTimeout().
 */
window.requestAnimFrame = (function() {
	return window.requestAnimationFrame		||
		window.webkitRequestAnimationFrame	||
		window.mozRequestAnimationFrame		||
		window.oRequestAnimationFrame		||
		window.msRequestAnimationFrame		||
		function(callback, element) {
			window.setTimeout(callback, 1000/60);
		};
})();

function detectCollision() {
	var objects = [];
	game.quadTree.getAllObjects(objects);

	for (var x = 0, len = objects.length; x < len; x++) {
		game.quadTree.findObjects(obj = [], objects[x]);
		for (y = 0, length = obj.length; y < length; y++) {
			if (objects[x].collidableWith === obj[y].type &&
				(objects[x].x < obj[y].x + obj[y].width &&
				 objects[x].x + objects[x].width > obj[y].x &&
				 objects[x].y < obj[y].y + obj[y].height &&
				 objects[x].y + objects[x].height > obj[y].y)) {
					 objects[x].isColliding = true;
					 obj[y].isColliding = true;	
			}
		}
	}
};
/**
 * Initialize the Game and starts it.
 */
var game = new Game();
function init() {
	game.init();
}