/** ANIMATION FUNCTIONS *******************************************************/
// Mar 13, 2008: No new functionality, but now multiple animations can be
//               running in parallel.
// Nov 6, 2008:  Added DualStyleAnimation (for animations with styles that take 2 values)
// May 25, 2009: Added "unit" parameter to MoveAnimation() function

/*

  Usage example:

  var myAnim = new Animation();
  myAnim.clear();
  myAnim.addMoveAnimation(div1,10,10,100,100);
  myAnim.addMoveAnimation(div2,10,10,100,100);
  myAnim.start();


*/

var allAnimations = new Array();
var animationCounter = 0;

function Animation(uniqueID)
{
  var ID = animationCounter++;
  allAnimations[ID] = this;
  var moveAnimsFIFO  = new Array();
  var resizeAnimsFIFO = new Array();
  var styleAnimsFIFO = new Array();
  var dualStyleAnimsFIFO = new Array();
  var fifoSize = 0;
  var funcDoneFIFO = new Array();

  this.animSteps = 18;
  this.animDelay = 25;
  this.animBusy = false;

  // Start a new series of animations
  this.clear = function()
  {
    ++fifoSize; // first increase size
    moveAnimsFIFO[fifoSize-1] = new Array();
    resizeAnimsFIFO[fifoSize-1] = new Array();
    styleAnimsFIFO[fifoSize-1] = new Array();
    dualStyleAnimsFIFO[fifoSize-1] = new Array();
    //alert("cleared, fifoSize="+fifoSize);
  }

  function MoveAnimation(div,x1,y1,x2,y2,unit)
  {
    this.div = div;
    this.x1 = x1;
    this.y1 = y1;
    this.x2 = x2;
    this.y2 = y2;
    this.unit = unit;
  }

  function ResizeAnimation(div,w1,h1,w2,h2,unit)
  {
    this.div = div;
    this.w1 = w1;
    this.h1 = h1;
    this.w2 = w2;
    this.h2 = h2;
    this.unit = unit;
  }

  function StyleAnimation(div,property,v1,v2,unit)
  {
    this.div = div;
    this.property = property;
    this.v1 = v1;
    this.v2 = v2;
    this.unit = unit;
  }

  function DualStyleAnimation(div,property,a1,a2,b,unit)
  {
    this.div = div;
    this.property = property;
    this.a1 = a1;
    this.a2 = a2;
    this.b = b;
    this.unit = unit;
  }

  this.addMoveAnimation = function(div,x1,y1,x2,y2,unit)
  {
    moveAnimsFIFO[fifoSize-1][moveAnimsFIFO[fifoSize-1].length] = new MoveAnimation(div,x1,y1,x2,y2,unit);
  }

  this.addResizeAnimation = function(div,w1,h1,w2,h2,unit)
  {
    resizeAnimsFIFO[fifoSize-1][resizeAnimsFIFO[fifoSize-1].length] = new ResizeAnimation(div,w1,h1,w2,h2,unit);
  }

  this.addStyleAnimation = function(div,property,v1,v2,unit)
  {
    styleAnimsFIFO[fifoSize-1][styleAnimsFIFO[fifoSize-1].length] = new StyleAnimation(div,property,v1,v2,unit);
  }

  this.addDualStyleAnimation = function(div,property,a1,a2,b,unit)
  {
    dualStyleAnimsFIFO[fifoSize-1][dualStyleAnimsFIFO[fifoSize-1].length] = new DualStyleAnimation(div,property,a1,a2,b,unit);
  }

  this.start = function(evalWhenDone)
  {
    if (arguments.length < 1) evalWhenDone = "";
    funcDoneFIFO[funcDoneFIFO.length] = evalWhenDone;
    if (!this.animBusy) // if anim already busy, then simply exit
    {
      this.animBusy = true;
      //alert("starting, fifoSize="+fifoSize);
      this.animateWorker(1);
    }
  }

  this.animateWorker = function(step)
  {
    var x1, y1, x2, y2, unit;
    //var debugStr = "fifoSize="+fifoSize+"<br>step="+step+"<br>fifoLen="+moveAnimsFIFO.length;
    //debug(debugStr);
    //debugStr += "<br>arrayLen="+moveAnimsFIFO[0].length;
    //debug(debugStr);
    //debugStr += "<br>";
    for (var n=0; n<moveAnimsFIFO[0].length; ++n)
    {
      //debugStr += n+"="+moveAnimsFIFO[0][n]+" ";
      //debug(debugStr);
      x1 = moveAnimsFIFO[0][n].x1;
      y1 = moveAnimsFIFO[0][n].y1;
      x2 = moveAnimsFIFO[0][n].x2;
      y2 = moveAnimsFIFO[0][n].y2;
      unit = moveAnimsFIFO[0][n].unit;
      moveAnimsFIFO[0][n].div.move(x1+(x2-x1)*step/this.animSteps+unit,y1+(y2-y1)*step/this.animSteps+unit);
    }
    //debugStr += "<br>MARK 1";
    //debug(debugStr);
    var w1, h1, w2, h2;
    for (var n=0; n<resizeAnimsFIFO[0].length; ++n)
    {
      w1 = resizeAnimsFIFO[0][n].w1;
      h1 = resizeAnimsFIFO[0][n].h1;
      w2 = resizeAnimsFIFO[0][n].w2;
      h2 = resizeAnimsFIFO[0][n].h2;
      unit = resizeAnimsFIFO[0][n].unit;
      resizeAnimsFIFO[0][n].div.resize(w1+(w2-w1)*step/this.animSteps+unit,h1+(h2-h1)*step/this.animSteps+unit);
    }
    //debugStr += "<br>MARK 2";
    //debug(debugStr);
    var property, v1, v2;
    for (var n=0; n<styleAnimsFIFO[0].length; ++n)
    {
      property = styleAnimsFIFO[0][n].property;
      v1 = styleAnimsFIFO[0][n].v1;
      v2 = styleAnimsFIFO[0][n].v2;
      unit = styleAnimsFIFO[0][n].unit;
      eval("styleAnimsFIFO[0][n].div.div.style."+property+" = v1+(v2-v1)*step/this.animSteps+unit");
    }
    //debugStr += "<br>MARK 3";
    //debug(debugStr);
    var property, a1, a2, b;
    for (var n=0; n<dualStyleAnimsFIFO[0].length; ++n)
    {
      property = dualStyleAnimsFIFO[0][n].property;
      a1 = dualStyleAnimsFIFO[0][n].a1;
      a2 = dualStyleAnimsFIFO[0][n].a2;
      b = dualStyleAnimsFIFO[0][n].b;
      unit = dualStyleAnimsFIFO[0][n].unit;
      eval("dualStyleAnimsFIFO[0][n].div.div.style."+property+" = a1+(a2-a1)*step/this.animSteps+unit +' '+ b+unit");
    }
    //debugStr += "<br>MARK 4";
    //debug(debugStr);
    if (step < this.animSteps) setTimeout("animateWorker("+ID+","+(step+1)+")",this.animDelay);
    else
    {
      moveAnimsFIFO = moveAnimsFIFO.slice(1,fifoSize); // TODO use shift() instead?
      resizeAnimsFIFO = resizeAnimsFIFO.slice(1,fifoSize);
      styleAnimsFIFO = styleAnimsFIFO.slice(1,fifoSize);
      dualStyleAnimsFIFO = dualStyleAnimsFIFO.slice(1,fifoSize);
      --fifoSize;
      //if (moveAnimsFIFO.length == 0) alert("finished, fifoSize="+fifoSize+" fifoLen="+moveAnimsFIFO.length);
      //else alert("finished, fifoSize="+fifoSize+" fifoLen="+moveAnimsFIFO.length+" arrayLen="+moveAnimsFIFO[0].length);
      this.animBusy = false;
      if (funcDoneFIFO[0] != "") setTimeout(funcDoneFIFO[0],0);
      funcDoneFIFO = funcDoneFIFO.slice(1,funcDoneFIFO.length);
      if (funcDoneFIFO.length > 0) // start new series of animations
      {
        this.animBusy = true;
        setTimeout("animateWorker("+ID+",1)",this.animDelay);
      }
    }
    //debugStr += "<br>END";
    //debug(debugStr);
  }

}

function animateWorker(animID,step)
{
  var anim = allAnimations[animID];
  anim.animateWorker(step);
}
