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;
  this.currentColor = [255, 0, 0, 1];

  // 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 = MochiKit.Base.bind(this.turn, this);

  // initialize matrix
  this.matrix = new Matrix(
    width, 
    height,
    this.pixScale,
    this.container,
    this.ieCanvasBullpen
  );
  this.matrix.show();
  this.matrix.setOnClick(MochiKit.Base.bind(this.onclick, this));

  // 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.randomColor();
  this.cells[6][4].on(this.currentColor);
  this.randomColor();
  this.cells[11][4].on(this.currentColor);
  this.randomColor();

  this.cells[4][5].on(this.currentColor);
  this.randomColor();
  this.cells[5][5].on(this.currentColor);

  this.randomColor();
  this.cells[7][5].on(this.currentColor);
  this.randomColor();
  this.cells[8][5].on(this.currentColor);
  this.randomColor();
  this.cells[9][5].on(this.currentColor);
  this.randomColor();
  this.cells[10][5].on(this.currentColor);

  this.randomColor();
  this.cells[12][5].on(this.currentColor);
  this.randomColor();
  this.cells[13][5].on(this.currentColor);

  this.randomColor();
  this.cells[6][6].on(this.currentColor);
  this.randomColor();
  this.cells[11][6].on(this.currentColor);

  // initialize view
  this.drawScreen();

  // initialize events
  if (this.button)
  {
    MochiKit.Signal.connect(this.button, 'onclick', this, this.onButtonClick);
  }
}


// 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
// _______________________________________________________________________

ScreenManager.prototype.randomColor = function ()
{
  this.currentColor[0] = Math.floor( Math.random() * 256);
  this.currentColor[1] = Math.floor( Math.random() * 256);
  this.currentColor[2] = Math.floor( Math.random() * 256);
}



























// 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, cell.getColor());
    }
    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 ()
{
  var i;
  var len = this.flatCells.length;
  for (i = 0; i < len; ++i)
  {
    this.flatCells[i].shiftAge();
  }

  var canvas = this.matrix.getNextCanvas();
  var cell;
  for (i = 0; i < len; ++i)
  {
    cell = this.flatCells[i];
    cell.turn();
    this.matrix.plot(cell.x, cell.y, cell.getColor(), canvas);
    // if (cell.turn())
    // {
    //   this.matrix.plot(cell.x, cell.y, cell.getColor(), 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)
{
  //console.log(ev);

  var m = ev.mouse();
  var pos = MochiKit.DOM.elementPosition(this.matrix.container);
  var localX = 
    m.client.x 
    - (
        pos.x 
        + parseInt(
          MochiKit.DOM.computedStyle(this.matrix.container, 'border-left-width')
        )
    );
  var localY = 
    m.client.y 
    - (
        pos.y 
        + parseInt(
          MochiKit.DOM.computedStyle(this.matrix.container, '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);

  // FIXME!!
  var cell = this.cells[indexX][indexY];
  if (cell.getLife())
  {
    cell.off();
  }
  else
  {
    this.randomColor();
    cell.on(this.currentColor);
  }
  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 ]
      );
    }
  }
}



