/*
-------------------------------------------------------------------------------
Perform an animation on an object

Parameters:

aObject       The object to apply the animation on (ex: lDiv.style)
aProperty     The property to be affected by the animation (ex: "top")
aFunction     Function to call to affect the tween (ex: MV_Tween.noEasing)
aBegin        The start value of the animation
aFinish       The end value of the animation
aDuration     The duration of the animation in milliseconds
aUnit         Unit to add to the modified value (ex: "px")
-------------------------------------------------------------------------------
*/

function MV_Tween(aObject, aProperty, aFunction, aBegin, aFinish, aDuration, aUnit)
{
  this.mObject = aObject;
  this.mProperty = aProperty;
  this.mFunction = aFunction;
  this.mBegin = aBegin;
  this.mFinish = aFinish;
  this.mUnit = aUnit;
  this.mDuration = aDuration;
  
  this.mCurrentValue = aBegin;
  this.mTimer = null;
  // 18 FPS = 55 milliseconds
  this.mIntervalTime = 55;
  this.mCurrentTime = (new Date()).getTime();
  this.mStartTime = this.mCurrentTime;
  this.mEventListener = null;
}

// Definition of the events that can be handled
MV_Tween.ON_MOTION_FINISH = 0;

// ----------------------------------------------------------------------------
MV_Tween.prototype.run = function()
{
  this.mObject[this.mProperty] = ( this.mUnit === undefined ) ? this.mBegin : this.mBegin.toString() + this.mUnit;
  this.mTimer = window.setInterval(mv_delegateCallback(this, this.privTweenExecute), this.mIntervalTime);
}

// ----------------------------------------------------------------------------
MV_Tween.prototype.stop = function()
{
  window.clearInterval(this.mTimer);
  this.mTimer = null;
}

// ----------------------------------------------------------------------------
MV_Tween.prototype.privTweenExecute = function()
{
  this.mCurrentTime = (new Date()).getTime();
  
  var lAnimationTime = this.mCurrentTime - this.mStartTime;
  
  if(lAnimationTime >= this.mDuration)
  {
    this.stop();
    lAnimationTime = this.mDuration;
  }
  
  var lNewValue = this.mFunction(lAnimationTime, this.mBegin, this.mFinish, this.mDuration);
  this.mObject[this.mProperty] = ( this.mUnit === undefined ) ? lNewValue : lNewValue.toString() + this.mUnit;
  
  if(this.mTimer == null && this.mEventListener !== null && this.mEventListener[MV_Tween.ON_MOTION_FINISH] !== undefined )
  {
    this.mEventListener[MV_Tween.ON_MOTION_FINISH]();
  }
}

// ----------------------------------------------------------------------------
MV_Tween.prototype.registerEventListener = function(aEvent, aFcn)
{
  if ( this.mEventListener === null )
  {
    this.mEventListener = new Array();
  }
  
  this.mEventListener[aEvent] = aFcn;
}

// ----------------------------------------------------------------------------
MV_Tween.noEasing = function(aTime, aBeginValue, aEndValue, aDuration)
{
  return ((aEndValue-aBeginValue) / aDuration) * aTime + aBeginValue;
}

// ----------------------------------------------------------------------------
MV_Tween.easeIn = function(aTime, aBeginValue, aEndValue, aDuration)
{
  return (aEndValue - aBeginValue) * aTime * aTime / ( aDuration * aDuration ) + aBeginValue;
}

// ----------------------------------------------------------------------------
MV_Tween.easeOut = function(aTime, aBeginValue, aEndValue, aDuration)
{
  return ((aBeginValue - aEndValue) / aDuration * ((aTime / aDuration) - 2)) * aTime + aBeginValue;
}

// ----------------------------------------------------------------------------
// Utility method to start all the tweens in an array.
MV_Tween.startTweenArray = function(aTweenArray)
{
  if( aTweenArray ) {
    var lArraySize = aTweenArray.length;
    for (var i=0; i<lArraySize; i++) {
      if ( aTweenArray[i] && aTweenArray[i].run ) {
        aTweenArray[i].run();
      }
    }
  }
}

// ----------------------------------------------------------------------------
// Utility method to stop all the tweens in an array.
MV_Tween.stopTweenArray = function(aTweenArray)
{
  if( aTweenArray ) {
    var lArraySize = aTweenArray.length;
    for (var i=0; i<lArraySize; i++) {
      if ( aTweenArray[i] && aTweenArray[i].stop ) {
        aTweenArray[i].stop();
      }
    }
  }
}

// ----------------------------------------------------------------------------
function mv_delegateCallback(aObj, aFunc)
{
  var lDelegateFcn = function()
  {    
    var lTarget = arguments.callee.prvTarget;
    var lFcn = arguments.callee.prvFunc;
    
    return lFcn.apply(lTarget, arguments);
  };

  lDelegateFcn.prvTarget = aObj;
  lDelegateFcn.prvFunc = aFunc;

  return lDelegateFcn;
}