/**
 * @author karl
 */
lifeViewer = function(container, xCells, yCells){
	var el = $(container);
	
	var width = el.getWidth();
	var height = el.getHeight();
	
	var cellWidth = Math.floor(width / xCells);
	var cellHeight = Math.floor(height / yCells);
	var total = xCells * yCells;
	
	var cells = new life(xCells, yCells);
	var divs = new Array(total);
	
	var timer;
	
	var update = function(theDiv, theVal){
		if (theVal == 0) {
			theDiv.setStyle({'backgroundColor': '#fff'});
		} else {
			theDiv.setStyle({'backgroundColor': '#000'});			
		}
	}
	
	var i = 0;	
	for (var y=0; y < yCells; y++){
		for (var x = 0; x < xCells; x++) {
			divs[i] = new Element('div', {'class':'lifeCell', 'style':'height:' + cellHeight + 'px;width:' + cellWidth + 'px'});
			update(divs[i], cells.value(x, y));
			el.appendChild(divs[i]);
			i++;
		}
	}
	
	next = function(){
		cells.next();
		
		var i = 0;
		for (var y = 0; y < yCells; y++) {
			for (var x = 0; x < xCells; x++) {
				update(divs[i++], cells.value(x, y));
			}
		}
	}	
	
	this.step = function(){
		next();
	}	
	
	this.start = function(){
		timer = setInterval(next, 500);
	}
	
	this.stop = function(){
		clearInterval(timer);
	}
}

life = function(width, height){
	if (3 >= width || 3 >= height){
		throw "There must be at least 3x3 cells.";
	}
	
	var gen = 0; // generation number
	var cells1 = new Array(width * height); // cells buffer
	var cells2 = new Array(width * height); // cells buffer
	var current = cells1; // pointer to current generation buffer
	var next = cells2; // pointer to next generation buffer
		
	for (var i=0; i < cells1.length; i++){
		cells1[i] = Math.random() > 0.750 ? 1 : 0;
		cells2[i] = cells1[i];
	}
				
	this.next = function(){
		for(var y=0; y < height; y++){
			
			prevRow = ((y-1+height) % height) * width;
			nextRow = ((y+1) % height) * width;
			
			for (var x=0; x < width; x++){
				i = y * width + x;
				
				prevCol = (x-1+width)%width;
				nextCol = (x+1)%width;
				
				var neighbours = current[prevRow + prevCol] + current[prevRow + x] + current[prevRow + nextCol]
							   + current[y * width + prevCol] + current[y * width + nextCol]
							   + current[nextRow + prevCol] + current[nextRow + x] + current[nextRow + nextCol];
						
				next[i] = current[i];					 
				// dead cells with exactly 3 neighbours come to life
				if (0 == current[i] && 3 == neighbours){
					next[i] = 1;
				} else if ((1 == current[i]) && (2 > neighbours || 3 < neighbours)){
					// less than 2 neighbours => die
					// mode than 3 neighbours => die
					next[i] = 0;
				}
			}
		}
		
		// switch buffers for next generation
		var tmp = current;
		current = next;
		next = tmp;

		gen++;
	}
	
	this.value = function(x, y){
		return current[y * width + x];
	}
}

