var gameSizes = {9: 3, 16: 4, 25: 5, 36: 6};
var gameSizeList = [3, 4, 5, 6];
var gameTypes = ['3x3', '4x4', '5x5', '6x6'];
var clickPatterns = {
	 0: 
	[0,0,0
	,0,1,0
	,0,0,0]
	,1:
	[0,0,0
	,1,1,1
	,0,0,0]
	,2:
	[0,1,0
	,0,1,0
	,0,1,0]
	,3:
	[0,1,0
	,1,1,1
	,0,1,0]
	,4:
	[1,1,1
	,1,1,1
	,1,1,1]
};

function setOverlay(message){
	if(!(go = $('gameoverlay'))) return;
	if(message){
		$('overlaycontent').innerHTML = message;
		go.setStyle('display','block');
	}else{
		go.setStyle('display','none');
	}
}

var UpDownGame = new Class({
	 gameServer: null
	// STATUS
	,loading: false
 	,loaded: false
 	,buttonsLoading: false
 	,buttonsLoaded: false
	,running: false
	,isWon: false
	,editMode: false
	
 	,buttonIds: []
 	,buttonById: {}
 	,moveCounter: 0
 	,startTime: null
 	,gameElem: null
 	,counterElem: null
 	,timerElem: null
 	,gameWinCallBack: null
	,boardSize: 0
	,gameData: []
	,movesMade: []
	,currentTime: 0
	,gameSize: 0
	,btnSize: 0
	
	,imgLoaders: null
 	
	,initialize: function(){
		this.gameServer = new UpDownGameServer(this);
	}
	,showStats: function(stats){
		if(!(gs = $('gamestats'))) return;
		if(!stats){
			statsMessage = "<p>You are the <em>first</em> to play today's "+this.boardSize+"x"+this.boardSize+" puzzle.</p>";
		}else{
			statsMessage = '<p>This puzzle has been played '+stats.play_count+' times and solved '+stats.solved_count+' times.</p>';
			if(stats.solved_count > 0){
				statsMessage += '<p style="font-weight: bold;">Best moves: '+stats.best_moves+' (avg: '+Math.round(stats.average_moves)+')<br>'
				statsMessage += 'Best time: '+stats.best_time+'s (avg: '+Math.round(stats.average_time*10)/10+'s)</p>';
			}
		}
		gs.innerHTML = statsMessage;
	}
	,loadGame: function(gameSize, gameId){
		if(pi = $('playinfo')) pi.setStyle('display', 'block');
		if(con = $('console')) con.setHTML('');
		this.gameSize = gameSize;
		this.stopGame();
		this.loading = true;
		this.drawLoader('Loading game...');
		this.gameServer.loadGame(this.gameSize, gameId, function(response){
			this.loading = false;
			this.setGame(response.gamedata)
			if(gt = $('gametitle')) gt.innerHTML = "Game of the Day "+response.size+'x'+response.size;
			this.showStats(response.stats);
			var icomId = this.gameData.join('');
			
			document={};
			instac_buttonHTML = '';
			document.write=function(s){instac_buttonHTML=s;};
			instac_button(88, icomId);
			instac_buttonHTML = instac_buttonHTML.replace(/(img src="[^"]*)(")/, "$1?nocache="+Math.round(Math.random()*1000000)+"$2");
			if(icom = $('instacomment')){icom.setHTML(instac_buttonHTML);}
//			instac_button_ajax(88, icomId, 'instacomment');
			
		}.bind(this));
	}
	,updateMove: function(button){
		if(button){
			this.movesMade.push({t: Math.round((new Date() - this.startTime)/1000), b: button.id.replace(/udb_([0-9])_([0-9])/,"$1$2")});
		}
		this.updateMoveCounter();
		if(this.running && this.checkGameWin()){
			this.stopGame();
		 	this.drawLoader('Submitting results...');
			if(this.gameWinCallback){
				this.isWon = true;
				this.gameWinCallback(this);
			}
		}
	}
	,stopGame: function(){
		if(this.isWon){
//			this.drawLoader('Congratulations, you won!');
		}else{
			this.drawLoader('Game Stopped');
		}
		clearInterval(this.timerInterval);
	 	this.running = false;
		this.isWon = 0;
		this.updateMove();
		this.updateTimer();
	}
	,startGame: function(){
		if(this.loaded && !this.running){
		 	this.running = true;
			this.isWon = false;
			this.timerInterval = setInterval(function(){this.updateTimer()}.bind(this),500);
			this.startTime = new Date();
		 	this.gameServer.startGame();
		 	this.movesMade = [];
		 	this.currentTime = 0;
			this.moveCounter = 0;
			this.updateTimer();
		}else{
			alert('UpDownGame.startGame: Game not loaded yet, or already running.');
		}
	}
	,submitGame: function(){
		if(!this.running && this.checkGameWin()){
			var moves=[];
			udGame.movesMade.each(function(m){
				moves.push(m.b+','+m.t);
			});
		 	this.gameServer.submitGame(moves.join(';'), function(response){
				setOverlay(response.message);
				this.showStats(response.stats);
			}.bind(this));
		}else{
			alert('Game not finished yet.');
		}
	}
	,voteGameImpossible: function(){
		if(this.running){
			if(!this.checkGameWin()){
				var moves=[];
				udGame.movesMade.each(function(m){
					moves.push(m.b+','+m.t);
				});
			 	this.gameServer.voteGameImpossible();
			}else{
				alert('Game won! Please submit results.');
			}
		}else{
			alert('Game not running.');
		}
	}
	,resetGame: function(){
		this.stopGame();
		this.drawLoader('');
		this.moveCounter = 0;
		this.currentTime = 0;
		this.updateMoveCounter();
		this.updateTimer();
		this.getButtonIds().each(function(bId){
			$(bId).removeClass('pressed');
		}.bind(this));
	}
	
	,startEditMode: function(){
		if(this.editMode)	return;
		this.editMode = true;
		var thisGame = this;
	  $$('.UpDownButton').action({
			 onclick: function(){
				button = $(this);
				var oldType = parseInt(thisGame.buttonById[button.id].type);
				var newType = (oldType+1) %5;
				thisGame.buttonById[button.id].type = newType
				button.removeClass('bType_'+oldType);
				button.addClass('bType_'+newType);
			}
	  	,onmouseover: function(){$(this).addClass('highlight');}
	  	,onmouseout: function(){$(this).removeClass('highlight');}
		});
	}
	,stopEditMode: function(){
		if(!this.editMode)	return;
		this.editMode = false;
		var thisGame = this;
	  $$('.UpDownButton').action({
	  	 onclick: function(){thisGame.buttonPressed(this)}
	  	,onmouseover: function(){thisGame.buttonHover(this)}
	  	,onmouseout: function(){thisGame.buttonHoverOff(this)}
	  });
	}
	
	,setGame: function(gameData){
		if($type(gameData)=='string'){gameData = gameData.split('');}
		this.gameData = gameData;
		this.boardSize = gameSizes[gameData.length];
		if(!this.boardSize) return;
		var i = 0;
		this.buttonIds = [];
    for(var row = 0; row < this.boardSize; row++){
	    this.buttonIds[row] = [];
		  for(var col = 0; col < this.boardSize; col++){
		  	var buttonId = 'udb_'+row+'_'+col;
		    this.buttonIds[row][col] = buttonId;
		  	this.buttonById[buttonId] = {row: row, col: col, type: gameData[i++]}
	    }
	  }
	 	this.loaded = true;
	 	this.running = false;
		this.draw();
	}
	,attachGameElem: function(gameElem){
		this.gameElem = $(gameElem);
		this.draw();
	}
	,attachCounterElem: function(counterElem){
		this.counterElem = $(counterElem);
	}
	,attachTimerElem: function(timerElem){
		this.timerElem = $(timerElem);
	}
	,setGameWinCallback: function(gameWinCallback){
		this.gameWinCallback = gameWinCallback;
	}
	,getButtonIds: function() {
		var buttonIds = [];
		this.buttonIds.each(function(row){row.each(function(bId){
			buttonIds.push(bId);
		})});
		return buttonIds;
	}
	,updateMoveCounter: function(){
		if(this.counterElem)
			this.counterElem.setHTML(this.moveCounter);
	}
	,updateTimer: function(){
		if(this.timerElem){
			if(this.running) {
				this.currentTime = Math.round((new Date() - this.startTime)/1000);
			}
			this.timerElem.setHTML(this.currentTime);
		}
	}
	,checkGameWin: function(){
		this.isWon = true;
		this.getButtonIds().each(function(bId){
			if(!$(bId).hasClass('pressed')) this.isWon = false;
		}.bind(this));
		return this.isWon;
	}
	,loadButtons: function() {
	 	this.buttonsLoading = true;
	 	this.buttonsLoaded = false;
	 	this.drawLoader('Loading buttons...');
		var totalPreloadCount = 0;
		var preloadCount = 0;
		this.imgLoaders = [];
		$$('.UpDownButton div').each(function(b){
			var ImageUrl = b.getStyle('background-image').replace(/url\("?(.*?)"?\)/,'$1');
			var imgIsLoading = false;
			// check if image is already loading.
			this.imgLoaders.each(function(imgLoader){
				if(imgLoader.src == ImageUrl){
					imgIsLoading = true;
				}
			});
			if(!imgIsLoading){
				preloadCount++;
				totalPreloadCount++;
				this.drawLoader('Loading buttons '+Math.round(((totalPreloadCount-preloadCount+1)/totalPreloadCount)*100)+'% ...');
				var img = new Image();
				img.onload = function(){
					this.drawLoader('Loading buttons '+Math.round(((totalPreloadCount-preloadCount+1)/totalPreloadCount)*100)+'% ...');
					preloadCount--;
					if(preloadCount == 0){
						this.drawLoader("");
					}
				}.bind(this);
				img.src = ImageUrl;
				this.imgLoaders.push(img);
			}
		}.bind(this));
	}
	,drawLoader: function(load_msg){
		if(load_msg == ''){
			setOverlay();
		}else{
			if(!load_msg)load_msg = 'loading...';
			var overlayMessage = '<div id="game_loader"><div><span>'+load_msg+'</span></div></div>';
			setOverlay(overlayMessage);
		}
	}
	,draw: function() {
		if(this.gameElem && this.loaded){
			var buttonHtml = [];
			this.getButtonIds().each(function(bId){
		  	buttonHtml.push('<div id="'+bId+'" class="UpDownButton bType_'+this.buttonById[bId].type+'"><div class="btn btnUp"><div class="btn hover"></div></div><div class="btn btnDown"><div class="btn hover"></div></div></div>');
			}.bind(this));
			var btnsize = this.btnSize==0?this.boardSize:this.btnSize;
			var gameClass = 'gamesize_'+this.boardSize+'_'+btnsize;
			gameClass += ' size_'+btnsize;
		  $('gamebox').className = gameClass;
		  this.gameElem.setHTML(buttonHtml.join(""));
		  var thisGame = this;
		  $$('.UpDownButton').action({
		  	 onclick: function(){thisGame.buttonPressed(this)}
		  	,onmouseover: function(){thisGame.buttonHover(this)}
		  	,onmouseout: function(){thisGame.buttonHoverOff(this)}
		  });
		  this.resetGame();
		  this.updateTimer();
			this.loadButtons();
		}
	}
	,buttonGetAffected: function(buttonId) {
		var b = this.buttonById[buttonId];
		var affectedButtons = [];
    for(var rr = -1; rr <= 1; rr++){
    	for(var cc = -1; cc <= 1; cc++){
    		var bRow = b.row + rr;
    		var bCol = b.col + cc;
    		if( (0 <= bRow && bRow < this.boardSize)
	    		&&(0 <= bCol && bCol < this.boardSize)
	    		&& clickPatterns[b.type][(rr+1)*3+(cc+1)]){
	    		var bId = 'udb_'+bRow+'_'+bCol;
	    		affectedButtons.push('udb_'+bRow+'_'+bCol);
    		}
    	}
    }
		return affectedButtons
	}
	,buttonHover: function(button) {
		this.buttonGetAffected(button.id).each(function(b){
			$(b).addClass('highlight');
		});
	}
	,buttonHoverOff: function(button) {
		this.getButtonIds().each(function(bId){
		  $(bId).removeClass('highlight');
		}.bind(this));
	}
	,buttonPressed: function(button) {
		if(!this.isWon){
			if(this.loaded && !this.running)
				this.startGame();
		 	if(this.running){
				button = $(button);
				this.buttonHoverOff(button);
				this.buttonGetAffected(button.id).each(function(b){
					$(b).toggleClass('pressed');
				});
		 		this.moveCounter++;
				this.updateMove(button);
			}else{
				alert('Press "Start Game" to start.');
			}
		}
	}
	,makeRandomGame: function(size) {
		var gameString = "";
		for(var i = 0; i < size * size; i++){
			gameString += Math.floor(Math.random() * 5);
		}
		return gameString;
	}
	,randomClick: function() {
		var buttonIds = this.getButtonIds()
		var rndId = buttonIds[Math.floor(Math.random() * buttonIds.length)];
		this.buttonPressed(rndId);
	}
	,getCurrentSolution: function(){
		var btns = [];
		this.movesMade.each(function(m){
			var idx = parseInt(m.b);
			btns[idx] = !btns[idx];
		});
		return btns
	}
});