/* 
 This file was generated by Dashcode.  
 You may edit this file to customize your widget or web page 
 according to the license.txt file included in the project.
 */

//
// Function: load()
// Called by HTML body element's onload event when the web application is ready to start
//
function load()
{
    dashcode.setupParts();
    setup();
    setTimeout(function() {window.scrollTo(0, 1) }, 100);
}

//Puzzler draws a grid with 15 columns and rows
var numberOfColumns = 14; //14 - iphone; 37 - iPad
var numberOfRows    = 15; //15 - iPhone  - 35 -iPad
var numberOfColors  = 5;

//The grid array contains numbers ranging from 1 to 5, which represent 5 different ball images.
var grid = [];

//The selected array contains either true or false. True indicates that the current cell is selected (a user clicked on the ball)
var selected = [];

//The dirty array contains either true or false values. True indicates that the current cell contains a grey ball
var dirty = [];
var allowClicks = true;

function addColumn(){
 if(numberOfColumns<14){
  removeColumnButton.style.opacity = 1;
  numberOfColumns++;
  setup();
 }
 
 if(numberOfColumns==14){
  addColumnButton.style.opacity = 0.5;
 }
}

function removeColumn(){
 if(numberOfColumns>1){
   addColumnButton.style.opacity = 1;
   numberOfColumns--;
   setup();
 }
 if(numberOfColumns == 1){
    removeColumnButton.style.opacity = 0.5;
 } 
}

function addColor(){
 if(numberOfColors<5){
  removeColorButton.style.opacity = 1;
  numberOfColors++;
  setup();
 }
 
if(numberOfColors==5){
  addColorButton.style.opacity = 0.5;
 }
}

function removeColor(){
 if(numberOfColors>2){
    addColorButton.style.opacity = 1;
    numberOfColors--;
    setup();
 }
  if(numberOfColors == 2){
    removeColorButton.style.opacity = 0.5;
 } 
}


//Remove all the DOM elements of the grid
function removeAllChildren (parent)
{
		while (parent.hasChildNodes()) 
		{
				parent.removeChild(parent.firstChild);
		}
}

//Initialize or Reinitialize the grid. Remove all balls on the grid.
function resetGrid()
{
		grid      = new Array(numberOfColumns);
		selected  = new Array(numberOfColumns);
		dirty     = new Array(numberOfColumns);
		
		for( var column=0; column< numberOfColumns; column++ )
		{
					grid[column]      = new Array(numberOfRows);
					selected[column]  = new Array(numberOfRows);
					dirty[column]     = new Array(numberOfRows);
					
					for( var row=0; row < numberOfRows; row++ )
					{
							 //Generate numbers ranging from 1 to 5 randomly. 
               // Yellow      = 1
               // Light Blue  = 2
               // Green       = 3
               // Dark Blue   = 4
               // Red         = 5
							var ballNumber= 1 + Math.floor(Math.random() * numberOfColors);
							grid[column][row] = ballNumber;
							
							//No ball is selected initially
							selected[column][row] = false;
							
							//The grid does contain any grey ball initially
							dirty[column][row] = false;
					}
		}
}


//Set up the game on the page using DOM elements
function setup()
{
		//Remove any current ball on the grid 
		resetGrid();
		
    if(numberOfColumns==14){
      addColumnButton.style.opacity = 0.5;
    }
    
		var gridTable = document.getElementById('grid');
		removeAllChildren(gridTable);
		
		//Loop thru the grid, Create 15 rows, add them to the grid.
		//For each row, generate 15 columns that contain each an image
		for( var row=0; row < numberOfRows; row++ ) 
		{
				//Create a row 
				var gridRow = document.createElement('tr'); 
				
				//Create 15 columns for the row generated above
				for( var column=0; column< numberOfColumns; column++ )
				{
							//Create a new column 
							var gridColumn = document.createElement('td');  
							
							//Create a new image 
							var img = document.createElement('img');        
							
							//Set the image attributes
							img.setAttribute("onclick", "click("+column+","+row+")");
							img.setAttribute("src", "images/ball-"+grid[column][row]+".png");
							img.setAttribute("id", column+"_"+row);
							img.setAttribute("numberOfColumns", 32);
							img.setAttribute("numberOfRows", 32);
							img.setAttribute("width", 20);
							img.setAttribute("height", 20);
							
							//Append the new image to this column 
							gridColumn.appendChild(img); 
							
							//Add this column to the curent row 
							gridRow.appendChild(gridColumn);          
				}
				//Add this row to the grid 
				gridTable.appendChild(gridRow);   
		}
}


//Update image at position represented by (column,row)
function updateCell(column,row)
{
		var newSrc;
		
		//Append a grey ball at the position given by (column, row) if the current ball is selected
		if( selected[column][row] )
		{
				newSrc = "images/ball-sel.png";
		}    
		else 
		{
				//Append a ball at the position given by (column, row) if the current ball is not selected
				//The color of the ball is determined by grid[column][row], which returns a number ranging from 1 to 5
				newSrc = "images/ball-"+grid[column][row]+".png"
		}        
		document.images[column+"_"+row].src = newSrc;
		}


//Update all images on the grid 
function updateAllCells()
{
		 //Loop thru all rows and columns, then update each image at position specified by column and row
		for( var row=0; row< numberOfRows; row++ ) 
		{
				for( var column= 0; column< numberOfColumns; column++ ) 
				{
						updateCell(column,row);
				}
		}
}


//Check the dirty array for any true value, if true is found at a position(column,row), update the associated cell
function updateAllDirtyCells()
{
		for( var row=0; row< numberOfRows; row++ )
		{
				for( var column=0; column< numberOfColumns; column++ )
				{
						if( dirty[column][row] ) 
						{
								//Place a grey ball at this position
								updateCell(column, row);
								dirty[column][row]= false;
						}
				}
		}
}


//Remove all selected balls on the grid 
function removeSelectedCells()
{

		for( var row=0; row< numberOfRows; row++ ) 
		{
				for( var column=0; column< numberOfColumns; column++ )
				{
						if( selected[column][row] ) 
						{
								//Remove the ball at this position
								grid[column][row] = 0;
								selected[column][row] = false;
								dirty[column][row] = true;
						}
				}
		}
}


//Look for empty cells along the vertical axis on the grid 
function fallDown()
{
		var fallTo,foundGap;
		for( var column= numberOfColumns-1; column >= 0; column-- ) 
		{
				//Indicate whether a ball at a given position is grey 
				foundGap = false;
				for( var row= numberOfRows-1; row >= 0; row-- )
				{
						 //Check if cell at position(column,row) is empty
						if( grid[column][row] == 0 ) 
						{
								if( ! foundGap )
								{
										//Get position (along the vertical axis) of the cell that contains a grey ball 
										fallTo = row;
										foundGap = true;
								}
						}
						else 
						{ 
								 //If cell contains a ball, check if the ball is grey 
								if( foundGap ) 
								{
										//Insert a new ball at this position  
										grid[column][fallTo] = grid[column][row];
										grid[column][row] = 0;
										dirty[column][fallTo] = true;
										dirty[column][row] = true;
										fallTo -= 1;
								}
						}
				}
		}
}


//Look for empty cells along the horizontal axis on the grid 
function fallRight()
{
		var fallTo,foundGap;
		for( var row= numberOfRows-1; row >= 0; row-- )
		{
				//Indicate whether a ball at a given position is grey 
				foundGap = false;
				for( var column= numberOfColumns-1; column >= 0; column-- ) 
				{
						//Check if cell at position(column,row) is empty
						if( grid[column][row] == 0 ) 
						{
								if( ! foundGap ) 
								{ 
										//Get position (along the horizontal axis) of the cell that contains a grey ball
										fallTo = column;
										foundGap = true;
								}
						}
						else 
						{ 
								//Check if cell at position(column,row) contains a grey ball
								if( foundGap) 
								{
										//Insert a new ball at this position  
										grid[fallTo][row] = grid[column][row];
										grid[column][row] = 0;
										dirty[fallTo][row] = true;
										dirty[column][row] = true;
										fallTo -= 1;
								}
						}
				}
		}
}


//Unselect all balls on the grid 
function deselectAllCells()
{
		for( var row= 0; row < numberOfRows; row++ ) 
		{
				for( var column= 0; column < numberOfColumns; column++ ) 
				{
						//Remove position from the selected array 
						if( selected[column][row] ) 
						{
								selected[column][row] = false;
								
								//Set value to true, so grey ball can be added at that position
								dirty[column][row] = true;
						}
				}
		}
}


//Determines whether each of the 4 neighbors(top,bottom,left, and right) of a
//cell is equal to that current cell
function cellHasIdenticalNeighbour(column, row)
{
		var cell = grid[column][row];
		if( ( column+1 < numberOfColumns  && cell == grid[column+1][row] )
			|| ( column-1 >= 0     && cell == grid[column-1][row] )
			|| ( row+1 < numberOfRows && cell == grid[column][row+1] )
			|| ( row-1 >= 0     && cell == grid[column][row-1] ) ) 
		{
				return true;
		}
		else 
		{
				return false;
		}
}


//Select all contiguous cells of the same color
function selectCellAndContiguousCells(cell, column, row)
{
		if( column >= 0 && column < numberOfColumns && row >= 0 && row < numberOfRows ) 
		{
				if( cell == grid[column][row] && ! selected[column][row] ) 
				{
						selected[column][row] = true;
						dirty[column][row] = true;
						selectCellAndContiguousCells( cell, column+1, row);
						selectCellAndContiguousCells( cell, column-1, row );
						selectCellAndContiguousCells( cell, column, row+1 );
						selectCellAndContiguousCells( cell, column, row-1 );
				}
		}
}


//Update cells along the horizontal axis
function fallRightAndAllowClicks()
{
		fallRight();
		updateAllDirtyCells();
		allowClicks = true;
}


//Update all cells on the grid
function fallDownThenFallRightAndAllowClicks()
{
		fallDown();
		updateAllDirtyCells();
		fallRightAndAllowClicks();
}


//Handle clicks on the grid 
function click(column, row)
{
		if( ! allowClicks )
		{
				return;
		}	
		
		// if a given cell is selected
		if( selected[column][row] )
		{
				// remove all selected cells
				removeSelectedCells();
				
				//Check the grid for selected values, then add grey balls at their positions
				updateAllDirtyCells();
				
				allowClicks = false;
				setTimeout("fallDownThenFallRightAndAllowClicks();", 100);
		}
		else if( grid[column][row] != 0 )
		{   
				//If a given cell is not selected, but contains a ball, deselect all cells
				deselectAllCells();
				
				//Check whether there is an adjacent cell of the same color
				if( cellHasIdenticalNeighbour(column,row ))
				{
						//select all contiguous cells of the same color
						selectCellAndContiguousCells( grid[column][row], column, row);
				}	
				updateAllDirtyCells();
		}
}
