// Copyright 2009, Acknack Ltd. All rights reserved.
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.


//---------------------------------------------------------------------
//Global Varialbes
//---------------------------------------------------------------------
var FINALS = function() {
    var globals = {
        COLOURS : [	"CF1D1D",//red
 					"1DCF34",//green
 					"221DCF",//blue
 					"E0EB15"//yellow
 					],
        SIZE : 10         
    }
    return { getValue : function(s) {
                return globals[s];
        }
    }
}();
var tempGameBoard = [];
var tempScore = 0;












//---------------------------------------------------------------------
//Google I/O
//---------------------------------------------------------------------

//Used for IO with google
var googleStateIO = function(){
	var delta = {};
	var cache = {};
	return {
		append: function(key, dat){
			delta[key] = dat;
			cache[key] = dat;
		},
		flush: function (){
			wave.getState().submitDelta(delta);
			delta = {};
			cache = {};
		},
		get: function(key) {
			if(cache[key] == undefined) {
				cache[key] = wave.getState().get(key);
			}
			return cache[key];
		}
	};
}();

var updatedStateIO = function(){
	var delta = {};
	return {
		get: function(key) {
			if(delta[key] == undefined) {
				delta[key] = wave.getState().get(key);
			}
			return delta[key];
		},
		updateComplete: function() {
			delta = {};
		}
	};
}();











//---------------------------------------------------------------------
//Google req. methods
//---------------------------------------------------------------------
 	
//Initialization
function init() {
	if (wave && wave.isInWaveContainer()) {
		wave.setStateCallback(stateUpdated);
	}
}

gadgets.util.registerOnLoadHandler(init);
  











//---------------------------------------------------------------------
//Updating status
//---------------------------------------------------------------------
function stateUpdated() {
	robotChanger();
	var documentCache = document;
	
	
	//Update players & scores
	//Player 1
	if(updatedStateIO.get("player1Id") !== null) {
		documentCache.getElementById('textP1').value = updatedStateIO.get("player1Id");
		documentCache.getElementById('butAddP1').disabled=true;
		documentCache.getElementById('p1Score').value = updatedStateIO.get("player1Score");
	}
	else
	{
		documentCache.getElementById('textP1').value = "";
		documentCache.getElementById('butAddP1').disabled=false;
		documentCache.getElementById('p1Score').value = "";
		documentCache.getElementById('instructions').value = "Select two players to start...";
	}
		
	//Player 2
	if(updatedStateIO.get("player2Id") !== null) {
		documentCache.getElementById('textP2').value = updatedStateIO.get("player2Id");
		documentCache.getElementById('butAddP2').disabled=true;
		documentCache.getElementById('p2Score').value = updatedStateIO.get("player2Score");
	}
	else
	{
		documentCache.getElementById('textP2').value = "";
		documentCache.getElementById('butAddP2').disabled=false;
		documentCache.getElementById('p2Score').value = "";
		documentCache.getElementById('instructions').value = 'Select two players to start...';
	}
	
	
	
	//Disable/enable colour buttons
	//Completely disable
	if(updatedStateIO.get("player1Id") === null || updatedStateIO.get("player2Id") === null) {//players not added
		documentCache.getElementById('butRed').disabled =true;
		documentCache.getElementById('butBlue').disabled =true;
		documentCache.getElementById('butGreen').disabled =true;
		documentCache.getElementById('butYellow').disabled =true;
		documentCache.getElementById('instructions').value = 'Select two players to start...';
	}
	else//Enable depending on turn
	{
		var currentTurn = parseInt(updatedStateIO.get("turn"));
		var currentViewerId = wave.getViewer().getId();
		//Disable players control
		if(currentTurn === 1 && currentViewerId !== updatedStateIO.get("player1Id")) {
			documentCache.getElementById('butRed').disabled =true;
			documentCache.getElementById('butBlue').disabled =true;
			documentCache.getElementById('butGreen').disabled =true;
			documentCache.getElementById('butYellow').disabled =true;
			documentCache.getElementById('instructions').value="Waiting for other player...";
		}
		if(currentTurn === 2 && currentViewerId !== updatedStateIO.get("player2Id")) {
			documentCache.getElementById('butRed').disabled =true;
			documentCache.getElementById('butBlue').disabled =true;
			documentCache.getElementById('butGreen').disabled =true;
			documentCache.getElementById('butYellow').disabled =true;
			documentCache.getElementById('instructions').value="Waiting for other player...";	
		}
		//Enable players control
		if(currentTurn === 1 && currentViewerId === updatedStateIO.get("player1Id")) {
			documentCache.getElementById('butRed').disabled =false;
			documentCache.getElementById('butBlue').disabled =false;
			documentCache.getElementById('butGreen').disabled =false;
			documentCache.getElementById('butYellow').disabled =false;
			documentCache.getElementById('instructions').value="Your turn...";
		}
		if(currentTurn === 2 && currentViewerId === updatedStateIO.get("player2Id")) {
			documentCache.getElementById('butRed').disabled =false;
			documentCache.getElementById('butBlue').disabled =false;
			documentCache.getElementById('butGreen').disabled =false;
			documentCache.getElementById('butYellow').disabled =false;
			documentCache.getElementById('instructions').value="Your turn...";	
		}
	
	
	
		//Update the game board
		for(var x = 0; x < FINALS.getValue("SIZE"); x++) {
			for(var y = 0; y < FINALS.getValue("SIZE"); y++) {
				documentCache.getElementById("c" + x + "" + y).bgColor = updatedStateIO.get("r" + x + "" + y);
			}	
		}
		
		
		//Update if someone has won
		if(parseInt(updatedStateIO.get("winner")) !== -1) {
			documentCache.getElementById('butRed').disabled =true;
			documentCache.getElementById('butBlue').disabled =true;
			documentCache.getElementById('butGreen').disabled =true;
			documentCache.getElementById('butYellow').disabled =true;
			
			if(updatedStateIO.get("winner") === "0") {
				documentCache.getElementById('instructions').value="Draw! Press reset to play again.";
			}
			else if(updatedStateIO.get("winner") === "1") {
				if(wave.getViewer().getId() === updatedStateIO.get("player1Id")) {
					documentCache.getElementById('instructions').value="Congratualtions you win! Press reset to play again.";
				}
				else {
					documentCache.getElementById('instructions').value="Sorry you lose. Press reset to play again.";
				}
			}
			else {
				if(wave.getViewer().getId() === updatedStateIO.get("player2Id")) {
					documentCache.getElementById('instructions').value="Congratualtions you win! Press reset to play again.";
				}
				else {
					documentCache.getElementById('instructions').value="Sorry you lose. Press reset to play again.";
				}
			}
		}
	}
	
	document = documentCache;
	updatedStateIO.updateComplete();
}

//@@@@@@@@@@@@@@@@@@@@ Method ready for when google finishes the api
//Lets the robot change & play
function robotChanger() {
	//**googleStateIO.append can CAREFULLY be used in here. Provided a flush is run before method ends**
	//Set game up if required
	if(updatedStateIO.get("robotPlayer") !== null && updatedStateIO.get("needToSetup") !== null) {
		if(updatedStateIO.get("player1Id") !== null) {
			googleStateIO.append("needToSetup", null);
			newGame(false);
			googleStateIO.flush();
		}
	}
	
	//If its the robots turn make the modifications
	if(updatedStateIO.get("robotPlayer") !== null && updatedStateIO.get("turn") === "2") {
		if(updatedStateIO.get("robotRed") !== null) {
			googleStateIO.append("robotRed", null);
			redClicked();
		}
		else if(updatedStateIO.get("robotGreen") !== null) {
			googleStateIO.append("robotGreen", null);
			greenClicked();
		}
		else if(updatedStateIO.get("robotBlue") !== null) {
			googleStateIO.append("robotBlue", null);
			blueClicked();
		}
		else if(updatedStateIO.get("robotYellow") !== null) {
			googleStateIO.append("robotYellow", null);
			yellowClicked();
		}
	}
}









//---------------------------------------------------------------------
//Button calls
//---------------------------------------------------------------------
function redClicked(){
	newMove(FINALS.getValue("COLOURS")[0]);
	googleStateIO.flush();
}

function greenClicked(){
	newMove(FINALS.getValue("COLOURS")[1]);
	googleStateIO.flush();
}

function blueClicked(){
	newMove(FINALS.getValue("COLOURS")[2]);
	googleStateIO.flush();
}

function yellowClicked(){
	newMove(FINALS.getValue("COLOURS")[3]);
	googleStateIO.flush();
}

function addP1Clicked() {
	//Check two players are not the same
	var player1Id = wave.getViewer().getId();
	var player2Id = googleStateIO.get("player2Id");
	if(player1Id === player2Id) {
		return;	
	}
	
	//Set the new player
	googleStateIO.append('player1Id', player1Id);
	
	//If two players are present start the game
	if(player2Id !== null) {
		newGame(false);
	}
	
	googleStateIO.flush();
}

function addP2Clicked() {
	//Check two players are not the same
	var player1Id = googleStateIO.get("player1Id");
	var player2Id = wave.getViewer().getId();
	if(player1Id === player2Id) {
		return;	
	}
	
	//Set the new player
	googleStateIO.append('player2Id', player2Id);
	
	//If two players are present start the game
	if(player1Id !== null) {
		newGame(false);
	}
	
	googleStateIO.flush();
}

function resetClicked() {
	newGame(true);
	
	googleStateIO.flush();
}






//---------------------------------------------------------------------
//Support methods
//---------------------------------------------------------------------

//Resets everything to defaults for new game
function newGame(isReset) {
	//set players as null
	if(isReset === true)
	{
		googleStateIO.append('player1Id', null);
		googleStateIO.append('player2Id', null);
	}
	googleStateIO.append('player1Score', '0');
	googleStateIO.append('player2Score', '0');
	googleStateIO.append('turn', Math.floor(Math.random()*2)+1);//TODO rand
	googleStateIO.append('winner', '-1');
	newRandomGrid();
}


//Generates a random grid of colours
function newRandomGrid(){
	for(var x = 0; x < FINALS.getValue("SIZE"); x++) {
		for(var y = 0; y < FINALS.getValue("SIZE"); y++) {
			googleStateIO.append("r" + x + "" + y, 
				FINALS.getValue("COLOURS")[Math.floor(Math.random()*FINALS.getValue("COLOURS").length)]);
		}	
	}
}

//changes the turn
function newTurn() {
	if(parseInt(googleStateIO.get('turn')) === 1) {
		googleStateIO.append('turn', "2");
	}
	else {
		googleStateIO.append('turn', "1");
	}
}


//executes a new move by launching the fill algorithm correctly
function newMove(newCol) {
	
	//Prevents infinite loop when same colour is chosen
	if(newCol !== googleStateIO.get("r00"))
	{
		//Fill the new game board
		tempGameBoard = [];
		
		
		//initilize the temp array
		for(var i = 0; i < FINALS.getValue("SIZE"); i++) {
			tempGameBoard[i] = [];	
		}
		
		//Get the values from googleWave into temp array
		for(var x = 0; x < FINALS.getValue("SIZE"); x++){
			for(var y = 0; y < FINALS.getValue("SIZE"); y++){
				tempGameBoard[x][y] = googleStateIO.get("r" + x + "" + y);
			}
		}
		
		//Run the algorithm on the temp array
		floodFill(newCol, 0, 0);
	
		//Move the changes into array ready for submission
		for(var x = 0; x < FINALS.getValue("SIZE"); x++){
			for(var y = 0; y < FINALS.getValue("SIZE"); y++){
				googleStateIO.append("r" + x + "" + y, tempGameBoard[x][y])
			}
		}
		
	}	
		
	//Work out the score
	calculateScore();	
	//Work out if that move won the game
	winner();
	//Change the persons turn
	newTurn();
}


//Fill algorithm
function floodFill(newCol, x, y) {
	
	//1. If the color of node is not equal to target-color, return.	
	if(tempGameBoard[x][y] !== googleStateIO.get("r00")) {
		return;
	}
	//2. Set the color of node to replacement-color.
	tempGameBoard[x][y] = newCol;
	tempScore += 1;
	//3. Perform Flood-fill (one step to the west of node, target-color, replacement-color).
	if(x > 0) {
		floodFill(newCol, x-1, y);	
	}
	//Perform Flood-fill (one step to the east of node, target-color, replacement-color).
	if(x < FINALS.getValue("SIZE")-1) {
		floodFill(newCol, x+1, y);
	}
	//Perform Flood-fill (one step to the north of node, target-color, replacement-color).
	if(y > 0) {
		floodFill(newCol, x, y-1);	
	}
	//Perform Flood-fill (one step to the south of node, target-color, replacement-color).
	if(y < FINALS.getValue("SIZE")-1) {
		floodFill(newCol, x, y+1);	
	}
	//4. Return.
	return;
}


//Calculates the score of current turn
function calculateScore() {
	//------------------
	//Work out the score
	//This is an inefficient method-- a better one should be sought
	tempScore = 0;
	
	//Run the algorithm on the temp array
	floodFill("E0EB16", 0, 0);//make sure E0EB16 is not used in program, otherwise bad things will happen
	
	if(parseInt(googleStateIO.get('turn')) === 1) {
		googleStateIO.append('player1Score', 
			tempScore + parseInt(googleStateIO.get('player1Score')));
	}
	else {
		googleStateIO.append('player2Score', 
			tempScore + parseInt(googleStateIO.get('player2Score')));
	}
	
}


//Works out if the game has been completed
function winner() {
	for(var x = 0; x < FINALS.getValue("SIZE"); x++){
		for(var y = 0; y < FINALS.getValue("SIZE"); y++){
			if(googleStateIO.get("r" + x + "" + y) !== googleStateIO.get("r00")) {
				return;//A block is not the same
			}
		}
	}
	//The game has been won
	var player1Score = parseInt(googleStateIO.get('player1Score'));
	var player2Score = parseInt(googleStateIO.get('player2Score'));
	
	if(player1Score === player2Score) {
		googleStateIO.append('winner', '0');
	}
	else if (player1Score > player2Score) {
		googleStateIO.append('winner', '1');
	}
	else {
		googleStateIO.append('winner', '2');
	}
	
}






//@@@@@@@@@@@@@@@@@@@@ Testing Methods ready for when google finishes the api

//---------------------------------------------------------------------
//Some testing stuff
//---------------------------------------------------------------------
function robotSetup() {
	googleStateIO.append("robotPlayer", "true");
	googleStateIO.append("player2Id", "flooditrobot@appspot.com");
	googleStateIO.append("needToSetup", "true");
	
	googleStateIO.flush();
}

function robotRed() {

	googleStateIO.append("robotRed", "true");
	googleStateIO.flush();
}

function robotBlue() {

	googleStateIO.append("robotBlue", "true");
	googleStateIO.flush();
}

function robotGreen() {
	googleStateIO.append("robotGreen", "true");
	
	googleStateIO.flush();
}

function robotYellow() {

	googleStateIO.append("robotYellow", "true");
	googleStateIO.flush();
}
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@--Untested^