var	cell_width = 4;
var	cell_height = 8;

var	width = 48;
var	height = 48;

var	delay = 1;

var	life = new Array(width);

var all_td;

var running = false;
var threads = 0;

var request_stop = false;
var paused = false;

DOM = (document.getElementById) ? 1 : 0;
Opera = (navigator.userAgent.indexOf("Opera") > -1) ? 1 : 0;
IE = (navigator.userAgent.indexOf("MSIE") > -1) ? 1 : 0;
IE = IE && !Opera;
IE4 = (document.all) ? 1 : 0;
IE4 = IE4 && IE && !DOM;

function get_element_by_id(name) {
  if (!IE4) {
    return document.getElementById(name);
  } else {
    return document.all(name);
  }
}

function cell() {
  this.age = 0;
  this.old_age = 1;
  this.neighbours = 0;
}

function SetCellImage(x, y) {
  v = life[x][y].age;
  table_cell = all_td[x + width * y];

  if (v == 0) {
    table_cell.style.background = "#E0E0E0";
  } else {
    table_cell.style.background = "#000000";
  }
}

function count_all_neighbours() {
  for(x = 0; x < width; x++) {
    life[x][         0].neighbours = count_neighbours(x, 0);
    life[x][height - 1].neighbours = count_neighbours(x, height - 1);
  }

  for(y = 1; y < height - 1; y++) {
    life[        0][y].neighbours = count_neighbours(0, y);
    life[width - 1][y].neighbours = count_neighbours(width - 1, y);
  }

  for(x = 1; x < width - 1; x++) {
    for(y = 1; y < height - 1; y++) {
      life[x][y].neighbours = count_neighbours(x, y);
    }
  }
}

function count_neighbours(x, y) {
  var result = 0;

  for(checkx = x - 1; checkx <= x + 1; checkx++) {
    for(checky = y - 1; checky <= y + 1; checky++) {
      cx = (checkx < 0) ? width  - 1 : ((checkx >= width ) ? 0 : checkx);
      cy = (checky < 0) ? height - 1 : ((checky >= height) ? 0 : checky);
      if ((cx != x) || (cy != y)) {
        result += life[cx][cy].age;
      }
    }
  }

  return result;
}

function count_neighbours_fast(x, y) {
  result =  life[x-1][y-1].age;
  result += life[x-1][y  ].age;
  result += life[x-1][y+1].age;

  result += life[x  ][y-1].age;
  result += life[x  ][y+1].age;

  result += life[x+1][y-1].age;
  result += life[x+1][y  ].age;
  result += life[x+1][y+1].age;

  return result;
}

function update_neighbour_counts(x, y, delta) {
  update_neighbour_count(x-1, y-1, delta);
  update_neighbour_count(x-1, y  , delta);
  update_neighbour_count(x-1, y+1, delta);

  update_neighbour_count(x  , y-1, delta);
  update_neighbour_count(x  , y+1, delta);

  update_neighbour_count(x+1, y-1, delta);
  update_neighbour_count(x+1, y  , delta);
  update_neighbour_count(x+1, y+1, delta);
}

function update_neighbour_count(x, y, delta) {
  if (x < 0) {
    x = width - 1;
  } else if (x >= width) {
    x = 0;
  }

  if (y < 0) {
    y = height - 1;
  } else if (y >= height) {
    y = 0;
  }

  current = life[x][y];

  current.neighbours = current.neighbours + delta;
}

function update_all() {
  for(x = 0; x < width; x++) {
    for(y = 0; y < height; y++) {
      update(x, y);
    }
  }
}

function update(x, y) {
  current = life[x][y];
  current.old_age = current.age;
  if(current.age == 0) {
    if(current.neighbours == 3) {
      current.age = 1;
    }
  } else {
    if((current.neighbours > 3) || (current.neighbours < 2)) {
      current.age = 0;
    }
  }
}

function render_updated() {
  for(x = 0; x < width; x++) {
    for(y = 0; y < height; y++) {
      current = life[x][y];
      if (current.old_age != current.age) {
        SetCellImage(x, y);
        update_neighbour_counts(x, y, current.age - current.old_age);
      }
    }
  }
}

function life_cycle() {
  if (running || (threads > 1)) {
    threads--;
    return;
  }

  running = true;

  update_all();

  render_updated();

  if (request_stop) {
    request_stop = false;
    threads--;
  } else {
    setTimeout("life_cycle()", delay);
  }

  running = false;
}

function render_all() {
  for(x = 0; x < width; x++) {
    for(y = 0; y < height; y++) {
      current = life[x][y];
      current.old_age = current.age ^ 1;
      SetCellImage(x, y);
    }
  }

  count_all_neighbours();
}

function life_set_up() {
  for(x = 0; x < width; x++) {
    life[x] = new Array(height);
  }

  for(y = 0; y < height; y++) {
    document.write('<TR>');
    for (x = 0; x < width; x++) {
      document.write('<TD style="background:#E0E0E0" id="' + x + '" name="' + y + '"+ " WIDTH="' + cell_width + '" HEIGHT="' + cell_height + '><font size="-6"></font></TD>');
      life[x][y] = new cell();
    }

    document.write('</TR>');
  }

  var table = get_element_by_id("life_table");

  all_td = table.getElementsByTagName("td");
}

function life_click() {
  e = event.srcElement;
  if (e.id == "table") {
    return;
  }

  if (e.id == null) {
    return;
  }

  if (e.id == "") {
    return;
  }

  x = eval(e.id);
  y = eval(e.name);

  //window.status = "X = " + x + " - Y = " + y;

  current = life[x][y];
  current.age = 1;

  SetCellImage(x, y);
  update_neighbour_counts(x, y, current.age - current.old_age);
}

function life_clear() {
  for(x = 0; x < width; x++) {
  	for(y = 0; y < height; y++) {
      life[x][y].age = 0;
    }
  }

  render_all();
}

function life_randomise() {
  for(x = 0; x < width; x++) {
  	for(y = 0; y < height; y++) {
  	  if((life[x][y].age == 0) && (Math.floor(Math.random() * 5) == 0)) {
		    life[x][y].age = 1;
	    } else {
		    life[x][y].age = 0;
	    }
	  }
	}

  render_all();
}


function life_pause() {
  paused = !paused;
}

function life_start() {
  if (!paused) {
    if (threads < 1) {
      threads++;
      count_all_neighbours();
      life_cycle();
    }

    request_stop=false;
  }
}

function life_stop() {
  if (!paused) {
    request_stop = true;
  }
}
