/**
	Método importante:
		AddModule(id, callback)
		CreateAnimation(module, div, settings)
	
	Settings internas:
		delay
		end_trigger
**/
function dAnim(){}
dAnim.Init             = function(){
	if(!dAnim.Initialized){
		dAnim.Initialized = true;
		dAnim.Modules  = new Array;
		dAnim.Actions  = new Array; // Store running motions
		dAnim.Settings = new Array;
		dAnim.Timer    = false;
		dAnim.Interval = 1000/60; // (1000 / FPS)
	}
}
dAnim.AddModule        = function(id, callback){
	dAnim.Init();
	
	if(!callback){
		alert("dAnim: Erro adicionando módulo "+id+", callback não encontrado.");
		return;
	}
	
	if(!dAnim.Modules[id])
		dAnim.Modules[id] = callback;
}

dAnim.CreateAnimation  = function(module, div, settings){
	dAnim.Settings[div+":=>"+module] = settings;
	if(!dAnim.Settings[div+":=>"+module].delay){
		alert("Cannot proceed, setting 'delay' not found.");
		return false;
	}
	
	dAnim.Actions [div+":=>"+module] = { trigger: module, div: div };
	dAnim._StartAnimation();
}

dAnim._CalcEase        = function(effect, rate, multiplier, funct){
	// http://www.pixelwit.com/blog/2007/06/27/actionscript-easing-functions/
	r = rate;
	p = multiplier;
	f = funct;
	if(effect == 'easeIn'){
		if(p == undefined) p = 2;
		if(typeof f != "function") f = Math.pow;
		return f(r, p);
	}
	if(effect == 'easeOut'){
		return 1-dAnim._CalcEase('easeIn', 1-r, p, f);
	}
	if(effect == 'easeInOut'){
		if(r<.5) return dAnim._CalcEase('easeIn', r*2, p, f)/2;
		return .5+dAnim._CalcEase('easeOut', (r-.5)*2, p, f)/2;
	}
	if(effect == 'easeOutIn'){
		if(r<.5) return dAnim._CalcEase('easeOut', r*2, p, f)/2;
		return .5+dAnim._CalcEase('easeIn', (r-.5)*2, p, f)/2;
	}
	
	// Unknown effect?
	return rate;
}
dAnim._StartAnimation  = function(){
	if(dAnim.Timer){
		return;
	}
	dAnim.Timer = setTimeout('dAnim._UpdateAnimation()', dAnim.Interval);
}
dAnim._StopAnimation   = function(){
	if(dAnim.Timer){
		clearTimeout(dAnim.Timer);
		dAnim.Timer = false;
	}
}
dAnim._UpdateAnimation = function(){
	var _AnimCount = 0;
	for(var div_name in dAnim.Actions){
		var act = dAnim.Actions[div_name];
		var set = dAnim.Settings[div_name];
		var obj = act.div?document.getElementById(act.div):false;
		var _pc = 0;
		
		if(!obj && act.div){
			alert("Cannot animate object '"+act.div+" ("+div_name+")' - Not found!");
			continue;
		}
		
		// Atualiza o time elapsed da animação atual
		if(!act.time_elapsed)    act.time_elapsed    = 0;
		if(!act.time_frames)     act.time_frames     = 0;
		if(!act.timestamp_start) act.timestamp_start = (new Date()).getTime()-dAnim.Interval;
		
		act.time_elapsed  = (new Date()).getTime()-act.timestamp_start;
		act.time_frames  += 1;
		
		// Define a porcentagem da animação (_pc)
		_pc = ((act.time_elapsed*100)/set.delay);
		if(_pc > 100)
			_pc = 100;
		
		// Define isFirst e isLast
		var isFirst = (act.time_frames==1);
		var isLast  = (_pc==100);
		
		for(var module in dAnim.Modules){
			dAnim.Modules[module](set, obj, act, _pc, isFirst, isLast);
		}
		
		_AnimCount++;
		
		// Se alcançou o tempo maximo, 
		if(act.time_elapsed >= set.delay){
			dAnim._FinishAction(div_name);
			_AnimCount--;
			
			// Dispara o callback
			if(set.end_trigger)
				set.end_trigger(set, obj);
		}
	}
	
	// Reseta o contador e verifica se novas ações foram adicionadas
	_AnimCount = 0;
	for(var div_name in dAnim.Actions)
		_AnimCount++;
	
	// Se ainda tiver animação a ser executada, continue o loop.
	if(_AnimCount){
		dAnim._StopAnimation();
		dAnim.Timer = setTimeout('dAnim._UpdateAnimation()', dAnim.Interval);
	}
	else{
		dAnim._StopAnimation();
	}
}
dAnim._FinishAction    = function(index){
	var new_r = new Array;
	for(var idx in dAnim.Actions){
		if(idx != index)
			new_r[idx] = dAnim.Actions[idx];
	}
	dAnim.Actions = new_r;
}
