// Animator class
//
// Maintain a list of objects that need an animate() call performed at some interval.
//
var Animator=new Object();

Animator.work=new Array();
Animator.next=0;

// Add an object to be animated
//
Animator.add=function(interval, aObject, aMethod /* ,arg, ...*/) {
	var a=new Object();						// Create an object to hold properties for this animation
	a.interval=interval;					// Animation interval
	a.obj=(aObject==null?window:aObject);	// Object, or window for global methods
	a.method=aMethod;						// Method
	a.args=new Array();						// and optional parameters
	for (var i=3; i<arguments.length; i++) {
		a.args.push(arguments[i]);
	}
	a.nextAnimate=interval;					// Wait interval before catching this request
	Animator.work.push(a);					// Add to end of list of objects under animation
	Animator.next=10000000;					// Find time til next work
	for (var i=0; i<Animator.work.length; i++) {
		if (Animator.work[i].nextAnimate<Animator.next) Animator.next=Animator.work[i].nextAnimate;
	}
	if (Animator.next==0) Animator.next=10;
	if (Animator.timer) clearTimeout(Animator.timer);	// Clear existing timer and set new one
	Animator.timer=setTimeout('Animator.intervalCheck()', Animator.next);
};

// An an object to be called one time; useful for things that need to happen outside the
// normal thread of execution.
//
Animator.once=function(/* aObject, aMethod, arg, ... */) {
	var a=new Array();
	a.push(10);								// Interval for one-shot calls is 10 (the minimum)
	for (var i=0; i<arguments.length; i++) {
		a.push(arguments[i]);				// Other arguments are the same as for add()
	}
	Animator.add.apply(window, a);			// Use add() to do the rest of our work
}

// This is the method that maintains and responds to timer events
//
Animator.intervalCheck=function() {
	var i=0;
	while (i<Animator.work.length) {
		Animator.work[i].nextAnimate-=Animator.next;		// Remove elapsed time
		if (Animator.work[i].nextAnimate<=0) {				// Needs animated; call it
			var ca=false;									// Verify that animation needs to continue
			try {
				ca=Animator.work[i].method.apply(Animator.work[i].obj, Animator.work[i].args);
			} catch (err) {
				ca=false;
			}
			if (ca && Animator.work[i].interval>0) {		// Returned true and has non-zero interval; keep
				Animator.work[i].nextAnimate+=Animator.work[i].interval;
			} else {										// Animation complete; remove from list
				if (i>0) {
					Animator.work[i]=Animator.work[0];		// Copy element 0 to here
				}
				Animator.work.shift();						// Remove first element
				i--;										// Don't skip something in loop
			}
		}
		i++;
	}
	if (Animator.timer) clearTimeout(Animator.timer);
	delete Animator.timer;
	if (Animator.work.length>0) {
		Animator.next=10000000;					// Find time til next work
		for (var i=0; i<Animator.work.length; i++) {
			if (Animator.work[i].nextAnimate<Animator.next) Animator.next=Animator.work[i].nextAnimate;
		}
		if (Animator.next==0) Animator.next=10;
		Animator.timer=setTimeout('Animator.intervalCheck()', Animator.next);
	}
};
