//

kkjs.uebergaenge = {
	runStyleAttributeToValue: function runStyleAttributeToValue(att){
		if (!kkjs.is.object(att)) return kkjs.Debug.error("Argument muss ein Objekt sein.");
		
		if (!kkjs.is.node(att.node)) return kkjs.Debug.error("Eine Node muss im Argumentsobjekt übergeben werden (key: node)");
		if (kkjs.is.array(att.attribute)){
			var ret = new Array();
			for (var i = 0; i < att.attribute.length; i++){
				var nAtt = new Object();
				nAtt.attribute = att.attribute[i];
				for (var n in att){
					if (n != "attribute"){
						if (kkjs.is.array(att[n])){
							nAtt[n] = att[n][i];
						}
						else {
							nAtt[n] = att[n];
						}
					}
				}
				ret.push(arguments.callee.call(this, nAtt));
			}
			return ret; 
		}
		if (!kkjs.is.string(att.attribute)) return kkjs.Debug.error("Eine String zur Identifizierung eines Styleattributs muss im Argumentsobjekt übergeben werden (key: attribute)");
		if (att.attribute == "opacity"){
			if (kkjs.is.key(att.node.style, "opacity")){
				att.toValue /= 100;
				if (!kkjs.is.undefined(att.fromValue)) att.fromValue /= 100;
				else{
					var o = 1;
					if ((o = kkjs.getStyle(att.node, "opacity")) != ""){
						att.fromValue = parseFloat(o);
					}
					else {
						att.fromValue = 1;
					}
				}
			}
			else if (kkjs.is.key(att.node.style, "filter")){
				if (kkjs.is.undefined(att.fromValue)){
					var found = /opacity=(\d+)/i.exec(att.node.style.filter);
					if (found) att.fromValue = found[1];
					else att.fromValue = 100;
				}
				att.attribute = "filter";
				att.praefix = "Alpha(opacity=";
				att.postfix = ")";
				att.unit = "";
			}
		}
		
		if (!kkjs.is.number(att.toValue)) att.toValue = 0;
		var foundFromValue = parseInt(att.node.style[att.attribute]);
		if (!kkjs.is.number(att.fromValue)) att.fromValue = foundFromValue;
		if (isNaN(att.fromValue)) att.fromValue = 0;
		
		if (!kkjs.is.string(att.unit)){
			att.unit = /[^0-9]*$/.exec(att.node.style[att.attribute])[0];
		} 
		if (att.fromValue == att.toValue){
			return;
		}
		
		if (typeof att.shape == "function"){
			kkjs.uebergaenge.functions.userDefined = att.shape;
			att.shape = "userDefined";
		}
		if (!kkjs.is.string(att.shape)) att.shape = "linear";
		if (!kkjs.is.number(att.timeconstant)) att.timeconstant = 20;
		
		if (!kkjs.is.number(att.steps)){
			if (kkjs.is.number(att.duration)){
				att.steps = att.duration * 1000 / att.timeconstant;
			}
			else{
				att.steps = 100;
			}
		}
		var path = new Array();
		for (var i = 0; i <= att.steps; i++){
			var newPoint = kkjs.uebergaenge.functions[att.shape](att.fromValue, att.toValue, i / att.steps) + att.unit;
			if (att.mustRound) newPoint = Math.round(newPoint);
			if (newPoint < 0 && att.notNegative) newPoint = 0;
			path.push(newPoint);
		}
		
		/*
		if (!kkjs.is.number(att.stepwidth)){
			if (kkjs.is.number(att.duration)){
				att.stepwidth = Math.round((att.toValue - att.fromValue) / (att.duration * 1000) * att.timeconstant);
				if (att.stepwidth == 0){
					att.stepwidth = 1;
					att.timeconstant = Math.round((att.duration * 1000) / Math.abs(att.toValue - att.fromValue));
				}
			}
			else if(kkjs.is.number(att.speed) && att.speed != 0){
				att.stepwidth = Math.round(att.speed * att.timeconstant / 1000);
				if (att.stepwidth == 0){
					att.stepwidth = 1;
					att.timeconstant = Math.round(1000 / att.speed);
				}
			}
			else{
				att.stepwidth = 1;
			}
		}
		
		att.stepwidth = Math.abs(att.stepwidth) * (att.toValue - att.fromValue) / Math.abs(att.toValue- att.fromValue);
		
		var path = new Array();
		for (var i = att.fromValue; Math.abs(i - att.toValue) > Math.abs(att.stepwidth); i += att.stepwidth){
			path.push(i + att.unit);
		}
		if (i != att.toValue + att.stepwidth){
			path.push(att.toValue+ att.unit);
		}
		*/
		
		att.path = path;
		att.object = att.node.style;
		kkjs.uebergaenge.runAttributeByPath(att);
	},
	
	functions: {
		linear: function(start, ende, pos){
			return start + pos * (ende - start);
		},
		quadratic_start: function(start, ende, pos){
			return start + pos*pos * (ende - start);
		},
		quadratic_end: function(start, ende, pos){
			pos = 1 - pos;
			return ende + pos*pos * (start - ende);
		},
		sinus: function(start, ende, pos){
			return start + (1 - Math.cos(Math.PI * pos))/ 2 * (ende - start);
		},
		cosinus: function(start, ende, pos){
			return start + (1 - Math.acos(pos * 2 - 1)/Math.PI) * (ende - start);
		},
		ellipse1: function(start, ende, pos){
			return start + Math.sin(pos * Math.PI / 2) * (ende - start);
		},
		ellipse2: function(start, ende, pos){
			return start + (1 - Math.cos(pos * Math.PI / 2)) * (ende - start);
		},
		bounce_sinus: function(start, ende, pos){
			pos *= 2.5 * Math.PI;
			return ende + Math.abs(Math.cos(pos)*Math.exp(-0.5*pos))*(start - ende);
		},
		bounce: function(start, ende, pos){
			var sqrt04 = 0.6324555320;
			var a = 3.39;
			var anteil = 0;
			if (pos*a < 1){
				anteil = 1 - pos*pos*a*a;
			}
			else if(pos*a < 1 + 2*sqrt04){
				anteil = 0.4 - Math.pow(pos*a  - 1 - sqrt04, 2);
			}
			else if(pos*a < 1 + 2*sqrt04 + 2*0.4){
				anteil = 0.16 - Math.pow(pos*a  - 1 - 2*sqrt04 - 0.4, 2);
			}
			else{
				anteil = 0.0256 - Math.pow(pos*a  - 1 - 2*sqrt04 - 2*0.4 - 0.16, 2);
			}
			
			return ende + anteil * (start - ende);
		},
		swing: function(start, ende, pos){
			pos *= 2.5 * Math.PI;
			return ende + (Math.cos(pos)*Math.exp(-0.5*pos))*(start - ende);
		},
		exponential_start: function(start, ende, pos){
			return start + (Math.exp(pos) - 1)/(Math.E - 1) * (ende - start);
		},
		exponential_end: function(start, ende, pos){
			pos = 1 - pos;
			return ende + (Math.exp(pos) - 1)/(Math.E - 1) * (start - ende);
		}
	},
	
	runReference: new Object(),
	
	runAttributeByPath: function runAttributeByPath(att){
		//att.object soll Referenz auf das zu ändernde Objekt sein
		//att.attribute soll der Name des Attributes sein
		//att.path sollen die einzelnen Stationen des Pfades als Array
		//att.timeconstant soll die Zeit zwischen den einzelnen Punkten sein oder (unterdrückt bei beiden)
		//att.duration ist die komplette Zeit des Durchlaufs
		//att.fixDuration lässt nicht einfach alle Einträge nacheinander ablaufen, sondern wählt nach abgelaufener Zeit den aktuellen Punkt aus.
		
		if (!kkjs.is.key(att, "timeconstant")) att.timeconstant = att.duration * 1000 / att.path.length;
		if (!kkjs.is.key(att, "praefix")) att.praefix = "";
		if (!kkjs.is.key(att, "postfix")) att.postfix = "";
		if (!kkjs.is.key(att, "onFinish")) att.onFinish = function(){};
		if (!kkjs.is.key(att, "onAbort")) att.onAbort = function(){};
		
		att.position = 0;
		att.stepByDuration = function(){
			var d = new Date();
			this.position = Math.floor(( d - this.startTime ) / this.timeconstant);
			if (this.position >= this.path.length){
				this.position = this.path.length - 1;
			}
			
			this.object[this.attribute] = this.praefix + this.path[this.position] + this.postfix;
			this.position++;
			
			if (this.position == this.path.length){
				this.stop(true);
			}
		};
		att.stepByStep = function(){
			this.object[this.attribute] = this.praefix + this.path[this.position] + this.postfix;
			this.position++;
			
			if (this.position == this.path.length){
				this.stop(true);
			}
		};
		
		att.stop = function(ende){
			window.clearInterval(this.interval);
			if (ende){
				this.onFinish();
			}
			else{
				this.onAbort();
			}
			delete kkjs.uebergaenge.runReference[this.referenzIndex];
		};
		
		for (var i in kkjs.uebergaenge.runReference){
			var test = kkjs.uebergaenge.runReference[i];
			if (test.attribute == att.attribute && test.object == att.object){
				if (test.disableAbort){
					return false;
				}
				test.stop();
			}
		}
		if (att.fixDuration){
			att.startTime = new Date();
			att.interval = window.setInterval(function(){att.stepByDuration();}, att.timeconstant);
		}
		else {
			att.interval = window.setInterval(function(){att.stepByStep();}, att.timeconstant);
		}
		
		att.referenzIndex = new Date() + Math.random();
		kkjs.uebergaenge.runReference[att.referenzIndex] = att;
	}
};

