;(function($) {

$.snake = {

	$map : {}, $cherry : {}, $overlay : {}, seg : {}, wallseg : {}, cache : {},
	animateTimer : 0, score : 0, grid : 0, level : 1, lives : 3, speed : 0, cherriesEaten : 0,
	wall : 0, gridsize : 20,

	setup : function() {

		// Create initial div's
		$(".snake").html("");
		$(".snake").append($('<div id="map1"><span id="map-msg">Druk op start om<br/> het spel te beginnen</span></div> 	<div id="stats"> 		<span id="stats-score-label">Punten</span> 		<span id="stats-score">0</span> 		<span id="stats-level-label">Level</span> 		<span id="stats-level">0</span> 		<span id="stats-lives-label">Levens</span> 		<span id="stats-lives">0</span> 		<a href="#start" id="start-game">Start</a> 	</div>'));

		$("a#start-game").click(function(e){
			if (!$.browser.msie) { e.preventDefault(); } else { event.returnValue = false; }
			// start the game
			$.snake.newGame();
		});

		// build map
		$.snake.$map = $("#map1");
		$.snake.$map.width = $.snake.$map.innerWidth();
		$.snake.$map.height = $.snake.$map.innerHeight();
		
		// build and prepend overlay to map
		$.snake.$overlay = $('<div id="overlay"></div>').hide();
		$.snake.$map.prepend($.snake.$overlay);

		// build and append cherry to map
		$.snake.$cherry = $('<div id="cherry"></div>').appendTo($.snake.$map);
	
		// listen for key press, store keycode
		$.snake.cache.keyCode = [0,0];
		document.onkeydown = function(e){
			keycode = (e == null) ? event.keyCode : e.which;
			switch(keycode) {					
				case 71 : $.snake.toggleGrid(); break;
				case 80 : $.snake.pause(); break;
				case 78 : $.snake.newGame(true); break;
				case 37 : 					
				case 38 : 
				case 39 : 
				case 40 :
					// preventing default event behaviour causes issues with IE; 
					// need to research further!
					if (!$.browser.msie) {
						e.preventDefault();
					} else {
						event.returnValue = false;
					}
					$.snake.cache.keyCode[0] = $.snake.cache.keyCode[1]; 
					$.snake.cache.keyCode[1] = keycode;					
					break;
				default : break;
			}
		};	
	},
		
	start : function() {
		$.snake.$cherry.fadeIn(function(){
			$.snake.animateTimer = setInterval($.snake.animate, $.snake.speed);			
		});
	},
	
	newGame : function(reset) {

		$.snake.cherriesEaten = 0;
	
		// reset animation timer
		clearInterval($.snake.animateTimer);
		$.snake.animateTimer = 0;

		// reset score
		$.snake.score = reset ? 0 : $.snake.score;

		// reset level
		$.snake.level = reset ? 1 : $.snake.level;
		$("#stats-level").html($.snake.level);

		// reset lives
		$.snake.lives = reset ? 3 : $.snake.lives;
		$("#stats-lives").html($.snake.lives);

		// reset level cherries eaten and total
		$("#stats-eaten").html($.snake.cherriesEaten+"");
		$("#stats-totcherries").html(Level[$.snake.level][0].cherries);
		
		// remove any wall & snake segments
		$(".wall, .snakebody").remove();

		// hide the cherry
		$.snake.$cherry.hide();

		// update map message	
		$("#map-msg").hide().html("Level "+$.snake.level+"<small><br/>Pak <strong>"+Level[$.snake.level][0].cherries+"</strong> ballen</small>").fadeIn();

		setTimeout(function(){

			// hide map message
			$("#map-msg").fadeOut(500, function(){

				// hide overlay
				$.snake.$overlay.hide();

				// reset and generate wall
				$.snake.wallseg = {};
				$.snake.Wall.generate();
				
				// hide then reposition cherry
				$.snake.Cherry.generate(false);

				// reset, remove and re-append snake segments to map
				$.snake.seg = {length:Level[$.snake.level][0].length};
				for(var i=0;i<$.snake.seg.length;i++) {
					$.snake.seg[i] = $('<span class="snakebody '+i+'"></span>').appendTo($.snake.$map);
					$.snake.seg[i].top = $.snake.seg[i].left = 0;
				}
				$(".snake").show();
				
				// start animation
				setTimeout(function(){
					// reset direction and speed
					$.snake.cache.keyCode[0] = 0;
					$.snake.cache.keyCode[1] = 39;
					$.snake.speed = 200;
					$.snake.start();
				}, 1000);
			});
		}, 1800);
	},
			
	animate : function() {			
		// adjust segment position list	 					
		for(var i=1;i<$.snake.seg.length;i++) {
			$.snake.seg[i].top = $.snake.seg[(i==$.snake.seg.length-1?0:i+1)].top;
			$.snake.seg[i].left = $.snake.seg[(i==$.snake.seg.length-1?0:i+1)].left;
		}

		var keycode = $.snake.cache.keyCode;
		if (
			keycode[0] == 37 && keycode[1] == 39 || 
			keycode[0] == 39 && keycode[1] == 37 || 
			keycode[0] == 38 && keycode[1] == 40 || 
			keycode[0] == 40 && keycode[1] == 38
		) {
			$.snake.cache.keyCode[1] = $.snake.cache.keyCode[0];
		}

		keycode = $.snake.cache.keyCode[1];
		// adjust leading segment properties
		if (keycode == 39) {
			//right
			$.snake.seg[0].left += $.snake.gridsize;
			if ($.snake.seg[0].left > $.snake.$map.width-$.snake.gridsize) {
				$.snake.wall && $.snake.gameOver();
				$.snake.seg[0].left = 0;
			}			
		}else if (keycode == 40) {
			//down
			$.snake.seg[0].top += $.snake.gridsize;
			if ($.snake.seg[0].top > $.snake.$map.height-$.snake.gridsize) {
				$.snake.wall && $.snake.gameOver();
				$.snake.seg[0].top = 0;
			}
		} else if (keycode == 38) {
			//up
			$.snake.seg[0].top -= $.snake.gridsize;
			if ($.snake.seg[0].top < 0) {
				$.snake.wall && $.snake.gameOver();
				$.snake.seg[0].top = $.snake.$map.height-$.snake.gridsize;
			}
		} else if (keycode == 37) {
			//left
			$.snake.seg[0].left -= $.snake.gridsize;
			if ($.snake.seg[0].left < 0) {
				$.snake.wall && $.snake.gameOver();
				$.snake.seg[0].left = $.snake.$map.width-$.snake.gridsize;
			}			
		}
		// check if snake has eaten a cherry
		($.snake.seg[0].left == $.snake.Cherry.left && $.snake.seg[0].top == $.snake.Cherry.top) && 
			$.snake.advance();
		
		// unset $.snake.seg[0], gotta be an easier way!
		var seg = {};
		for(var i=1;i< $.snake.seg.length;i++) {seg[i-1]=$.snake.seg[i];}	
		
		// check if snake has slithered into itself
		($.snake.in_obj($.snake.seg[0], seg)) && 
			$.snake.gameOver();

		// check if snake has slithered into a wall obstacle
		($.snake.in_obj($.snake.seg[0], $.snake.wallseg)) && 
			$.snake.gameOver();

		// check if cherries eaten match total: finished level.. advance to next level
		// TODO: Should not be using $.snake.score : need a variable to hold cherries eaten!!!!!!!!!
		($.snake.cherriesEaten == Level[$.snake.level][0].cherries) &&
			$.snake.advanceLevel();

		// reposition snake segments on map
		for(var i=0;i<$.snake.seg.length;i++) {
			$.snake.seg[i].css({top:$.snake.seg[i].top+"px",left:$.snake.seg[i].left+"px",display:"block"});
		}						
	},
			
	advance : function(val) {
		
		// increase snake segments
		$.snake.seg.length++;

		var x = $.snake.seg.length-1;
		$.snake.seg[x] = 
		$('<span class="snakebody '+x+'"></span>')
		.css({left:$.snake.seg[1].left+"px",top:$.snake.seg[1].top+"px",display:"block"})
		.appendTo($.snake.$map);
		
		// position new snake segment
		$.snake.seg[x].top = $.snake.seg[x-1].top;
		$.snake.seg[x].left = $.snake.seg[x-1].left;
		
		// reposition cherry
		$.snake.Cherry.generate();

		// adjust score
		$.snake.score += 10;
		$("#stats-score").html($.snake.score);

		// update cherries eaten
		$.snake.cherriesEaten++;
		$("#stats-eaten").html($.snake.cherriesEaten);
		
		// adjust speed
		$.snake.speed -= 1;
		$("#stats-speed").html($.snake.speed);
		clearInterval($.snake.animateTimer);
		$.snake.animateTimer = setInterval($.snake.animate, $.snake.speed);			
		return false;
	},

	advanceLevel : function() {
		if ($.snake.level == Level.length-1) {
			$.snake.finishedGame();	
		} else {
			$.snake.level++;
			$.snake.newGame();
		}
	},
			
	toggleGrid : function(){
		var background;
		if (!$.snake.grid) {
			$.snake.grid = 1;
		} else {
			background = "none";
			$.snake.grid = 0;
		}
		$.snake.$map.css({background:background});
	},
	
	pause : function(){
		if ($.snake.animateTimer == 0) {
			$.snake.start();
			$.snake.$overlay.hide();
			$("#map-msg").fadeOut();
		} else {
			clearInterval($.snake.animateTimer);
			$.snake.animateTimer = 0;
			$.snake.$overlay.show();
			$("#map-msg").html("Pause").fadeIn();
		}
	},

	gameOver : function(){
		if ($.snake.lives-1) {
			$.snake.lives--;
			$.snake.newGame();
		} else {
			$.snake.pause();
			$("#map-msg").html('Je bent af, druk op start om nog een keer te spelen');
		}
	},

	finishedGame : function(){
		$.snake.pause();
		$("#map-msg").html('Gefelificteerd, je hebt het spel uitgespeeld, druk op start om nog een keer te spelen');
	},

	Cherry : {	
		left : 0,
		top : 0,
		generate : function(show){
			do {	 
				$.snake.Cherry.left = Math.round((Math.random()*($.snake.$map.width-$.snake.gridsize))/$.snake.gridsize)*$.snake.gridsize;
				$.snake.Cherry.top = Math.round((Math.random()*($.snake.$map.height-$.snake.gridsize))/$.snake.gridsize)*$.snake.gridsize;
			} while ($.snake.in_obj($.snake.Cherry, $.snake.wallseg) || $.snake.in_obj($.snake.Cherry, $.snake.seg));
			
			$.snake.$cherry.css({
				left:$.snake.Cherry.left+"px",
				top:$.snake.Cherry.top+"px"
			});
			show == undefined && $.snake.$cherry.fadeIn();
		}

	},

	// wall obstacles
	Wall : {
		generate : function(){

			var 
				walls = Level[$.snake.level],
				c = 0, t, l, i, n;
	
			// append multiple walls
			for(i=1;i<walls.length;i++) {
				t = walls[i].top;
				l = walls[i].left;
				// append wall segments to map
				for(n=0;n<walls[i].seg;n++) {
					$.snake.wallseg[c] = $('<span class="wall '+c+'"></span>').css({top:t+"px",left:l+"px"}).appendTo($.snake.$map);
					$.snake.wallseg[c].left = l;
					$.snake.wallseg[c].top = t;
					c ++;
					t += $.snake.gridsize;
				}
			}
		}

	},

	// check for an object in an object collection
	in_obj : function(obj_needle, obj_haystack) {
		for(var i in obj_haystack) {
			if (obj_haystack[i].left === obj_needle.left && obj_haystack[i].top === obj_needle.top){
				return true;
			}
		}
		return false;
	}

},

Level = [
	,
	[
		{cherries : 10, length : 10},
		{seg : 14, top : 80, left : 220}
	],
	[
		{cherries : 20, length : 15},
		{seg : 14, top : 80, left : 120},
		{seg : 14, top : 80, left : 360}
	],
	[
		{cherries : 40, length : 20},
		{seg : 7, top : 40, left : 60},
		{seg : 7, top : 40, left : 400},
		{seg : 7, top : 260, left : 400},
		{seg : 7, top : 260, left : 60},
		{seg : 14, top : 80, left : 220}
	],
	[
		{cherries : 80, length : 25},
		{seg : 7, top : 40, left : 220},
		{seg : 7, top : 260, left : 220},
		{seg : 22, top : 0, left : 0},
		{seg : 22, top : 0, left : 460}
	],
	[
		{cherries : 200, length : 30},
		{seg : 11, top : 20, left : 80},
		{seg : 11, top : 20, left : 200},
		{seg : 11, top : 20, left : 320},
		{seg : 11, top : 20, left : 440},
		{seg : 11, top : 200, left : 20},
		{seg : 11, top : 200, left : 140},
		{seg : 11, top : 200, left : 260},
		{seg : 11, top : 200, left : 380}
	],
	[
		{cherries : 500, length : 35},
		{seg : 1, top : 20, left : 240},
		{seg : 1, top : 60, left : 240},
		{seg : 1, top : 100, left : 240},
		{seg : 1, top : 140, left : 240},
		{seg : 1, top : 180, left : 240},
		{seg : 1, top : 220, left : 240},
		{seg : 1, top : 260, left : 240},
		{seg : 1, top : 300, left : 240},
		{seg : 1, top : 340, left : 240},
		{seg : 1, top : 380, left : 240},
		{seg : 1, top : 420, left : 240},
		{seg : 10, top : 120, left : 300},
		{seg : 10, top : 120, left : 160},
		{seg : 16, top : 60, left : 80},
		{seg : 16, top : 60, left : 380},
		{seg : 22, top : 0, left : 0},
		{seg : 22, top : 0, left : 460}
	]
];

$(document).ready(function () {
	$(".snake").each(function () {
		$.snake.setup();
	})
});

})(jQuery);
