var Controller = function (original)
{
  this.initBackgroud();

  // console.log('Controller::constructor');
  this.original     = original;
  this.actors       = [];
  this.actorStuck   = null;
  this.frame        = null;
  this.ptTimer      = null;
  this.loadingImage = null;
  this.ready        = [false, false]; // need abstract stack-queue

  this.fnCache = {};
  this.fnCache.onAfterAppearing = EventRunner.scope(this, this.onAfterAppearing);
  this.fnCache.onStart          = EventRunner.scope(this, this.onStart);
  this.fnCache.onUpdate         = Controller.buildEventOnUpdate(this);

  this.initFrame();
  this.initPreloadImages();
  this.initActors();
  this.original.style.display = 'none';
}


// STATICs
// _______________________________________________________________________


Controller.STR_DEFAULT_FRAME_ID   = 'canvasFrame';
Controller.STR_LOADING_ID         = 'warmup';
Controller.MILSEC_DEFAULT_DELAY   = 17;
Controller.MILSEC_INTRO_DELAY     = 500;
Controller.MILSEC_DISAPPEAR_DELAY = 5000;
Controller.MILSEC_LOADING_FADE    = 1000;
Controller.IS_IE                  = (document.all && !window.opera);
Controller.INDEX_READY_PRELOADER  = 0;
Controller.INDEX_READY_ACTORS     = 1;


Controller.buildEventOnUpdate = function (self)
{
  return function ()
  {
    var f = self.frame;
    f.draw();
    f.update();
    if (self.ptTimer)
    {
      self.ptTimer = null;
    }
  }
}


Controller.deg2rad = function (v)
{
  return v * Math.PI / 180;
}


Controller.jumpPage = function (url)
{
  window.location.href = url;
}


Controller.rad2deg = function (v)
{
  return v * 180 / Math.PI;
}


Controller.round = function (v, digit)
{
  var temp = Math.pow(10, digit);
  return (Math.round(v * temp) / temp);
}


Controller.buildBackgroundString = function (filename)
{
  return "url(" + filename + ")";
}


// INIT Methods
// _______________________________________________________________________


Controller.prototype.initBackgroud = function ()
{
  var arr = [
    'http://nydd.org/css/home/bg_random0.png',
    'http://nydd.org/css/home/bg_random1.png',
    'http://nydd.org/css/home/bg_random2.png',
    'http://nydd.org/css/home/bg_random3.png',
    'http://nydd.org/css/home/bg_random4.png',
    'http://nydd.org/css/home/bg_random5.png'
  ];
  document.body.style.backgroundImage = Controller.buildBackgroundString(arr[Math.floor(Math.random() * arr.length)]);
}


Controller.prototype.callbackPreloadImages = function (ev, img)
{
  var index = $(img).data('index');
  this.loadingImage[index] = true;
  var result = true;
  for (var i = 0, len = this.loadingImage.length; i < len; ++i)
  {
    if (this.loadingImage[i] !== true)
    {
      result = false;
      break;
    }
  }
  if (result)
  {
    this.ready[Controller.INDEX_READY_PRELOADER] = true;
    this.checkReady();
  }
}


Controller.prototype.checkReady = function ()
{
  var result = true;
  for (var i = 0, len = this.ready.length; i < len; ++i)
  {
    if (this.ready[i] !== true)
    {
      result = false;
      break;
    }
  }
  if (result)
  {
    $('#' + Controller.STR_LOADING_ID).fadeOut(
      Controller.MILSEC_LOADING_FADE,
      this.fnCache.onStart
    );
  }
}


Controller.prototype.initFrame = function ()
{
  // console.log('Controller::initFrame');
  this.frame = new Frame(Controller.STR_DEFAULT_FRAME_ID);
  var jq  = $( $('div.wrapper', this.original).get(0) );
  var pos = jq.position();
  this.frame.setDisplayRect({
    'width' : jq.outerWidth(),
    'height': jq.outerHeight(),
    'x'     : pos.left,
    'y'     : pos.top
  });
}

Controller.prototype.initPreloadImages = function ()
{
  // this gives a nice visual touch, but 
  // it's too CPU intensive
  // <img src="img/vignet.png" title="vignet" />
  this.ready[Controller.INDEX_READY_PRELOADER] = true;
  document.getElementById('preloader').style.display = 'none';

  // console.log('Controller::initPreloadImages');
  // very tightly connected with Frame... Hmm...
  // var elm, title, i;
  // var jq  = $('#preloader img');
  // var len = jq.length
  // this.loadingImage = new Array(len);
  // 
  // for (i = 0; i < len; ++i)
  // {
  //   elm               = jq.get(i);
  //   title             = elm.getAttribute('title');
  //   this.frame[title] = elm;
  //   $(elm).data('index', i);
  //   ImageUtil.callbackImageLoaded(elm, EventRunner.scope(this, this.callbackPreloadImages));
  // }
}


Controller.prototype.initActors = function ()
{
  // console.log('Controller::initActors');
  var elm;
  var elments = $('img', this.original);
  var len     = elments.length;
  this.actorStuck = new Array(len);

  for (var i = 0; i < len; ++i)
  {
    elm = elments.get(i);
    // because WebKit Browsers will not return the size of image until 
    // it is really drawn on the page.  And... You cannot guarantee 
    // without using onload event.. so I introduce ImageUtil.js.
    this.queueActorLoading(i, elm, $(elm).position());
  }
}


Controller.prototype.queueActorLoading = function (index, img, position)
{
  var self      = this;
  var result    = {};
  result.elm    = img;
  result.x      = position.left;
  result.y      = position.top;
  var callback  = function (ev, element)
  {
    // console.log(element.src + '(' + element.width + ', ' + element.height + ')');
    result.width  = element.width;
    result.height = element.height;
    element.parentNode.removeChild(element);
    self.actorStuck[index] =  function ()
    {
      return result;
    };
    self.checkActorQueue();
  };
  ImageUtil.setCallbackImageLoaded(img.src, callback);
}


Controller.prototype.checkActorQueue = function ()
{
  var fail = false;
  for (var i = 0, len = this.actorStuck.length; i < len; ++i)
  {
    if (typeof(this.actorStuck[i]) === 'undefined')
    {
      fail = true;
      break;
    }
  }
  if (fail)
  {
    return;
  }

  var actor, result;
  for (i = 0; i < len; ++i)
  {
    result        = this.actorStuck[i]();
    actor         = new Actor(result.elm);
    actor.x       = result.x;
    actor.y       = result.y;
    actor.width   = result.width;
    actor.height  = result.height;

    this.actors[this.actors.length] = actor;
    this.frame.addActor(actor);
  }

  this.actorStuck = null;
  this.ready[Controller.INDEX_READY_ACTORS] = true;
  this.checkReady();
}


// EVENT Methods
// _______________________________________________________________________


Controller.prototype.onAfterAppearing = function (ev)
{
  this.frame.animateLeave();
  // this.ptTimer = window.setTimeout
  // (
  //   this.fnCache.onStart,
  //   Controller.MILSEC_DISAPPEAR_DELAY
  // );
}


Controller.prototype.onStart = function (ev)
{
  this.frame.animateEnter();
  // this.ptTimer = window.setTimeout
  // (
  //   this.fnCache.onAfterAppearing,
  //   Controller.MILSEC_DISAPPEAR_DELAY
  // );
}


Controller.prototype.onUpdate = function (ev)
{
  this.frame.draw();
  this.frame.update();
  if (this.ptTimer)
  {
    this.ptTimer = null;
  }
}


// UTILITY Methods
// _______________________________________________________________________


Controller.prototype.locate = function (obj, no_update)
{
  no_update = no_update || false;
  for (var i in obj)
  {
    switch (i)
    {
      case 'centerX':
      case 'centerY':
      case 'x':
      case 'y':
      case 'alpha':
      case 'rotation':
      case 'scaleX':
      case 'scaleY':
        this.frame[i] = obj[i];
      break;

      default:
        console.log(i + ': ' + obj[i]);
      break;
    }
  }
  if (!no_update)
  {
    this.ptTimer = window.setTimeout( this.fnCache.onUpdate, Controller.MILSEC_DEFAULT_DELAY);
  }
}


