	// based on the game space harrier
	var w = 500;
	var h = 500;
	var gameTime = 0;
	var gameOver = false;
	var gameStarted = false;
	var currentEnemy = null;
	var enemyLevel = 1;
	var ctx = null;
	document.onkeydown = keyDown;
	document.onkeyup = keyUp;
	
	// ----------------------------------------
	// --------- GROUND AND LANDSCAPE ---------
	// ----------------------------------------
	
	var groundBarZ = 0; // position counter for ground
	
	function clear() {
		ctx.fillStyle = "rgb(255,255,255)";
		ctx.fillRect (0,0,w,h);
	}
	
	function drawLandscape () {
		var radgrad4 = ctx.createRadialGradient(w/2,0,h/4,w/2,0,h);
		radgrad4.addColorStop(0, '#00ffff');
		radgrad4.addColorStop(0.9, '#0000ff');
		ctx.fillStyle = radgrad4;
		ctx.fillRect(0,0,w,h);
	}
	
	function drawGround() {
		if (gameStarted && !gameOver) {
			groundBarZ++;
		}
		
		if (groundBarZ == parseInt(h/2)) {
			groundBarZ = 1;
		}
		
		var gradientLoc = groundBarZ/(h/3.0);
		var gradientLocMin = gradientLoc - 0.4;
		var gradientLocMax = gradientLoc + 0.05;

		if (gradientLocMin < 0) {gradientLocMin = 0; }
		if (gradientLocMin > 1) {gradientLocMin = 1; }
		if (gradientLoc < 0) {gradientLoc = 0; }
		if (gradientLoc > 1) {gradientLoc = 1; }
		if (gradientLocMax < 0) {gradientLocMax = 0; }
		if (gradientLocMax > 1) {gradientLocMax = 1; }
		
		var gradient = ctx.createLinearGradient(0,h/3,0,h);  
		gradient.addColorStop(gradientLocMin,'rgb(0,200,0)');  
		gradient.addColorStop(gradientLoc,'rgb(0,150,0)');  
		gradient.addColorStop(gradientLocMax,'rgb(0,200,0)');  
		ctx.fillStyle = gradient;  
		ctx.fillRect(0,(2 * (h/3)),w,h);  
		
		if (gameTime/parseInt(h/2) > 1) {
			var passCount = parseInt(gameTime/parseInt(h/2));
			// draw rocks
			if (passCount % 2 == 0) {	
				drawRock(120 - groundBarZ * 4, (2 * h/3.0) + groundBarZ,groundBarZ);
			}
			else {
				drawRock(420 + groundBarZ * 4, (2 * h/3.0) + groundBarZ,groundBarZ);
			}
		}
		
		drawClouds();
	}
	
	var cloudFrame = 0;
	
	function drawClouds() {
		if (gameStarted && !gameOver) {
			cloudFrame++;
			
			var tmp = cloudFrame % 100;
			drawCloud(120 - tmp * 4, 50 - tmp * 1.5, tmp % parseInt(h/2));
			
			var tmp = (cloudFrame + 50) % 100;
			drawCloud(350 + tmp * 4, 50 - tmp * 1.5, tmp % parseInt(h/2));
			
			var tmp = (cloudFrame + 25) % 100;
			drawCloud(280, 50 - tmp * 2.5, tmp % parseInt(h/2));
		}
	}
	
	function drawCloud(x, y, z) {
		z = z/5;
		ctx.fillStyle = "#ffffff";
		ctx.beginPath();
		ctx.moveTo(x - (10 * z), y);
		ctx.lineTo(x - (7 * z),y - (4 * z));
		ctx.lineTo(x - (3 * z),y - (4 * z));
		ctx.lineTo(x, y - (6 * z));
		ctx.lineTo(x + (5 * z), y - (2 * z));
		ctx.lineTo(x + (6 * z), y);
		ctx.lineTo(x + (1 * z), y + (3 * z));
		ctx.lineTo(x - (1 * z), y + (2 * z));
		ctx.lineTo(x - (4 * z), y + (4 * z));
		ctx.closePath();
		ctx.fill();
	}
	
	function drawRock(x, y, z) {
		z = z/5;
		ctx.fillStyle = "#660000";
		ctx.beginPath();
		ctx.moveTo(x - (10 * z), y);
		ctx.lineTo(x - (7 * z),y - (4 * z));
		ctx.lineTo(x - (3 * z),y - (2 * z));
		ctx.lineTo(x, y - (6 * z));
		ctx.lineTo(x + (5 * z), y - (2 * z));
		ctx.lineTo(x + (6 * z), y);
		ctx.closePath();
		ctx.fill();
	}
	
	function animateText() {
		if (gameOver) {
			drawGameOver();
		}
		else {
			if (gameTime <= 150) {
				var fontSize = 100 + (gameTime * 2);
				
				ctx.font = fontSize + "pt Arial";
				ctx.fillStyle = "orange";  
				ctx.fillText("Start", 102 - gameTime * 3, 354 + gameTime * 3);  
				ctx.fillStyle = "red";  
				ctx.fillText("Start", 100 - gameTime * 3, 350 + gameTime * 3);
			}
			else {
				drawStage();
			}
			
			if (gameTime > 0) {
				ctx.font = "16pt Arial";
				ctx.fillStyle = "black";  
				ctx.fillText("Stage " + enemyLevel, w - 99, h - 24);
				ctx.fillStyle = "white";  
				ctx.fillText("Stage " + enemyLevel, w - 100, h - 25);
			}
		}
	}
	
	function drawGameOver() {
		var fontSize = 50;
		ctx.font = fontSize + "pt Arial";
		ctx.fillStyle = "orange";  
		ctx.fillText("Game Over", 62, 254);  
		ctx.fillStyle = "red";  
		ctx.fillText("Game Over", 60, 250);
	}
	
	var displayingStage = false;
	var currentStageDisplayed = true;
	var displayingStageTime = 0;
	var stageLevel;
	
	function initDrawStage() {
		displayingStage = true;
		displayingStageTime = gameTime;
		stageLevel = enemyLevel;
		currentStageDisplayed = false;
	}
	
	
	function drawStage() {
		if (displayingStage) {		
			var timeElapsed = (gameTime - displayingStageTime);
			
			if (timeElapsed < 30) {
				timeElapsed = 30;
			}
			
			var fontSize = 20 + (timeElapsed * 1.5);
			
			ctx.font = fontSize + "pt Arial";
			ctx.fillStyle = "orange";  
			ctx.fillText("Stage " + stageLevel, 222 - timeElapsed * 3.7, 302 + timeElapsed * 3);
			ctx.fillStyle = "red";  
			ctx.fillText("Stage " + stageLevel, 220 - timeElapsed * 3.7, 300 + timeElapsed * 3);
			
			if (timeElapsed >= 360) {
				displayingStage = false;
				currentStageDisplayed = true;
			}
		}
	}
	
	// ----------------------------------------
	// ------------ MOVEMENT LOGIC ------------
	// ----------------------------------------
	
	var speed = 6;
	var aSpeed = 0;
	var sSpeed = 0;
	var dSpeed = 0;
	var wSpeed = 0;
	var isBulletKeyDown = false;
	
	function keyDown(e) {
		if (!gameOver) {
			var unicode = getKeyCode(e);
			var key = String.fromCharCode(unicode);
						
			if (unicode == 87 && wSpeed == 0) {
				wSpeed = speed;
			}
			else if (unicode == 83 && sSpeed == 0) {
				sSpeed = speed;
			}
			else if (unicode == 65 && aSpeed == 0) {
				aSpeed = speed;	
			}
			else if (unicode == 68 && aSpeed == 0) {
				dSpeed = speed;
			}
			else if (unicode == 32 && !isBulletKeyDown) {
				gameStarted = true;
				isBulletKeyDown = true;
				fireBullet(charPosX + charSize/2, charPosY + charSize/2, true);
			}
		}
	}
	
	function keyUp(e) {			
		var unicode = getKeyCode(e);
		var key = String.fromCharCode(unicode);
		
		if (unicode == 87) {
			wSpeed = 0;
		}
		else if (unicode == 83) {
			sSpeed = 0;
		}
		else if (unicode == 65) {
			aSpeed = 0;	
		}
		else if (unicode == 68) {
			dSpeed = 0;
		}
		else if (unicode == 32) {
			isBulletKeyDown = false;
		}
	}

	function getKeyCode(e) {
		if (navigator.appName == "Microsoft Internet Explorer") {
				return event.keyCode; // not a typo.
		}
	   
		return e.which;
	}
	
	function calculateNewPosition() {
		charPosX += (dSpeed - aSpeed);
		charPosY += (sSpeed - wSpeed);
		
		if (charPosX + charSize > w) {
			charPosX = w - charSize;
		}
		else if (charPosX < 0) {
			charPosX = 0;
		}
		
		if (charPosY + charSize > h) {
			charPosY = h - charSize;
		}
		else if (charPosY < 0) {
			charPosY = 0;
		}
	}		
	
	// ----------------------------------------
	// -------------- BULLETS -----------------
	// ----------------------------------------
	
	var bulletList = new Array();
	
	function BulletClass (initialX, initialY, charBullet) {
		this.x = initialX;
		this.y = initialY;
		this.initialDist = zSpaceLength;
		this.dist = this.initialDist;
		this.charBullet = charBullet;
		this.alive = true;
		this.moveBulletMtd = moveBulletMtd;
		this.collide = collide;
	}
	
	function collide(x, y) {
		var collided = false;
		
		if (this.dist <= 4) {
			if (x >= this.x - this.initialDist && x <= this.x + this.initialDist &&
				y >= this.y - this.initialDist && y <= this.y + this.initialDist ) {
				collided = true;
				this.dist = 0;
			}
		}
		
		return collided;
	}
	
	function moveBulletMtd () {
		this.dist--;
		
		if (this.dist <= 1) {
			this.alive = false;
		}
		else {
			
			if (this.charBullet) {
				var visual = ctx.createRadialGradient(this.x,this.y,this.dist/2,this.x,this.y,this.dist); 
				visual.addColorStop(0, 'rgba(255, 0, 0, 1)');  
				visual.addColorStop(0.9, 'rgba(255, 200, 1500, 1)');  
				visual.addColorStop(1, 'rgba(255,1,136, 0)'); 
				ctx.fillStyle = visual;  
			}
			else {
				var visual = ctx.createRadialGradient(this.x,this.y,this.initialDist - this.dist,this.x,this.y,this.initialDist - this.dist/2);  
				visual.addColorStop(0, 'rgba(255, 0, 0, 1)');  
				visual.addColorStop(0.9, 'rgba(150, 0, 0, 1)');  
				visual.addColorStop(1, 'rgba(200, 0, 0, 0)');  
				ctx.fillStyle = visual;  
			}
			
			ctx.fillRect(this.x - this.initialDist,this.y - this.initialDist,2 * this.initialDist,2 * this.initialDist);  	
		}			
	}
	
	// called from keyDown
	function fireBullet(initialX, initialY, charBullet) {
		bulletList[bulletList.length] = new BulletClass(initialX, initialY, charBullet);
	}
	
	function moveBullets() {
		var i = 0;
		var len = bulletList.length;
		
		for (i = 0; i < len; i++) {
			bulletList[i].moveBulletMtd();
		}
		
		for (i = 0; i < len; i++) {
			if (!bulletList[i].alive) {
				bulletList.splice(i,1);
				len--;
			}
		}
		
		for (i = 0; i < bulletList.length; i++) {
			if (bulletList[i].charBullet) {
				if (currentEnemy != null) {
					if (bulletList[i].collide(currentEnemy.snakeHeadPosX, currentEnemy.snakeHeadPosY)) {
						currentEnemy.snakeHitTime = gameTime;
					}
				}
			}
			else {
				if (bulletList[i].collide(charPosX + charSize/2, charPosY + charSize/2)) {
					charHitTime = gameTime;
				}
			}
		}
		
	}
	
	// ----------------------------------------
	// -------------- ENEMIES -----------------
	// ----------------------------------------
	
	function animateEnemies() {
		if (currentEnemy != null && currentEnemy.isDead) {
			currentEnemy = null;
			enemyLevel++;
		}
		
		if (currentEnemy == null) {
			if (currentStageDisplayed) {
				currentEnemy = new SnakeCls(enemyLevel);
				currentStageDisplayed = false;
			}
			else if (!displayingStage) {
				initDrawStage();
			}
		}
		
		if (currentEnemy != null) {
			currentEnemy.animate();
		}
	}
	
	function SnakeCls(enemyLevel) {
		this.enemyLevel = enemyLevel;
		this.snakeHitTime = 0;
		this.snakeVisible = false;
		this.snakeVisibleDelay = gameTime + 20;
		this.snakeSpeed = enemyLevel * 1.2;
		this.snakePosZ = 0;
		this.snakePosZMax = 40;
		this.snakeHeadPosX = 50 + Math.floor(Math.random() * 250);
		this.snakeHeadPosY = 50 + Math.floor(Math.random() * 250);
		this.snakeDestPosX = 50 + Math.floor(Math.random() * 250);
		this.snakeDestPosY = 50 + Math.floor(Math.random() * 250);
		this.snakePosHistory = new Array();
		this.tailSize = 3 + enemyLevel;
		this.tailSpace = 5;
		this.animate = animate;
		this.isDead = false;
	}
	
	function animate() {
		if (gameTime == this.snakeVisibleDelay) { 
			this.snakeVisible = true;
		}
		
		if (this.snakeVisible) {
			if (this.snakePosZ < this.snakePosZMax) {
				if (gameTime % 2 == 0) this.snakePosZ += 1;
			}
			
			if (this.enemyLevel % 2 == 0) {
				if (parseInt(this.snakeHeadPosX/this.snakeSpeed) == parseInt(this.snakeDestPosX/this.snakeSpeed)) {
					this.snakeDestPosX = Math.floor(Math.random()*(w - this.snakePosZ * 2)) + this.snakePosZ;
				}
				if (this.snakeHeadPosX < this.snakeDestPosX) {
					this.snakeHeadPosX += this.snakeSpeed;
				}
				else if (this.snakeHeadPosX > this.snakeDestPosX) {
					this.snakeHeadPosX -= this.snakeSpeed;
				}
			}
			else {
				this.snakeHeadPosX = Math.sin(gameTime/(50 - (this.snakeSpeed))) * 200 + 250;
			}
			
				
			if (parseInt(this.snakeHeadPosY/this.snakeSpeed) == parseInt(this.snakeDestPosY/this.snakeSpeed)) {
				this.snakeDestPosY = Math.floor(Math.random()*(h - h/2- this.snakePosZ * 2)) + this.snakePosZ;
			}
			
			if (this.snakeHeadPosY < this.snakeDestPosY) {
				this.snakeHeadPosY += this.snakeSpeed;
			}
			else if (this.snakeHeadPosY > this.snakeDestPosY) {
				this.snakeHeadPosY -= this.snakeSpeed;
			}
			
			var oldX = this.snakeHeadPosX;
			var oldY = this.snakeHeadPosY;
			var hitFrame = false;
			
			if (this.snakeHitTime > 0) {
				this.tailSize--;
				hitFrame = true;
				this.snakeHitTime = 0;
				
				if (this.tailSize == 0) {
					this.isDead = true;
				}
			}
			
			if (!this.isDead) {
				var arrayTmp = new Array();
				arrayTmp[0] = this.snakeHeadPosX;
				arrayTmp[1] = this.snakeHeadPosY;
				this.snakePosHistory.unshift(arrayTmp);
				
				if (this.snakePosHistory.length > this.tailSize * this.tailSpace) {
					this.snakePosHistory.splice(this.tailSize * this.tailSpace, this.snakePosHistory.length - this.tailSize * this.tailSpace);
				}
				
				for (var i = this.snakePosHistory.length - 1; i >= 0; i--) {
					if (i % this.tailSpace == 0 && this.snakePosZ/4 - i/2 > 0) {
						var visual = ctx.createRadialGradient(this.snakePosHistory[i][0], this.snakePosHistory[i][1], this.snakePosZ/4 - i/2, 
															  this.snakePosHistory[i][0], this.snakePosHistory[i][1], this.snakePosZ/2 - i/2);  
						
						if (hitFrame) {
							visual.addColorStop(0, '#660000');   
							visual.addColorStop(0.8, '#ff0000'); 
						}
						else {
							if (this.enemyLevel % 3 == 0) {
								visual.addColorStop(0, '#004400');  
								visual.addColorStop(0.8, '#00bb00');  
							}
							else if (this.enemyLevel % 2 == 0) {
								visual.addColorStop(0, '#000044');  
								visual.addColorStop(0.8, '#0000bb');  
							}
							else {
								visual.addColorStop(0, '#660000');  
								visual.addColorStop(0.8, '#669999');  
							}
						}
						
						
						visual.addColorStop(1, 'rgba(200, 0, 0, 0)');  
						ctx.fillStyle = visual;
						ctx.fillRect(this.snakePosHistory[i][0]  - this.snakePosZ - i,this.snakePosHistory[i][1] - this.snakePosZ - i,
									 2 * (this.snakePosZ + i), 2 * (this.snakePosZ + i));  	
					}
				}
				
				// draw eyes
				if (this.snakePosZ > 25) {
					var visual = ctx.createRadialGradient(this.snakePosHistory[0][0] - 8, this.snakePosHistory[0][1] - 10, this.snakePosZ/15 + 3, 
														  this.snakePosHistory[0][0] - 8, this.snakePosHistory[0][1] - 10, this.snakePosZ/15 + 4);  
					visual.addColorStop(0.2, '#000000');  
					visual.addColorStop(0.9, '#ff5555');  
					visual.addColorStop(1, 'rgba(0, 0, 0,0)');  
					ctx.fillStyle = visual;
					ctx.fillRect(this.snakePosHistory[0][0] - 8 - this.snakePosZ, this.snakePosHistory[0][1] - 8 - this.snakePosZ,
								 2 * (this.snakePosZ + 4), 2 * (this.snakePosZ + 4));  	
					
					visual = ctx.createRadialGradient(this.snakePosHistory[0][0] + 8, this.snakePosHistory[0][1] - 10, this.snakePosZ/15 + 3, 
													  this.snakePosHistory[0][0] + 8, this.snakePosHistory[0][1] - 10, this.snakePosZ/15 + 4);  
					visual.addColorStop(0.2, '#000000');  
					visual.addColorStop(0.9, '#ff5555');  
					visual.addColorStop(1, 'rgba(0, 0, 0,0)');  
					ctx.fillStyle = visual;
					ctx.fillRect(this.snakePosHistory[0][0] + 8 - this.snakePosZ, this.snakePosHistory[0][1] + 8 - this.snakePosZ,
								 2 * (this.snakePosZ + 4), 2 * (this.snakePosZ + 4));  
				}
													  
				
				if (gameTime % 30 == 0 && this.snakePosZ == this.snakePosZMax) {
					bulletList[bulletList.length] = new BulletClass(this.snakeHeadPosX, this.snakeHeadPosY, false);
				}
			}
		}
	}
	
	// ----------------------------------------
	
	var charSize = 50;
	var charPosX = w/2;
	var charPosY = h/3;
	var charHitTime = 0;
	var zSpaceLength = 20; // Space empty between enemies and the character
	
	var imageLoaded = false;
	var charImage = new Image();
	charImage.onload = function () { imageLoaded = true; }
	charImage.src = "images/harrier-character.png";
		
	function moveCharacter() {
		calculateNewPosition();
		if (imageLoaded) {
			ctx.drawImage(charImage, charPosX, charPosY, 30, 48);
		}
		
		if (charHitTime > 0) {
			gameOver = true;
			charHitTime = 0;
		}
	}
	 
	function drawGame() {
		clear();
		drawLandscape();
		drawGround();
		
		animateText();
		
		if (!gameOver) {
			if (gameStarted) {
				gameTime++;
				animateEnemies();
			}
			
			moveBullets();
			moveCharacter();
		}
		
		setTimeout(drawGame, 30);
	}
	
	function initSpaceHarrierGame(divName) {
		document.getElementById(divName).innerHTML = '<canvas id="spaceHarrierGame" width="500" height="500"></canvas><p style="color:#777777;">A S D W &amp; space</p>';	
		var canvas = document.getElementById('spaceHarrierGame');  
		ctx = canvas.getContext('2d');  
		drawGame();
	}
