/**
	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.Motion   = 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.Motion  [dAnim.Motion.length] = div+":=>"+module;
	dAnim.Actions [div+":=>"+module]    = { trigger: module, div: div };
	
	dAnim._StartAnimation();
}

dAnim.GetAct      = function(module, div){
	return dAnim.Actions[div+":=>"+module];
}
dAnim.GetSettings = function(module, div){
	return dAnim.Settings[div+":=>"+module];
}

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 k=0; k < dAnim.Motion.length; k++){
		var div_name = dAnim.Motion[k];
		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++;
		
		// Último frame atingido.
		if(isLast){
			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 = dAnim.Motion.length;
	
	// 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;
	var new_m = new Array;
	for(var i = 0; i < dAnim.Motion.length; i++){
		var idx = dAnim.Motion[i];
		if(idx != index){
			new_r[idx] = dAnim.Actions[idx];
			new_m[new_m.length] = idx;
		}
	}
	dAnim.Actions = new_r;
	dAnim.Motion  = new_m;
}

var __isIE         = navigator.appVersion.match(/MSIE/);
var __userAgent    = navigator.userAgent;
var __isFireFox    = __userAgent.match(/firefox/i);
dAnim._getElementAbsPos = function(obj){
    var res = new Object();
    res.x = 0; res.y = 0;
    if (obj !== null) {
        res.x = obj.offsetLeft;
        res.y = obj.offsetTop;
        
        var offsetParent = obj.offsetParent;
        var parentNode = obj.parentNode;
        var borderWidth = null;

        while (offsetParent != null) {
            res.x += offsetParent.offsetLeft;
            res.y += offsetParent.offsetTop;
            
            var parentTagName = offsetParent.tagName.toLowerCase();    

            if ((__isIE && parentTagName != "table") || 
                (parentTagName == "td")) {            
                borderWidth = dAnim._geabp2(offsetParent);
                res.x += borderWidth.left;
                res.y += borderWidth.top;
            }
            
            if (offsetParent != document.body && 
                offsetParent != document.documentobj) {
                res.x -= offsetParent.scrollLeft;
                res.y -= offsetParent.scrollTop;
            }

            //next lines are necessary to support FireFox problem with offsetParent
               if (!__isIE) {
                while (offsetParent != parentNode && parentNode !== null) {
                    res.x -= parentNode.scrollLeft;
                    res.y -= parentNode.scrollTop;
                    parentNode = parentNode.parentNode;
                }    
            }

            parentNode = offsetParent.parentNode;
            offsetParent = offsetParent.offsetParent;
        }
    }
    return res;
}
dAnim._geabp1           = function(width){   // parseBorderWidth
    var res = 0;
    if (typeof(width) == "string" && width != null 
                && width != "" ) {
        var p = width.indexOf("px");
        if (p >= 0) {
            res = parseInt(width.substring(0, p));
        }
        else {
             //do not know how to calculate other 
             //values (such as 0.5em or 0.1cm) correctly now
             //so just set the width to 1 pixel
            res = 1; 
        }
    }
    return res;
}
dAnim._geabp2           = function(element){ // getBorderWidth
	var res   = new Object();
    res.left = 0; res.top = 0; res.right = 0; res.bottom = 0;
    if (window.getComputedStyle) {
        //for Firefox
        var e  = window.getComputedStyle(element, null);
		var pi = parseInt;
        res.left    = pi(e.borderLeftWidth  .slice(0, -2));  
        res.top     = pi(e.borderTopWidth   .slice(0, -2));  
        res.right   = pi(e.borderRightWidth .slice(0, -2));  
        res.bottom  = pi(e.borderBottomWidth.slice(0, -2));  
    }
    else {
		var parse = dAnim._geabp1;
		var es    = element.style;
        res.left   = parse(es.borderLeftWidth);
        res.top    = parse(es.borderTopWidth);
        res.right  = parse(es.borderRightWidth);
        res.bottom = parse(es.borderBottomWidth);
    }
   
    return res;
}

