YAHOO.namespace("OPS");

YAHOO.OPS.AnimMgr = function() {
    this.createEvent('complete');
    this._onComplete = new YAHOO.util.CustomEvent('complete', this, true);
    this._onStart = new YAHOO.util.CustomEvent('_start', this, true);
    this._onTween = new YAHOO.util.CustomEvent('_tween', this, true);
    this.anims = new Array();
    this.curTime = 0;
    this.endTime = 0;
    this._onTween.subscribe(this.tick, this, true);
    this._onStart.subscribe(this.handleStart, this, true);
    this._onComplete.subscribe(this.handleComplete, this, true);
    this.nReady = 0;
    this.debugTick = 0;
    this.autoStart = true;
};

YAHOO.OPS.AnimMgr.prototype = {
    add: function(o) {
	var anim = {o: o};
	this.anims.push(anim);
	return this.anims.length-1;
    }

    , getStartTime: function() {
	if(!this.startTime)
	    this.startTime = new Date();
	return this.startTime;
    }

    , handleComplete: function(e, o) {
	opsDebugDump('complete', e, 1);
	for(var i in this.anims) {
	    var anim = this.anims[i];
	    if(!anim.nSteps)
		continue;
	    if(anim.startAt > this.curTime)
		continue;
	    if(anim.endAt < this.curTime)
		continue;
	    while(anim.stepNo < anim.nSteps) {
		opsDebug('curTime='+this.curTime+' stepNo='+anim.stepNo);
		anim.o.tick({
		    duration: this.curTime-anim.startAt
		    , currentFrame: this.currentFrame
		    , stepNo: anim.stepNo
		}, anim);
		anim.stepNo++;
	    }
	}
    }

    , handleStart: function(e, o) {
	opsDebugDump('start', e, 1);
    }

    , isAnimated: function() {
	return this.hasAnimation;
    }

    , queue: function(id, o, delay) {
	if(!o.nSteps)
	    o.nSteps = 0;
	if(!o.duration)
	    o.duration = 10;
	if(!delay)
	    delay = 0;
	this.anims[id] = {
	    o: o
	    , nSteps: o.nSteps
	    , duration: o.duration
	    , startAt: this.curTime+(1000*delay)
	    , endAt: this.curTime+(1000*delay)+(1000*o.duration)
	    , isCompleted: false
	};
	if(o.nSteps) {
	    this.anims[id].stepNo = 0;
	    this.anims[id].stepSize = (1000*o.duration)/o.nSteps;
	}
	if(this.anims[id].endAt > this.endTime)
	    this.endTime = this.anims[id].endAt;
	this.hasAnimation = true;
	this.nReady++;
	if(this.nReady == this.anims.length && this.autoStart) {
	    this.start();
	}
    }

    , reset: function() {
	this.startTime = null;
	this.curTime = 0;
	this.currentFrame = 0;
	this.totalFrames = null;
    }

    , start: function() {
	this.reset();
	this.curTime = new Date() - this.getStartTime();
	//this.endTime += this.curTime;
	opsDebug('endTime='+this.endTime);
	YAHOO.util.AnimMgr.registerElement(this);
    }

    , stop: function() {
	opsDebug('DONE!');
	YAHOO.util.AnimMgr.unRegister(this);
	this.reset();
    }

    , tick: function(type, data) {
	//opsDebugDump('data', data, 1);
	this.curTime = new Date() - this.getStartTime();
	if(this.curTime > this.endTime) {
	    this.stop();
	    return;
	}

	var hasAnimation = false;
	for(var i in this.anims) {
	    var anim = this.anims[i];
	    if(anim.startAt > this.curTime)
		continue;
	    if(!anim.nSteps && anim.endAt < this.curTime) {
		if(!anim.isCompleted)
		    anim.o.complete(anim);
		this.anims[i].isCompleted = true;
		continue;

	    } else if(!anim.nSteps) {
		//opsDebug('curTime='+this.curTime+' unlimited steps');
		anim.o.tick({
		    duration: this.curTime-anim.startAt
		    , currentFrame: this.currentFrame
		}, anim);
		hasAnimation = true;

	    } else if(anim.stepNo >= anim.nSteps) {
		if(!anim.isCompleted)
		    anim.o.complete(anim);
		this.anims[i].isCompleted = true;
		continue;

	    } else {
		while(anim.stepNo < anim.nSteps && (this.curTime-anim.startAt) > anim.stepNo*anim.stepSize) {
		    //opsDebug('curTime='+this.curTime+' stepNo='+anim.stepNo+' of '+anim.nSteps);
		    anim.o.tick({
			duration: this.curTime-anim.startAt
			, currentFrame: this.currentFrame
			, stepNo: anim.stepNo
		    }, anim);
		    anim.stepNo++;
		    hasAnimation = true;
		}
	    }
	}
	//this.hasAnimation = hasAnimation;
	//opsDebug('isAnimated='+this.hasAnimation);
    }

};

YAHOO.lang.augmentProto(YAHOO.OPS.AnimMgr, YAHOO.util.EventProvider);

//var opsAnimMgr = new YAHOO.OPS.AnimMgr();

