﻿/* Animator class. Copyright by ADenis (adeniss@ukr.net) */

function Animator(){
	
	var activeAnimations = 0;	
	var animationArray = new Array();
	
	this.debug = false;

	var request = parseHTMLArgs();
	
	if(request["debug"]){
		this.debug = true;
	}
	
	this.add =  function (object, attribute, startValue, finishValue, absolute, timeLength, listener, handler, filter) {
		this.animateObj(object, attribute, startValue, finishValue, absolute, timeLength, listener, handler, filter);
	}
	
	this.animateObj =  function (object, attribute, startValue, finishValue, absolute, timeLength, listener, handler, filter){			
		
		var valueSuffix = getValueSuffix(startValue);
		valueSuffix = (valueSuffix == "")?getValueSuffix(finishValue):valueSuffix;
		
		startValue = parseFloat(startValue);
		finishValue = parseFloat(finishValue);
		
		startValue = isNaN(startValue)?0:startValue;
		
		if(!absolute){
			if(!isNaN(parseFloat(object[attribute]))){
				startValue = startValue + parseFloat(object[attribute]);
				finishValue = finishValue + parseFloat(object[attribute]);
			}
		}
			
		//alert("startValue "+ startValue + " finishValue " + finishValue);

		if(this.debug)
			alert("Animator: " + object + " " + attribute + "(" + startValue + "," + finishValue + ")");

		if(startValue == finishValue){
			if(listener && handler){				
				handler.call(listener, object, attribute);
			}
			return;
		}
		
		var step = (finishValue - startValue) / (timeLength * 1000 / 20);
		
		object[attribute] = startValue + valueSuffix;
		
		this.addToAnimationArray(object, attribute, startValue, finishValue, absolute, timeLength, listener, handler, filter, step);
	}

	this.addToAnimationArray =  function (object, attribute, startValue, finishValue, absolute, timeLength, listener, handler, filter, step){
		var index = this.checkDuplicatedAnimation(object, attribute);
		
		if(index != -1){
			delete animationArray[index];
		}else{
			index = animationArray.length;
		}
		
		animationArray[index] = new AnimationElement();
		animationArray[index].object = object;
		animationArray[index].attribute = attribute;
		animationArray[index].startValue = startValue;
		animationArray[index].finishValue = finishValue;
		animationArray[index].value = startValue;
		animationArray[index].absolute = absolute;
		animationArray[index].timeLength = timeLength;	
		animationArray[index].listener = listener;
		animationArray[index].filter = filter;
		animationArray[index].step = step;
		animationArray[index].handler = handler;
		animationArray[index].active = true;
		
		activeAnimations++;				

		addUpdateListener(this, this.update);
	}

	this.checkDuplicatedAnimation =  function(object, attribute){
		if(animationArray){
			for(var i in animationArray){
				if((object == animationArray[i].object) && (attribute == animationArray[i].attribute)){
					return i;
				}
			}
		}
		return -1;
	}
	
	this.update =  function (){		
		if(animationArray && (activeAnimations > 0)){
			for(var i in animationArray){
				
				if(animationArray[i].active){
					
					var stopAnimation = false;
					var step = 0;
					var valueSuffix = getValueSuffix(animationArray[i].object[animationArray[i].attribute]);
					
					if(animationArray[i].filter){
						if(animationArray[i].filter == "parabola")
							step = parabolaStep(animationArray[i]);
					}else{
						step = animationArray[i].step;						
					}
					
					var newValue = animationArray[i].value + step;
					
					if(step > 0){
						if(newValue > animationArray[i].finishValue){
							stopAnimation = true;							
						}
					}else if(step < 0){
						if(newValue < animationArray[i].finishValue){
							stopAnimation = true;
						}
					}else{
						stopAnimation = true;
					}
					
					if(stopAnimation){
						newValue = animationArray[i].finishValue;
						animationArray[i].active = false;
						activeAnimations --;
					}
					animationArray[i].value = newValue;	
					
					if(valueSuffix != "")
						newValue = newValue + valueSuffix;
					
					if(setAttribute(animationArray[i].object, animationArray[i].attribute, newValue)){
						//alert("Animating object " + animationArray[i].object + " " + animationArray[i].attribute + "=" + newValue);
						//alert(animationArray[i].object[animationArray[i].attribute]);
						//document.getElementById('message').innerHTML = animationArray[i].object[animationArray[i].attribute];
					}
					
					if(stopAnimation){
						var listener = animationArray[i].listener;
						var handler = animationArray[i].handler;

						if(this.debug)
							alert("Animator: STOP ANIMATION " + animationArray[i].object + " " + animationArray[i].attribute + "(" +newValue + ")");

						if (listener && handler) {
							handler.call(listener, animationArray[i].object, animationArray[i].attribute);
						} else if (handler) {
							handler = parseFunction(handler);
							handler(animationArray[i].object, animationArray[i].attribute);
						}
					}
				}
			}
		}else{
			removeUpdateListener(this, this.update);
		}
	}
	
	this.isPartOfAnimation = function (object){
		if(animationArray && (activeAnimations > 0)){			
			for(var i in animationArray){				
				if(animationArray[i].active && animationArray[i].object == object){
					return true;
				}
			}
		}
		return false;
	}
	
	this.remove = function (object) {
		return this.removeFromAnimation(object);
	}
	
	this.removeFromAnimation = function (object){
		if(animationArray && (activeAnimations > 0)){			
			for(var i in animationArray){				
				if(animationArray[i].active && animationArray[i].object == object){
					animationArray[i].active = false;
					activeAnimations --;
				}
			}
		}
		return false;
	}

	var parabolaStep = function (object){
				
		object.i = isNaN(object.i)?0:object.i;
		object.i++;
		
		var dValue = object.finishValue - object.startValue;
		var value = parseFloat(object.object[object.attribute]);
		var time = object.timeLength * 1000 / 20;
		
		value = isNaN(value)?0:value;
		value = value - object.startValue;		
		value = value?value:dValue/time;

		var a = -12*dValue/(time*time*time);
		var V = -a*time/2;

		var maxStep = 2*dValue/time;
		var step = V*object.i + (a*object.i*object.i)/2;
		
		return step;
	}
}

function AnimationElement() {
	this.object = null;
	this.attribute = "";
	this.startValue = 0;
	this.finishValue = 0;
	this.value = 0;
	this.timeLength = 0;
	this.abolute = false;
	this.step = 0;
	this.active = false;
	this.listener = null;
	this.handler = null;
	this.filter = null;	
}


function ClipAnimator(tobject){	
	var object = tobject;
		
	this.top = "0px";
	this.left = "0px";
	this.bottom = "0px";		
	this.right = "0px";
	
	if(object){
		this.bottom = object.clientHeight+"px";		
		this.right = object.clientWidth+"px";
	}
	
	this.ontop = function(value){
		this.top = parseInt(value)+"px";
		this.update();
	}
	this.onbottom = function(value){
		this.bottom = parseInt(value)+"px";
		this.update();
	}
	this.onleft = function(value){
		this.left = parseInt(value)+"px";
		this.update();
	}
	this.onright = function(value){
		this.right = parseInt(value)+"px";
		this.update();
	}
	
	this.update = function(){
		var rect = "rect("+this.top+","+this.right+","+this.bottom+","+this.left+")";
		//alert(rect);
		object.style.clip = rect;

	}	
}

var ANIMATOR = null;

function getAnimator() {
	if (!ANIMATOR) {
		ANIMATOR = new Animator();
	}
	
	return ANIMATOR;
}