﻿/// <reference path="jquery-1.4.1.js" />

function Cell(x, y)
{
    this.column = x;
    this.row = y;

    this.currentState = false;
    this.nextState = false;
    this.neighbours = 0;

    this.Position = function() { return this.column + 'x' + this.row; }
    this.IsChanged = function() { return this.nextState != this.currentState; }
    this.SetChanged = function() { this.currentState = this.nextState; }
    this.SetNeighbours = function(amount)
    {
        if (this.currentState == true)
        {
            if (amount != 2 && amount != 3) this.nextState = false;
            else this.nextState = true;
        }
        else
        {
            if (amount == 3) this.nextState = true;
            else this.nextState = false;
        }

        this.neighbours = amount;
    };
}

function GameOfLifeRenderer(container, columns, rows)
{
    this.columns = 50;
    this.rows = 30;

    if (typeof (columns) == 'number' && columns >= 50) this.columns = columns;
    if (typeof (rows) == 'number' && rows >= 30) this.rows = rows;


    this.container = container;

    this.gol = new GameOfLifeLogic(this.columns, this.rows);

    var htmlString = '<table id="grid" class="big">';
    for (var j = 0; j < this.rows; j++)
    {
        htmlString += '<tr>';
        for (var i = 0; i < this.columns; i++)
        {
            htmlString += '<td id="' + i + 'x' + j + '"></td>';
        }
        htmlString += '</tr>';
    }
    $('#' + container).html(htmlString);

    $('#container').width($('#grid').width());
}

GameOfLifeRenderer.prototype.SetShape = function(shapeName)
{
    this.gol.LoadShape(shapeName);
    $('#grid tbody tr td').removeClass('full');
    this.DrawInit();
}

GameOfLifeRenderer.prototype.DrawInit = function()
{
    this.Draw();
}

GameOfLifeRenderer.prototype.DrawNext = function()
{
    this.gol.Advance();
    this.Draw();
}

GameOfLifeRenderer.prototype.Draw = function()
{
    for (var i = 0; i < this.columns; i++)
    {
        for (var j = 0; j < this.rows; j++)
        {
            if (this.gol.shape[i][j].IsChanged())
            {
                $('#grid tbody tr td#' + this.gol.shape[i][j].Position()).toggleClass('full');
                this.gol.shape[i][j].SetChanged();
            }
        }
    }
}

GameOfLifeRenderer.prototype.ClickCell = function(cell)
{
    if (cell.id.indexOf('x') > -1)
    {
        var coords = cell.id.split('x');
        if (coords.length == 2)
        {
            var x = coords[0];
            var y = coords[1];

            if (!isNaN(x) && !isNaN(y))
            {
                this.gol.ClickCell(x, y);
                $(cell).toggleClass('full');
            }
        }
    }
}

function GameOfLifeLogic(cols, rows)
{
    this.columns = cols;
    this.rows = rows;

    this.LoadShape('glider');
}

GameOfLifeLogic.prototype.LoadShape = function(shapeName)
{

    this.shape = new Array(this.columns);

    for (var i = 0; i < this.columns; i++)
    {
        this.shape[i] = new Array(this.rows);
        for (var j = 0; j < this.rows; j++)
        {
            this.shape[i][j] = new Cell(i, j);
            this.shape[i][j].currentState = false;
            this.shape[i][j].nextState = false;
        }
    }

    var coords;
    switch (shapeName)
    {
        case 'clear':
            coords = [];
            break;
        default:
        case 'glider':
            coords = [[24, 13], [25, 14], [23, 15], [24, 15], [25, 15]];
            break;
        case 'small exploder':
            coords = [[24, 13], [23, 14], [24, 14], [25, 14], [23, 15], [25, 15], [24, 16]];
            break;
        case 'exploder':
            coords = [[22, 12], [24, 12], [26, 12], [22, 13], [26, 13], [22, 14], [26, 14], [22, 15], [26, 15], [22, 16], [24, 16], [26, 16]];
            break;
        case '10 cell row':
            coords = [[19, 14], [20, 14], [21, 14], [22, 14], [23, 14], [24, 14], [25, 14], [26, 14], [27, 14], [28, 14]];
            break;
    }
    this.LoadShapeByCoords(coords);
}

GameOfLifeLogic.prototype.LoadShapeByCoords = function(coords)
{
    for (var i = 0; i < coords.length; i++)
    {
        this.shape[coords[i][0]][coords[i][1]].nextState = true;
    }
}

GameOfLifeLogic.prototype.ClickCell = function(x, y)
{
    this.shape[x][y].currentState = !this.shape[x][y].currentState;
    this.shape[x][y].nextState = this.shape[x][y].currentState;
}

GameOfLifeLogic.prototype.Advance = function()
{
    for (var i = 0; i < this.columns; i++)
    {
        for (var j = 0; j < this.rows; j++)
        {
            var neighbours = 0;

            neighbours += this.GetPopulationSizeOfCell(i - 1, j - 1);
            neighbours += this.GetPopulationSizeOfCell(i, j - 1);
            neighbours += this.GetPopulationSizeOfCell(i + 1, j - 1);
            neighbours += this.GetPopulationSizeOfCell(i - 1, j);
            neighbours += this.GetPopulationSizeOfCell(i + 1, j);
            neighbours += this.GetPopulationSizeOfCell(i - 1, j + 1);
            neighbours += this.GetPopulationSizeOfCell(i, j + 1);
            neighbours += this.GetPopulationSizeOfCell(i + 1, j + 1);

            this.shape[i][j].SetNeighbours(neighbours);
        }
    }
}

GameOfLifeLogic.prototype.GetPopulationSizeOfCell = function(x, y)
{
    if (x < 0 || x >= this.columns || y < 0 || y >= this.rows) return 0;
    else
    {
        if (this.shape[x][y].currentState == true) return 1;
        else return 0;
    }
}
