/** 
 * @fileoverview This is the complete {@link http://www.codeplex.com/animej AnimeJ}
 * library, an animation for DHTML designed to be lightweight and efficient.
 * This library has been developed for {@link http://www.toscana4u.net/ Toscana4U}.
 *
 * @author Antonio Cisternino cisterni@di.unipi.it (C) 2008, University of Pisa
 * @version 1.0
 */

/**
 * @private
 */
var __DependenciesManager;

/**
 * Displays a blue screen inspired to Windows well known blue screen. The modal
 * popup is closed when you click on it.
 * @param {String} msg Message to display (preceded by 'INTERNAL ERROR: ')
 */
function BlueScreen(msg) {
  if (document.body) {
    alert('onloaded');
    var d = document.createElement('div'), k;
    var values = { 'position': 'absolute', 'top': 0, 'left': 0, 'width': '100%',
      'height': '100%', 'background': 'Blue', 'color': 'White', 'fontFamily': 'Fixedsys, monospace' };
    for (k in values) d.style[k] = values[k];
    d.innerHTML = 'INTERNAL ERROR: '+msg;
    d.onclick = function () { document.body.removeChild(d); };
    document.body.appendChild(d);
  } else {
    // Hack! when in header you cannot access to DOM
    document.write('<div style="z-index: 1000; position: absolute; left: 0; top: 0; margin: 0; padding: 0; width: 100%; height: 100%; background: Blue; color: White; font-family: Fixedsys, monospace" onclick="this.parentNode.removeChild(this);">INTERNAL ERROR: '+msg+'</div>');
  }
  throw "INTERNAL ERROR: " + msg;
}

/**
 * This function should be called by scripts to register their loading.
 * @param {String} name Name of the script
 * @param {int} version Version of the script, should be an increasing integer number
 * @param {string} description Brief description used for display purpose
 */
function RegisterScript(name, version, description) {
  if (! __DependenciesManager) __DependenciesManager = {};
  __DependenciesManager[name + ", version=" + version] = description;
}

/**
 * This function is meant to check dependencies among a number of JavaScript
 * source files that share this dependency convention. If a dependency is violated
 * the script displays a blue screen informing which scripts are not available.
 * @param {Array} scripts The required scripts. Each element of the array can be either
 *        a string with the script name (registered using RegisterScript) or a pair
 *        { Name: '...', Version: 0 } if the least version number is specified.
 */
function Require(scripts) {
  var i, msg = null;
  for (i = 0; i < scripts.length; i++) {
    var el = scripts[i], k, strong = typeof(el) != "string";
    if (strong && !el.Name) {
      msg = "Invalid require statement!";
      BlueScreen(msg);
      return;
    }
    var toadd = strong ? el.Name + ' (version ' + el.Version + ')' : el;
    for (k in __DependenciesManager)
      if (!strong) {
        if (k.indexOf(el) == 0) {
          toadd = null;
          break;
        }
      } else {
        if (k.indexOf(el.Name) == 0) {
          var v = parseInt(k.substring(k.indexOf(", version=") + 10));
          if (el.Version && el.Version <= v) {
            toadd = null;
            break;
          }
        }
      }
    if (toadd)
      if (msg) msg += ", " + toadd;
      else msg = toadd;
  }
  
  if (msg) BlueScreen('Missing libraries are <br><br>' + msg);
}

RegisterScript('AnimeJ', 1, 'AnimeJ animation library');


/**
 * @private
 * @class Heap implementation, it is used to define a shared timer which is responsible
 * for orchestrating the animation. This class is considered to be private to the library.
 * @constructor
 */
function AnimeJHeap() {
  // This is used to close this in local functions.
  var obj = this;

  // Current position of the heap index.
  var pos = 0;

  // Function to compute the left node of the tree.
  var left = function(idx) {
    return (2 * (idx + 1) - 1);
  }

  // Function to compute the right node of the tree.
  var right = function (idx) {
    return (2 * (idx + 1));
  }

  // Function to compute the parent node of a node.
  var parent = function (idx) {
    return (Math.floor((idx + 1) / 2) - 1);
  }
  
  // Function to swap the content of two nodes.
  var swap = function (a, b) {
    var tmp = obj[a];
    obj[a] = obj[b];
    obj[b] = tmp;
  }
  
  // Function to percolate up a node in the heap.
  var percolateUp = function (p) {
	var par = parent(p);
	while ((p > 0) && (obj[p].Due < obj[par].Due)) {
		swap(p, par);
		p = par;
		par = parent(p);
	}
  }
  
  // Function to percolate down a node in the heap.
  var percolateDown = function (p) {
	var l = left(p), r = right(p);
	if (l < pos) {
		if (r < pos) {
			if (obj[l].Due > obj[r].Due) {
				swap(p, r);
				percolateDown(r);
			} else {
				swap(p, l);
				percolateDown(l);
			}
		} else {
			swap(p, l);
			percolateDown(l);
		}
	} else if (p != pos - 1) {
		swap(p, pos - 1);
		percolateUp(p);
	}
  }
  
  /**
   * The number of elements contained in the heap.
   * @type int
   */
  this.Count = function () { return pos; }

  /**
   * Insert a Task into the heap.
   * @param {AnimeJTask} el Task to be inserted.
   */  
  this.Insert = function (el) {
    this[pos] = el;
    percolateUp(pos++);
  }

  /**
   * Read the top of the heap. If the heap is empty null is returned.
   * @type AnimeJTask
   */  
  this.Top = function () {
	if (pos)
		return this[0];
	return null;
  }

  /**
   * Remove the top element from the heap and returns it. If the heap
   * is empty null is returned and the heap is left unchanged.
   * @type AnimeJTask
   */  
  this.Remove = function () {
	var ret = null;
	if (!pos) return ret;
	ret = this[0];

	percolateDown(0);
	this[pos--] = null;

	return ret;
  }
  
  /**
   * Remove a specific task from the heap.
   * @param {AnimeJTask} t The task to remove. 
   * @type AnimeJTask
   */
  this.RemoveTask = function (t) {
    var i, ret = -1;
    for (i = 0; i < pos; i++)
      if (this[i].Task == t) {
        ret = this[i].Due;
        percolateDown(i);
	    this[pos--] = null;
        break;
      }
    return ret;
  }
  
  /**
   * Debug function to convert the heap into a string.
   * @private
   * @type String
   */
  this.ToString = function () {
    var i, ret = "";
    for (i = 0; i < pos; i++)
      ret += " <i>" + i + ":</i> " + this[i].Due;
    return ret;
  }
}

/**
 * @private
 * @class This is the base class for all tasks that can be scheduled
 * by the library. It simply defines the expected structure of an object
 * that is handled by the scheduler.
 * The model chosen by the library is that of Finite State Automata (FSA):
 * each activity is an automata that is notified as time passes and of other
 * events.
 */
function AnimeJTask() {
  /**
   * Notify the task that the animation has been paused.
   */
  this.OnPause = function () {};
  /**
   * Notify the task that the animation has been resumed.
   */
  this.OnResume = function () {};
  /**
   * Notify the task that the animation has been stopped.
   */
  this.OnStop = function () {};
  /**
   * Perform a step of computation
   */
  this.DoAction = function (delay) {};
}

/**
 * Global variable to keep track of the current timer.
 */ 
var AnimeJTimerRunning = null;

/**
 * @private
 * @class This class implements a shared timer using a heap and the
 * setTimeout javascript function. Usually this class is not used by
 * the public API and it is used by the library.
 */
function AnimeJTimer() {
  /**
   * @private
   * When the timer is started, it is used to record time.
   */
  this.Start = new Date();

  /**
   * @private
   * Heap used to store tasks ordered by due time.
   */
  this.Heap = new AnimeJHeap();

  /**
   * Return the timer time, a number from start time to
   * the current time.
   * @type int
   */  
  this.Time = function () {
    return new Date() - this.Start;
  }

  /**
   * Schedules a task for execution.
   * @param {AnimeJTask} what Task to be executed
   * @param {int} when Number of milliseconds to schedule the task.
   */
  this.SetAlertMillis = function(what, when) {
    var exp = when + this.Time();
    this.Heap.Insert({ 'Due': exp, 'Task': what });
    if (AnimeJTimerRunning != null && this.Heap.Top().Due == exp) {
      clearTimeout(AnimeJTimerRunning);
      AnimeJTimerRunning = null;
    }
    if (AnimeJTimerRunning == null) {
      AnimeJTimerRunning = true;
      var tosleep = this.Heap.Top().Due - this.Time();
      tosleep = 0 > tosleep ? 1 : tosleep;
      AnimeJTimerRunning = setTimeout('AnimeJTimerTick()', tosleep);
    }
  }
  
  /**
   * Remove a task from the scheduler. If the task is not present it does nothing.
   * @param {AnimeJTask} t Task to be removed.
   */ 
  this.RemoveTask = function (t) {
    var v = this.Heap.RemoveTask(t);
    if (v > -1) {
      v = v - this.Time();
      if (v < 0) v = 0;
    }
    return v;
  }
  
  /**
   * Schedules a task for execution.
   * @param {AnimeJTask} what Task to be executed
   * @param {int} when Absolute time at which the task should be scheduled.
   */
  this.SetAlertDate = function (what, when) {
    var t = when - this.Start;
    this.SetAlertMillis(what, t);
  }
}

/**
 * Global timer used by the library for all the animations.
 */
var AnimeJGlobalTimer = new AnimeJTimer();

/**
 * @private
 * Helper function that is used by the setTimeout function to invoke
 * the timer.
 */
function AnimeJTimerTick() {
  var t = AnimeJGlobalTimer;
  var currt = t.Time() + 10;
  while (t.Heap.Count() > 0 && currt >= t.Heap.Top().Due) {
    var el = t.Heap.Remove();
    el.Task.DoAction(currt - el.Due);
  }
  if (t.Heap.Count() > 0) {
    currt = t.Time();
    AnimeJTimerRunning = setTimeout('AnimeJTimerTick()', t.Heap.Top().Due - currt);
  } else {
    AnimeJTimerRunning = null;
  }
}

/**
 * @private
 * @class Conversion functions used by interpolators. They interpolate
 * a range of values using a parameter between 0.0 and 1.0 which
 * represents a time fraction.
 */
function AnimeJConv() {}

/**
 * Interpolates a single integer value
 * @param {int} from Starting value
 * @param {int} to Ending value
 * @param {float} v A fraction between 0.0 and 1.0
 * @type int
 * @final
 */
AnimeJConv.Int = function (from, to, v) {
    return Math.floor(from + (to - from)*v);
  };

/**
 * Interpolates a single float value
 * @param {float} from Starting value
 * @param {float} to Ending value
 * @param {float} v A fraction between 0.0 and 1.0
 * @type float
 * @final
 */
AnimeJConv.Float = function (from, to, v) {
    return from + (to - from)*v;
  };

/**
 * Interpolates between two objects in a discrete fashion: if v is
 * less than 0.5 the first is returned the second otherwise.
 * @param {Object} from Starting value
 * @param {Object} to Ending value
 * @param {float} v A fraction between 0.0 and 1.0
 * @type Object
 * @final
 */
AnimeJConv.Discrete = function (from, to, v) {
    return v < 0.5 ? from : to;
  };
  
/**
 * Interpolates an array of integers
 * @param {Array} from Starting value
 * @param {Array} to Ending value
 * @param {float} v A fraction between 0.0 and 1.0
 * @type Array
 * @final
 */
AnimeJConv.IntList = function (from, to, v) {
    var ret = new Array(), i;
    for (i = 0; i < from.length; i++)
      ret.push(Math.floor(from[i] + (to[i] - from[i])*v));
    return ret;
  };

/**
 * Interpolates an array of floats
 * @param {Array} from Starting value
 * @param {Array} to Ending value
 * @param {float} v A fraction between 0.0 and 1.0
 * @type Array
 * @final
 */
AnimeJConv.FloatList = function (from, to, v) {
    var ret = new Array(), i;
    for (i = 0; i < from.length; i++)
      ret.push(from[i] + (to[i] - from[i])*v);
    return ret;
  };


/**
 * @private
 * @class Generalized linear interpolator used to interpolate
 * the argument of a function or an object property like a style.
 * The interpolation is linear but it is possible to specify an array of
 * linear segments unevenly distributed in the interval [0.0, 1.0] which
 * is the range of time (normalized). For instance the following is a way to
 * distribute interpolation for a value from 0 to 1000 in a way that the first
 * half the value changes linearly in the interval 0-50 and in the second half
 * in the interval 50-1000:<br/><br/>
 * [ { t: 0.0, v: 0 }, { t: 0.5, v: 50 }, { t: 1.0, v: 1000 } ]
 * @constructor
 * @param {Object} obj Either an object (like a style of a DOM node) or a function
 * with a single parameter which gets invoked for each change of the value.
 * @param {String} prop The property name to be changed, it is considered only in case
 * the obj parameter refers to an object.
 * @param {Array} steps Array of pairs { t: t, v: v } ORDERED by the field t. The
 * t field is a time value and should be in the interval [0.0, 1.0] and the first
 * and the last values for t MUST be 0.0 and 1.0 respectively. The field v defines the
 * value that should be set when time reaches the given value. Interpolation of values
 * is performed 
 * @param {Function} conv Conversion function to interpolate two values given a time
 * value in the range [0.0, 1.0] like those defined in AnimeJConv
 * @param {String} prefix Prefix string for the output value.
 * @param {String} suffix Suffix string for the output value (for instance 'px').
 * @exception If steps.length is less than two, or the sequence of steps is unordered
 * with respect to time, or does not begin by 0.0 nor end with 1.0.
 * @see AnimeJConv
 */
function AnimeJLinearInterpolator(obj, prop, steps, conv, prefix, suffix) {
  var i, last = 0.0;
  // typecheck steps
  if (steps.length < 2) throw "Invalid steps: length less than 2";
  if (steps[0].t != 0.0) throw "Invalid steps: timeline must start at 0.0!";
  if (steps[steps.length - 1].t != 1.0) throw "Invalid steps: timeline must end with 1.0!";
  for (i = 1; i < steps.length; i++) {
    if (steps[i].t > 1.0 || steps[i].t < 0.0 || steps[i].t <= last)
      throw "Invalid steps: invalid value "+(steps[i].t) +"!";
    last = steps[i].t;
  }

  /**
   * Computes a value given a time value in [0.0, 1.0]
   * @param {float} v Time value in the interval [0.0, 1.0]
   */
  this.Compute = function (v) {
    var idx;
    for (idx = 1; idx < steps.length; idx++)
      if (steps[idx].t >= v) break;
    
    idx--;
    var val = conv(steps[idx].v, steps[idx + 1].v, (v - steps[idx].t)/(steps[idx + 1].t - steps[idx].t));
    if (typeof(obj) == 'function')
      obj(val);
    else
      obj[prop] = prefix + val + suffix;
  }
}

/**
 * @private
 * @class Task for scheduling interpolators on the timer library.
 * The task is not trivial because it supports suspension and
 * resuming of tasks that means changing the absolute deadlines
 * inside the heap.
 * @constructor
 * @param {AnimeJLinearInterpolator} interp Interpolator to be used,
 * it can be an object with the Compute(v) function.
 * @param {int} ms Duration of the transition between 0.0 and 1.0 (and
 * consequently of the associated values).
 * @param {int} stepms The number of milliseconds between each value transition
 * (i.e. how frequent the value is changed).
 * @base AnimeJTask
 * @see AnimeJLinearInterpolator
 * @see AnimeJTimer
 */
function AnimeJInterpolatedTask(interp, ms, stepms) {
  /**
   * Duration of the whole transition in milliseconds.
   * @type {int}
   */
  this.Duration = ms;
  /**
   * Offset used to take into account suspension of task execution.
   * @type {int}
   */
  this.Start = - 1;

  /**
   * Invoked when the task is suspended, updates the internal state.
   */  
  this.OnPause = function() {
    if (this.Start != -1)
      this.Start = AnimeJGlobalTimer.Time() - this.Start;
  }
  
  /**
   * Invoked when the task is resumed, updates the internal state.
   */  
  this.OnResume = function() {
    if (this.Start != -1)
      this.Start = AnimeJGlobalTimer.Time() - this.Start;
  }
  
  /**
   * Invoked when the task is stopped, updates the internal state.
   */  
  this.OnStop = function() {
    this.Start = -1;
  }
    
  /**
   * It performs a step of animation by invoking the interpolator.
   * @param {int} d Delay in the notification with respect to the original deadline set.
   */  
  this.DoAction = function (d) {
    if (this.Start == -1)
      this.Start = AnimeJGlobalTimer.Time();
    
    var t = AnimeJGlobalTimer.Time();
    var v = (t - this.Start) / this.Duration;
    v = v > 1 ? 1 : v;
    interp.Compute(v);
    var t1 = AnimeJGlobalTimer.Time();
    var next = stepms - d + t1 - t; 
    if (v < 1)
      AnimeJGlobalTimer.SetAlertMillis(this, next);
    else
      this.Start = -1;
  }
}

/**
 * @private
 * @class Task used by the timeline to fire callbacks at the end of a timeline execution.
 * @constructor
 * @param {Timeline} t Timeline to be used to callback.
 * @param {String} prop Name of the property of the timeline holding the callback function.
 * @base AnimeJTask
 * @see AnimeJLinearInterpolator
 * @see AnimeJTimer
 */
function AnimeJTimelineCallBackTask(t, prop) {
  /**
   * Invoked when the task is paused, it does nothing.
   */  
  this.OnPause = function () {};

  /**
   * Invoked when the task is resumed, it does nothing.
   */  
  this.OnResume = function () {};

  /**
   * Invoked when the task is stopped, it does nothing.
   */  
  this.OnStop = function () {};

  /**
   * It invokes the specified callback on the property prop of the timeline t if defined.
   * @param {int} d Delay in the notification with respect to the original deadline set.
   */  
  this.DoAction = function (d) {
    if (t[prop])
      (t[prop])(d);
  }
}

/**
 * @private
 * @class Task used to invoke arbitrary functions when the task gets executed. The task is
 * fired only once.
 * @constructor
 * @param {Function} fun Function to be invoked when the task is executed, it may accept an integer
 * argument informing the delay of the execution with the expected deadline.
 * @base AnimeJTask
 * @see AnimeJLinearInterpolator
 * @see AnimeJTimer
 */
function AnimeJFunctionCallbackTask(fun) {
  /**
   * Invoked when the task is paused, it does nothing.
   */  
  this.OnPause = function () {};

  /**
   * Invoked when the task is resumed, it does nothing.
   */  
  this.OnResume = function () {};

  /**
   * Invoked when the task is stopped, it does nothing.
   */  
  this.OnStop = function () {};

  /**
   * It performs a step of animation by invoking the interpolator.
   * @param {int} d Delay in the notification with respect to the original deadline set.
   */  
  this.DoAction = function (d) {
    fun(d);
  }
}


/**
 * @class The timeline is the main interface to access the services of the animation library.
 * It features the classic interface to timeline in which tasks are scheduled at a given time
 * relative to the start of the execution. The SetAt method is meant for this purpose, and
 * an AnimeJTask should be provided. Usually the task is generated by one of the functions in
 * the AnimeJInterp class.<br/>
 * In the following example we have a text box that can be collapsed to left and vice versa.
 * This is the complete source code to show how expressive the library is:
 * <pre>
 * &lt;html&gt;
 * &lt;head&gt;
 * &lt;title&gt;Auto-hide text box&lt;/title&gt;
 * &lt;script type="text/javascript" src="..\..\src\AnimeJ.js"&gt;&lt;/script&gt;
 * &lt;script&gt;
 * function transition(btn) {
 *   var txt = btn.parentNode.childNodes[0];
 *   var t = new Timeline();
 *   if (txt.style.display == 'none') {
 *     txt.style.display = 'inline';
 *     t.SetAt(0, AnimeJInterp.px(1000, 30, txt.style, 'width', 0, 120));
 *     t.SetAt(0, AnimeJInterp.alpha(1000, 30, txt.style, 0.0, 1.0));
 *     t.OnEnd = function () { btn.innerHTML = '&amp;lt;&amp;lt;'; };
 *   } else {
 *     t.SetAt(0, AnimeJInterp.px(1000, 30, txt.style, 'width', 120, 0));
 *     t.SetAt(0, AnimeJInterp.alpha(1000, 30, txt.style, 1.0, 0.0));
 *     t.OnEnd = function (d) { btn.innerHTML = '&amp;gt;&amp;gt;'; txt.style.display = 'none'; };
 *   }
 *   t.Run();
 * }
 * &lt;/script&gt;
 * &lt;/head&gt;
 * &lt;body&gt;
 *   &lt;span&gt;
 *     &lt;input type="text" width="120px"&gt;&lt;/input&gt;
 *     &lt;span style="cursor: pointer; color: Blue" onclick="transition(this)"&gt;&amp;lt;&amp;lt;&lt;/span&gt;
 *   &lt;/span&gt;
 * &lt;/body&gt;
 * &lt;/html&gt;
 * </pre>
 * Note that the transition function simply prepares a timeline object t with a pixel interpolation
 * that changes the width property of the text box from 120 to 0 and vice versa. We also use fading by
 * changing the alpha during transition. Since the two transitions start at time 0 they run concurrently.
 * The OnEnd callback is used to update the text close to the text box.
 * @constructor
 * @see AnimeJInterp
 */
function Timeline() {
  var Paused = 0;
  var OnEndCB = null;
  var Data = {};
  var Running = false;
  
  /**
   * Tells wether the timeline is paused or not.
   * @type {bool}
   */
  this.IsPaused = function () {
    return Paused != 0;
  }
  
  /**
   * Check if the timeline is running.
   * Note that this will return true even if the timeline is paused. Use IsPaused()
   * to discriminate the actual status.
   * @type {bool}
   */
  this.IsRunning = function () {
    return Running;
  }

  /**
   * @private
   * Internal function used to raise the onend notification.
   */
  this.InternalOnEnd = function (d) {
    Runnning = false;
    if (this['OnEnd']) this['OnEnd'](d);
  }
  
  /**
   * Executes the timeline.
   */  
  this.Run = function () {
    Running = true;
    var max = 0;
    for (v in Data) {
      var el = Data[v];
      var startAt = parseInt(v);
      var i = 0;
      if (startAt > max) max = startAt;
      for (i = 0; i < el.length; i++) {
        if (el[i].Duration && (startAt + el[i].Duration) > max) max = startAt + el[i].Duration;
        AnimeJGlobalTimer.SetAlertMillis(el[i], startAt);
      }
    }
   var tm = this;
   OnEndCB = new AnimeJTimelineCallBackTask(tm, 'InternalOnEnd');
   AnimeJGlobalTimer.SetAlertMillis(OnEndCB, max);
  }

  /**
   * Schedule a task for execution at a given time from the start of the timeline.
   * @param {int} timems Milliseconds to be elapsed since the beginning of execution
   * before executing the task anim.
   * @param {AnimeJTask} task Task to be executed after timems elapsed.
   */
  this.SetAt = function (timems, task) {
    if (Data[timems])
      Data[timems].push(task);
    else
      Data[timems] = new Array(task);
  }

  /**
   * Stops the execution of the timeline by removing all the tasks from the scheduler.
   * The timeline should be started by invoking Run().
   */
  this.Stop = function () {
    Running = false;
    Paused = 0;
    var t = AnimeJGlobalTimer;
    var tm, i, v; 
    if (OnEndCB != null) {
      tm = t.RemoveTask(OnEndCB);
      OnEndCB = null;
    }
    
    for (v in Data) {
      var el = Data[v];
      for (i = 0; i < el.length; i++) {
        tm = t.RemoveTask(el[i]);
        el[i].OnStop();
      }
    }
  }


  /**
   * Pauses the execution of the current timeline. It can be resumed later on by invoking
   * the Resume() method.
   */  
  this.Pause = function () {
    if (Paused) return;
    Paused = 1;
    var t = AnimeJGlobalTimer;
    var tm, i, v; 
    if (OnEndCB != null) {
      tm = t.RemoveTask(OnEndCB);
      if (tm > -1)
        OnEndCB.Paused = tm;
      else
        OnEndCB = null;
    }
    
    for (v in Data) {
      var el = Data[v];
      for (i = 0; i < el.length; i++) {
        tm = t.RemoveTask(el[i]);
        if (tm == 0) tm = 1;// Hack: Paused == 0 is overloaded.
        el[i].OnPause();
        if (tm > -1)
          el[i].Paused = tm;
      }
    }
  }

  /**
   * Resumes the execution of a paused timeline.
   * @exception An exception is raised if the timeline is not paused.
   */
  this.Resume = function () {
    if (!Paused) throw "Timeline not paused!";
    Paused = 0;
    var t = AnimeJGlobalTimer;
    var tm, i, v; 
    if (OnEndCB != null) {
      t.SetAlertMillis(OnEndCB, OnEndCB.Paused);
      OnEndCB.Paused = 0;
    }
    
    for (v in Data) {
      var el = Data[v];
      for (i = 0; i < el.length; i++) {
        if (el[i].Paused) {
          t.SetAlertMillis(el[i], el[i].Paused);
          el[i].Paused = 0;
        }
        el[i].OnResume();
      }
    }
  }  
}

/**
 * Browser test. Used for setting alpha, but it can be useful in many other situations...
 */
var AnimeIsIE = navigator.appVersion.indexOf("MSIE") != -1;
var AnimeIEVer = AnimeIsIE ? parseFloat(navigator.appVersion.match(/MSIE\s([0-9\.]+)/)[1]) : -1;

/**
 * Setting the opacity is becoming more complicated (IE8 changed how alpha is handled
 * and still does not support the opacity attribute defined in CSS3). This function
 * is meant to hide these differences. Note that you must provide not the style object
 * but the whole object
 * @param {Object} obj Node to which the opacity should be applied
 * @param {float} value Opacity value expressed in 0-1 interval as CSS3 standard requires.
 */
function AnimeSetOpacity(obj, value) {
  if (AnimeIsIE) {
    //obj.filters.item("DXImageTransform.Microsoft.Alpha").Opacity = Math.floor(value * 100);
    obj.style.filter = "alpha(opacity=" + (Math.floor(value * 100)) + ")";
  } else {
    obj.style.opacity = value;
  }
}

/**
 * @class This class contains helpers for building interpolation tasks. It simply uses the
 * AnimeJLinearInterpolator in several different ways to ease common tasks. You can still
 * define your own interpolators. Apologize for interpolator names but they are conceived
 * to be short.
 */
function AnimeJInterp() {}

/**
 * Interpolates a pixel quantity (i.e. integer and appends px at the end).
 * @param {int} time Duration of the transition in milliseconds.
 * @param {int} tsteps Frequency (expressed in ms for an interval) at which
 * the property should be updated or the function called.
 * @param {Object} obj Object to set or function to invoke to set the value.
 * @param {Object} fromOrSteps If a number is given this is considered the starting value,
 * otherwise an array of steps is assumed as expected by AnimeJLinearInterpolator.
 * @param {int} to If specified (i.e. the fromOrSteps argument is an integer) it is
 * considered the target value for the interpolation.
 * @see AnimeJLinearInterpolator
 */
AnimeJInterp.px = function (time, tstep, obj, prop, fromOrSteps, to) {
    if (typeof(fromOrSteps) == 'number')
      fromOrSteps = [ { t: 0.0, v: fromOrSteps}, { t: 1.0, v: to } ];
    return new AnimeJInterpolatedTask(new AnimeJLinearInterpolator(obj, prop, fromOrSteps, AnimeJConv.Int, '', 'px'), time, tstep);
  };

  // Transparency from 0.0 to 1.0!
/**
 * Interpolates the alpha of an element in the appropriate way for the current browser.
 * @param {int} time Duration of the transition in milliseconds.
 * @param {int} tsteps Frequency (expressed in ms for an interval) at which
 * the property should be updated or the function called.
 * @param {Object} obj The object holding the alpha property to be changed.
 * @param {Object} fromOrSteps If a number between 0.0 (fully transparent) and 1.0
 * (totally opaque) is provided, this is considered the starting value;
 * otherwise an array of steps is assumed as expected by AnimeJLinearInterpolator.
 * @param {float} to If specified (i.e. the fromOrSteps argument is an integer) it is
 * considered the target value for the interpolation (should be a value in the range [0.0, 1.0].
 * @see AnimeJLinearInterpolator
 */
AnimeJInterp.alpha = function (time, tstep, obj, fromOrSteps, to) {
    if (typeof(fromOrSteps) == 'number')
      fromOrSteps = [ { t: 0.0, v: fromOrSteps}, { t: 1.0, v: to } ];

    var change = function (v) {
      AnimeSetOpacity(obj, v);
    }
    
    return new AnimeJInterpolatedTask(new AnimeJLinearInterpolator(change, null, fromOrSteps, AnimeJConv.Float, '', ''), time, tstep);
  };
  
/**
 * Interpolates an integer value and pass it to a funciton (fiv: function integer value).
 * @param {int} time Duration of the transition in milliseconds.
 * @param {int} tsteps Frequency (expressed in ms for an interval) at which
 * the property should be updated or the function called.
 * @param {Function} fun Function to be invoked with the current value.
 * @param {Object} fromOrSteps If a number is given this is considered the starting value,
 * otherwise an array of steps is assumed as expected by AnimeJLinearInterpolator.
 * @param {int} to If specified (i.e. the fromOrSteps argument is an integer) it is
 * considered the target value for the interpolation.
 * @see AnimeJLinearInterpolator
 */
AnimeJInterp.fiv = function (time, tstep, fun, fromOrSteps, to) {
    if (to)
      fromOrSteps = [ { t: 0.0, v: fromOrSteps}, { t: 1.0, v: to } ];
    return new AnimeJInterpolatedTask(new AnimeJLinearInterpolator(fun, null, fromOrSteps, AnimeJConv.Int, '', ''), time, tstep);
  };

/**
 * Interpolates a float value and pass it to a funciton (ffv: function float value).
 * @param {int} time Duration of the transition in milliseconds.
 * @param {int} tsteps Frequency (expressed in ms for an interval) at which
 * the property should be updated or the function called.
 * @param {Function} fun Function to be invoked with the current value.
 * @param {Object} fromOrSteps If a number is given this is considered the starting value,
 * otherwise an array of steps is assumed as expected by AnimeJLinearInterpolator.
 * @param {float} to If specified (i.e. the fromOrSteps argument is a float) it is
 * considered the target value for the interpolation.
 * @see AnimeJLinearInterpolator
 */
AnimeJInterp.ffv = function (time, tstep, fun, fromOrSteps, to) {
    if (to)
      fromOrSteps = [ { t: 0.0, v: fromOrSteps}, { t: 1.0, v: to } ];
    return new AnimeJInterpolatedTask(new AnimeJLinearInterpolator(fun, null, fromOrSteps, AnimeJConv.Float, '', ''), time, tstep);
  };

/**
 * Interpolates an array of integers and pass it to a funciton (fia: function int array).
 * @param {int} time Duration of the transition in milliseconds.
 * @param {int} tsteps Frequency (expressed in ms for an interval) at which
 * the property should be updated or the function called.
 * @param {Function} fun Function to be invoked with the current value.
 * @param {Array} fromOrSteps If the to argument is given this is considered the starting value,
 * otherwise an array of steps is assumed as expected by AnimeJLinearInterpolator.
 * @param {Array} to If specified (i.e. the fromOrSteps argument is considered to be an array of int) it is
 * considered the target value for the interpolation.
 * @see AnimeJLinearInterpolator
 */
AnimeJInterp.fia = function (time, tstep, fun, fromOrSteps, to) {
    if (to)
      fromOrSteps = [ { t: 0.0, v: fromOrSteps}, { t: 1.0, v: to } ];
    return new AnimeJInterpolatedTask(new AnimeJLinearInterpolator(fun, null, fromOrSteps, AnimeJConv.IntList, '', ''), time, tstep);
  };

/**
 * Interpolates an array of floats and pass it to a funciton (ffa: function float array).
 * @param {int} time Duration of the transition in milliseconds.
 * @param {int} tsteps Frequency (expressed in ms for an interval) at which
 * the property should be updated or the function called.
 * @param {Function} fun Function to be invoked with the current value.
 * @param {Array} fromOrSteps If the to argument is given this is considered the starting value,
 * otherwise an array of steps is assumed as expected by AnimeJLinearInterpolator.
 * @param {Array} to If specified (i.e. the fromOrSteps argument is considered to be an array of float) it is
 * considered the target value for the interpolation.
 * @see AnimeJLinearInterpolator
 */
AnimeJInterp.ffa = function (time, tstep, fun, fromOrSteps, to) {
    if (to)
      fromOrSteps = [ { t: 0.0, v: fromOrSteps}, { t: 1.0, v: to } ];
    return new AnimeJInterpolatedTask(new AnimeJLinearInterpolator(fun, null, fromOrSteps, AnimeJConv.FloatList, '', ''), time, tstep);
  };
