// wpfelife.js

var stepDelay = 250; // setInterval delay
var gridSize = 40;
var game = null;

function Cell()
{
    this.isAlive = false;
    if(Math.random() < 0.4)
    {
        this.isAlive = true;
    }
}

function CellCollection(size)
{
    // Uses three dimensional array 
    // [generation][x][y]    

    this.size = size;
    this.cells = new Array(2);
    this.cells[0] = new Array(size);
    this.cells[1] = new Array(size);
    
    var x, y;
    for(x = 0; x < size; x++)
    {
        this.cells[0][x] = new Array(size);
        this.cells[1][x] = new Array(size);
        for(y = 0; y < size; y++)
        {
           this.cells[0][x][y] = new Cell();
           this.cells[1][x][y] = new Cell();
        }
    }
    
    this.currentGeneration = 0;
    this.nextGeneration = 1;
}

CellCollection.prototype.CheckCell = function(generation, dx, dy)
{
    // if trying to check out of bounds, "wrap around" the grid 
    if(dx < 0) dx = this.size - 1;
    if(dx > this.size - 1) dx = 0;
    if(dy < 0) dy = this.size - 1;
    if(dy > this.size - 1) dy = 0;
       
    return this.cells[generation][dx][dy].isAlive; 
}

CellCollection.prototype.CountNeighbors = function(generation,x,y)
{    
    var count = 0;
    var size = this.size;
            
    if(this.CheckCell(generation, x-1, y-1))
        count++;   
    if(this.CheckCell(generation, x-1, y))
        count++;
    if(this.CheckCell(generation, x-1, y+1))
        count++;
    if(this.CheckCell(generation, x, y-1))
        count++;
    if(this.CheckCell(generation, x, y+1))
        count++;
    if(this.CheckCell(generation, x+1, y-1))
        count++;
    if(this.CheckCell(generation, x+1, y))
        count++;
    if(this.CheckCell(generation, x+1, y+1))
        count++;
          
    return count;
}

CellCollection.prototype.UpdateLife = function()
{
    
    var x, y;
    
    for(x = 0; x < this.size; x++)
    {
        for(y = 0; y < this.size; y++)
        {
            var neighbors = this.CountNeighbors(this.currentGeneration, x, y);
            
            // the basic rules of life:
            // 3 neighbors bring a dead cell to life
            // 2 or 3 neighbors keep a living cell alive
            // everything else stays dead, or dies
            
            if(!this.cells[this.currentGeneration][x][y].isAlive && neighbors == 3)
            {
                this.cells[this.nextGeneration][x][y].isAlive = true;
            }
            else if(this.cells[this.currentGeneration][x][y].isAlive && (neighbors == 2 || neighbors == 3))
            {
                this.cells[this.nextGeneration][x][y].isAlive = true;
            }
            else
            {
                this.cells[this.nextGeneration][x][y].isAlive = false;
            }
        }
    }
          
    if(this.currentGeneration == 1)
    {
        this.currentGeneration = 0;
        this.nextGeneration = 1;
    }
    else
    {
        this.currentGeneration = 1;
        this.nextGeneration = 0;
    }
}

CellCollection.prototype.isCellAlive = function(x, y)
{
    return this.cells[this.currentGeneration][x][y].isAlive;
}

CellCollection.prototype.size = function()
{
    return this.size;
}

// GameOfLife
function GameOfLife(agControl, cells)
{
    this.agControl = agControl;
    this.cells = cells;
    this.size = cells.size;
    this.timer = null;
    this.LayoutBoard();
    game = this;
}

GameOfLife.prototype.Start = function()
{  
    if(this.timer == null)
        this.timer = setInterval("TimerTick()", stepDelay);       
}

GameOfLife.prototype.Stop = function()
{
    if(this.timer != null)
    {
        clearInterval(this.timer);
        this.timer = null;
    }
}

GameOfLife.prototype.LayoutBoard = function()
{
    var x, y;
    var gameBoard = this.agControl.findName("gameBoard");
    
    this.ellipses = new Array(this.size);
    
    for(x = 0; x < this.size; x++)
    {
        this.ellipses[x] = new Array(this.size);
        
        for(y = 0; y < this.size; y++)
        {
            var ellipse = this.agControl.createFromXaml("<Ellipse/>");
            ellipse.Height = 10;
            ellipse.Width = 10;           
            ellipse.Fill = this.CreateBrush();
            ellipse.Opacity = this.cells.isCellAlive(x,y) ? 1 : 0.9;
            
            gameBoard.children.add(ellipse);
            
            ellipse["Canvas.Top"] = (this.agControl.height / this.size) * x;
            ellipse["Canvas.Left"] = (this.agControl.width / this.size) * y;
                     
            this.ellipses[x][y] = ellipse;            
        }
    }    
}

GameOfLife.prototype.CreateBrush = function()
{
	var r = Math.random();
    var xaml = '<RadialGradientBrush><GradientStop Color="White" Offset="0.0"/><GradientStop Color="Red" Offset="0.1" /><GradientStop Color="sc# 1,' + r + ',.9,0" Offset="0.9"/></RadialGradientBrush>';				
	return this.agControl.createFromXaml(xaml);
}

GameOfLife.prototype.NextStep = function()
{
    this.cells.UpdateLife();
    
    var x, y;
    
    for(x = 0; x < this.size; x++)
    {
        for(y = 0; y < this.size; y++)
        {
            this.ellipses[x][y].Opacity = this.cells.isCellAlive(x,y) ? 1 : 0.5;
        }
    }
}

function TimerTick()
{
    game.NextStep();
}

function gameBoardLoaded()
{
    var agControl = document.getElementById("agControl1");
    var cells = new CellCollection(gridSize);  
    var game = new GameOfLife(agControl, cells);
    game.Start();  
}
