var ScreenManager = function (wCount, hCount, pScale, div, bullpen, button)
{
  // member variables
  this.cells        = [];
  this.flatCells    = [];
  this.isAnimating  = false;
  this.matrixW      = wCount || ScreenManager.DEFAULT_COLUMN_COUNT;
  this.matrixH      = hCount || ScreenManager.DEFAULT_ROW_COUNT;
  this.pixScale     = pScale || ScreenManager.DEFAULT_PIX_SCALE;
  this.ptTimeout    = null;
  this.matrix       = null;

  // element
  var width  = this.matrixW * this.pixScale;
  var height = this.matrixH * this.pixScale;
  this.container        = ScreenManager.buildContainer(div, width, height);
  this.ieCanvasBullpen  = bullpen || ScreenManager.buildBullpen();
  this.button           = button || null;

  // function caches
  this.fnCache = {};
  this.fnCache.turn = EventRunner.scope(this, this.turn);

  // initialize matrix
  this.matrix = new Matrix(
    width, 
    height,
    this.pixScale,
    this.container,
    this.ieCanvasBullpen
  );
  this.matrix.show();

  // initilze cells
  for (var y = 0; y < this.matrixH; ++y)
  {
    for (var x = 0; x < this.matrixW; ++x)
    {
      if (y == 0)
      {
        this.cells[x] = [];
      }
      this.flatCells[this.flatCells.length] = this.cells[x][y] = new Cell(x, y);
    }
  }
  for (var i = 0, len = this.flatCells.length; i < len; ++i)
  {
    this.collectNeighbors(this.flatCells[i]);
  }
  this.cells[2][1].on();
  this.cells[3][2].on();
  this.cells[1][3].on();
  this.cells[2][3].on();
  this.cells[3][3].on();

  // initialize view
  this.drawScreen();

  // initialize events
  EventRunner.register(this.matrix.container, 'click', this.onclick, this);
  if (this.button)
  {
    EventRunner.register(this.button, 'click', this.onButtonClick, this);
  }
}


// STATICs
// ________________________________________________________________________


ScreenManager.MILSEC_ANIMATION_INTERVAL = 34;
ScreenManager.DEFAULT_COLUMN_COUNT      = 10;
ScreenManager.DEFAULT_ROW_COUNT         = 10;
ScreenManager.DEFAULT_PIX_SCALE         = 30;


ScreenManager.buildContainer = function (d, w, h)
{
  if (!d)
  {
    d = document.createElement('div');
    document.body.appendChild(d);
  }
  d.style.width   = w + 'px';
  d.style.height  = h + 'px';
  return d;
}


ScreenManager.buildBullpen = function ()
{
  var d = document.createElement('div');
  d.style.visibility  = 'hidden';
  d.style.width       = '1px';
  d.style.height      = '1px';
  d.id = 'ieCanvasBullpen' + Math.floor(Math.random() * 10000);
  document.body.appendChild(d);
  return d;
}


// SCRATCH PADS
// _______________________________________________________________________





























// VIEW METHODS
// _______________________________________________________________________


ScreenManager.prototype.animate = function ()
{
  this.isAnimating = true;
  this.turn();
}


ScreenManager.prototype.drawScreen = function ()
{
  var cell;
  for (var i = 0, len = this.flatCells.length; i < len; ++i)
  {
    cell = this.flatCells[i];
    if (cell.getLife(0))
    {
      this.matrix.plot(cell.x, cell.y);
    }
    else
    {
      this.matrix.erase(cell.x, cell.y);
    }
  }
}


ScreenManager.prototype.freeze = function ()
{
  this.isAnimating = false;
  window.clearTimeout(this.ptTimeout);
}


ScreenManager.prototype.toggle = function (ev)
{
  if (this.isAnimating)
  {
    this.freeze();
  }
  else
  {
    this.animate();
  }
  return this.isAnimating;
}


ScreenManager.prototype.turn = function ()
{
  for (var _i = 0, _len = this.flatCells.length; _i < _len; ++_i)
  {
    this.flatCells[_i].shiftAge();
  }

  var canvas = this.matrix.getNextCanvas();
  var cell;
  for (var i = 0, len = this.flatCells.length; i < len; ++i)
  {
    cell = this.flatCells[i];
    if (cell.turn())
    {
      this.matrix.plot(cell.x, cell.y, undefined, canvas);
    }
  }

  this.matrix.turn();
  if (this.isAnimating)
  {
    this.ptTimeout = window.setTimeout(this.fnCache.turn, ScreenManager.MILSEC_ANIMATION_INTERVAL);
  }
}


// EVENT METHODS
// _______________________________________________________________________


ScreenManager.prototype.onclick = function (ev)
{
  var jq = $(this.matrix.container);
  var pos = jq.position();
  var localX = ev.clientX - (pos.left + parseInt(jq.css('border-left-width')));
  var localY = ev.clientY - (pos.top + parseInt(jq.css('border-top-width')));
  //console.log('local: ' , localX, localY);
  var indexX = Math.floor(localX / this.pixScale);
  var indexY = Math.floor(localY / this.pixScale);
  //console.log('index: ', indexX, indexY);

  this.cells[indexX][indexY].toggle();
  this.drawScreen();
}


ScreenManager.prototype.onButtonClick = function (ev)
{
  if (this.toggle())
  {
    this.button.innerHTML = 'freeze';
  }
  else
  {
    this.button.innerHTML = 'animate';
  }
}


// UTILITY METHODS
// _______________________________________________________________________


ScreenManager.prototype.adjustedX = function (v)
{
  var result = v;
  if (v < 0)
  {
    result = this.matrixW - 1;
  }
  else if (v >= this.matrixW)
  {
    result = 0;
  }
  return result;
}


ScreenManager.prototype.adjustedY = function (v)
{
  var result = v;
  if (v < 0)
  {
    result = this.matrixH - 1;
  }
  else if (v >= this.matrixH)
  {
    result = 0;
  }
  return result;
}


ScreenManager.prototype.collectNeighbors = function (cell)
{
  //console.log('pos: ', cell.x, cell.y);
  for (var y = -1; y < 2; ++y)
  {
    for (var x = -1; x < 2; ++x)
    {
      if ((x === 0) && (y === 0))
      {
        continue;
      }
      var aX = this.adjustedX(cell.x + x);
      var aY = this.adjustedY(cell.y + y);
      //console.log('   nei: ', aX, aY);
      cell.setNeighbor(
        this.cells[ aX ][ aY ]
      );
    }
  }
}



