var animator = new Animator();

function LinearAnimationHandler() {
  var animations = [];
  var animationCount = 0;
  
  function addAnimation(oParams)
  {
    animation.Push(new Animation(oParams));
  }  
  
  function clearAnimations() {
    animations = [];
  }
  
  function nextAnimation() {
    if (animations[animationCount]) {
      // writeDebug('starting animation '+animationCount);
      animations[animationCount].start();
      animationCount++;
    }
  }

  function startAnimation() {
    animationCount = 0;
    nextAnimation();
  }
  
  function stopAnimation() {
    animator.stop();
  }
}

function Animator() {
  // controller for animation objects.
  var self = this;
  var intervalRate = 50;
  this.tweenTypes = {
    // % of total distance to move per-frame, total always = 100
    'default': [1,2,3,4,5,6,7,8,9,10,9,8,7,6,5,4,3,2,1],
    'blast': [12,12,11,10,10,9,8,7,6,5,4,3,2,1],
    'linear': [10,10,10,10,10,10,10,10,10,10],
    'quicklinear': [33,34,33]
  }
  this.queue = [];
  this.queueHash = [];
  this.active = false;
  this.timer = null;
  this.createTween = function(start,end,type) {
    // return array of tween coordinate data (start->end)
    type = type||'default';
    var tween = [start];
    var tmp = start;
    var diff = end-start;
    var x = self.tweenTypes[type].length;
    for (var i=0; i<x; i++) {
      tmp += diff*self.tweenTypes[type][i]*0.01;
      tween[i] = {};
      tween[i].data = tmp;
      tween[i].event = null;
    }
    return tween;
  };

  this.enqueue = function(o) {
    // add object
    
    // writeDebug('animator.enqueue()');
    self.queue.push(o);
    o.active = true;
  };

  this.animate = function() {
    // interval-driven loop: process queue, stop if done
    var active = 0;
    for (var i=0,j=self.queue.length; i<j; i++) {
      if (self.queue[i].active) {
        self.queue[i].animate();
        active++;
      }
    }
    if (active == 0 && self.timer) {
      // all animations finished
      
      // writeDebug('Animations complete');
      self.stop();
    } else {
      // writeDebug(active+' active');
    }
  };

  this.start = function() {
    if (self.timer || self.active) {
      // writeDebug('animator.start(): already active');
      return false;
    }
    // writeDebug('animator.start()');

    // report only if started
    self.active = true;
    self.timer = setInterval(self.animate,intervalRate);
  };

  this.stop = function() {
    // writeDebug('animator.stop()',true);

    // reset some things, clear for next batch of animations
    clearInterval(self.timer);
    self.timer = null;
    self.active = false;
    self.queue = [];
  };

};

function Animation(oParams) {
  // Individual animation sequence
  
  /*
    oParams = {
      from: 200,
      to: 300,
      tweenType: 'default', // see animator.tweenTypes (optional)
      ontween: function(value) { ... }, // method called each time (required)
      oncomplete: function() { ... } // when finished (optional)
    }
  */
  var self = this;
  if (typeof oParams.tweenType == 'undefined') {
    oParams.tweenType = 'default';
  }
  this.object = (oParams.object||null);
  this.ontween = (oParams.ontween||null);
  this.oncomplete = (oParams.oncomplete||null);
  this.tween = animator.createTween(oParams.from,oParams.to,oParams.tweenType);
  this.frameCount = animator.tweenTypes[oParams.tweenType].length;
  this.frame = 0;
  this.active = false;

  this.animate = function() {
    // generic animation method
    if (self.active) {
      if (self.ontween && self.tween[self.frame]) {
        self.ontween(self.object, self.tween[self.frame].data);
      }
      if (self.frame++ >= self.frameCount-1) {
        // writeDebug('animation(): end');
        self.active = false;
        self.frame = 0;
        if (self.oncomplete) {
          self.oncomplete();
        }
        return false;
      }
      return true;
    } else {
      return false;
    }
  };

  this.start = function() {
    // add this to the main animation queue
    animator.enqueue(self);
    if (!animator.active) {
      animator.start();
    }
  };

  this.stop = function() {
    self.active = false;
  };
  
};

