var Conway = {

    ShowNeighboursNum: false, //sets if neighbours numbers should be displayed
    GridSize: null, //size of the game area
    Interval: 100, //update interval
    Points: [], //all points
    PointsToFlip: [], //Collection of points to flip in the next iteraton
    Timer: null, //Game Loop timer
    GridID: null,

    //Starts Game Loop
    Start: function() {
        clearInterval(Conway.Timer);
        Conway.Timer = self.setInterval("Conway.FlipPoints()", Conway.Interval);
    },

    //Stops Game Loop
    Stop: function() {
        clearInterval(Conway.Timer);
    },

    //Updates cells display in front-end
    UpdateDisplay: function() {
        for (var x = 0; x <= this.GridSize.width - 1; x++) {
            for (var y = 0; y <= this.GridSize.height - 1; y++) {
                var point = this.Points[x][y];

                $(this.GridID)[0].rows[point.X].cells[point.Y].style.background = (point.Active) ? "red" : "#ccc";

                if (this.ShowNeighboursNum) {
                    $(this.GridID)[0].rows[point.X].cells[point.Y].innerHTML = point.Neighbours();
                }
            }
        }
    },

    //Activates single point
    EnablePoint: function(x, y) {
        this.Points[x][y].Active = true;
    },

    //Activates many points
    EnablePoints: function(points) {
        $.each(points, function(i, val) {
            Conway.Points[val[0]][val[1]].Active = true;
        });
    },

    //Initializes the game
    Init: function(gridId) {
        this.GridID = gridId;
        this.GridSize = {
            width: $(this.GridID)[0].rows.length,
            height: $(this.GridID)[0].rows[0].cells.length
        };

        //reset all points
        this.Clear();
    },

    //Clears game area and resets all points
    Clear: function() {
        this.Points = [];
        this.PointsToFlip = [];

        for (var x = 0; x < this.GridSize.width; x++) {
            this.Points[x] = new Array(this.GridSize.height);
            for (var y = 0; y < this.GridSize.height; y++) {
                this.Points[x][y] = new Point(x, y);
            }
        }

        this.UpdateDisplay();
    },

    DemoInitPoints: [],
    Record: function() {
        //clear grid
        this.Stop();
        this.Init(this.GridID);
        this.DemoInitPoints = [];
        
        $(this.GridID + ' td').click(function() {
            var coord = { x: $(this)[0].parentNode.rowIndex, y: $(this)[0].cellIndex };

            //enable point
            if (!Conway.Points[coord.x][coord.y].Active) {
                $(this).css("background", "yellow");
                Conway.EnablePoint(coord.x, coord.y);
                Conway.DemoInitPoints.push(coord);
            }
        });
    },

    RecordingDone: function() {
        $(this.GridID + ' td').unbind('click');
        this.Start();
    },

    ResetRecording: function() {
        this.Stop();
        this.Clear();
        $.each(Conway.DemoInitPoints, function(i, val) {
            Conway.EnablePoint(val.x, val.y);
        });
        this.UpdateDisplay();
        this.Start();
    },

    //Changes the state of every point of the game
    FlipPoints: function() {

        //clear list of points to flip
        this.PointsToFlip = [];

        //loop through all points..
        for (var x = 0; x < this.GridSize.width; x++) {
            for (var y = 0; y < this.GridSize.height; y++) {
                var point = this.Points[x][y];
                var neighbours = point.Neighbours();

                //..apply main game rules
                if (point.Active && neighbours < 2) {
                    this.PointsToFlip.push({ point: this.Points[point.X][point.Y], active: false });
                }
                if (point.Active && neighbours > 3) {
                    this.PointsToFlip.push({ point: this.Points[point.X][point.Y], active: false });
                }
                if (!point.Active && neighbours == 3) {
                    this.PointsToFlip.push({ point: this.Points[point.X][point.Y], active: true });
                }
                if (point.Active && (neighbours == 2 || neighbours == 3)) {
                    this.PointsToFlip.push({ point: this.Points[point.X][point.Y], active: true });
                }
            }
        }

        for (var i = 0; i <= this.PointsToFlip.length - 1; i++) {
            this.PointsToFlip[i].point.Active = this.PointsToFlip[i].active;
        }
        this.UpdateDisplay();
    }
};

	//Main Cell Object
	var Point = function(x, y) {
		this.X = x;
		this.Y = y;
		this.Active = false;
		this.Neighbours = function() {
			var neighbours = [];

			//Checkingthe boundries and getting all 8 cells around current (X) cell:
			// ABC
			// DXE
			// FGH
			if (this.X >= 1) {
				neighbours.push(Conway.Points[x - 1][y]); //D
				if (this.Y <= Conway.GridSize.height - 2) { neighbours.push(Conway.Points[x - 1][y + 1]); } //A
				if (this.Y >= 1) { neighbours.push(Conway.Points[x - 1][y - 1]); } //F
			}
			if (this.X <= Conway.GridSize.width - 2) {
				neighbours.push(Conway.Points[x + 1][y]); //E
				if (this.X <= Conway.GridSize.width - 2 && this.Y <= Conway.GridSize.height - 2) { neighbours.push(Conway.Points[x + 1][y + 1]); } //C
				if (this.X <= Conway.GridSize.width - 2 && this.Y >= 1) { neighbours.push(Conway.Points[x + 1][y - 1]); } //H
			}
			if (this.Y >= 1) {	neighbours.push(Conway.Points[x][y-1]); } //G
			if (this.Y <= Conway.GridSize.height - 2) {	neighbours.push(Conway.Points[x][y+1]); } //B
			
			var count = 0;
			for (var i = 0; i < neighbours.length; i++) {
				if (neighbours[i] != undefined && neighbours[i].Active)
				{
					count++;
				}
			}
			return count;
		}
	};
