
/**
* FLEXAEFFECTS
* some common interface effects 
* @author: jan vermaat june - august 2008
*/
var FLEXAEFFECTS = FLEXAEFFECTS || {
	/**
	* change color of an DOM object
	* @param object el: the dom object
	* @param string prop: the style property: please use color or backgroundColor
	* @param array colors: an array of HEX colors the perform the effect
	* @param function callback: callback function 
	* @param number time:  the timeout speed; default 100
	*/
	colorize : function (el, prop, colors, callback, time) {
		var props = {color:true, backgroundColor:true};
		var counter = 0;

		if (! props[prop]) return;
		
		var id = window.setInterval (function () {
			
			if  (counter==(colors.length-1)) {
				window.clearInterval (id);
				
				if (typeof callback ==='function')
					callback ();
					
				return false;
			}
			try {el.style[prop] = colors[counter++];} catch (e) {};
		}, (time || 100))
	},
	
	/**
	 * fade out function
	 * @param domobject el: the dom object you wanna fade out
	 * @param boolean invisible: true: set the dispay to 'none'; false : do nothis of this kind
	 * @param number startopacity: number between 0 and 100: the start opacity. Default 100 (== normal visiblility)
	 * @param number speed: the timout time in miliseconds. Default: 50
	 * @param function callback: optonal callback function
	 * @param number endopacity: stop at this opacity; optional. Default = 0
	 */
	fadeout : function (el, invisible, startopacity, time, callback, endopacity) {
		var op = startopacity || 100;
		var endop = endopacity || 0;
		if (typeof el !=='object')
			return;
		
		var filter = this.ieFilters (el);

		var c = window.setInterval( function() {
			el.style.filter = "alpha(opacity="+ op + ")"+filter;
			el.style.MozOpacity = (op/100);
			el.style.opacity = (op/100);
			
			if (op <= endop) {
				window.clearInterval (c);
				if (invisible===true) {
					el.style.display = 'none';
					el.style.filter = "alpha(opacity=50)"+filter;
					el.style.MozOpacity = (0.5);
					el.style.opacity = (0.5);
				}
				if (typeof callback === 'function') 
					callback ();
					
				return;
			}
			
			
			op = ( op - 10 );
		},time || 50);
	},
	/**
	 * this function is  used in fadein and fadeout
	 * we check if any other IE filters are active set on the 'el' element
	 */
	ieFilters: function (el) {
		var filter = FLEXAUTIL.getCSSStyle (el,'filter');
		var f= '';
		
		if (filter) {
			var filters = filter.split (/\)\s*/g);
		
			for (var i = 0 ;i < filters.length; i++) 
				if (!/^alpha/i.test(filters[i])){
					if (f=='') 
						f += ' ' + filters[i];
					else
						f += ') ' + filters[i];
				}
		}
		
		return f;
	},
	
	/**
	 * fade in function
	 * @param domobject el: the dom object you wanna fade out
	 * @param number startopacity: number between 0 and 100: the start opacity. Default 0 (== no visiblility)
	 * @param number speed: the timout time in miliseconds. Default: 50
	 * @param function callback: optonal callback function
	 */
	fadeIn : function (el, startopacity, time, callback) {
		
		var op = startopacity || 0;
		
		if (typeof el !=='object')
			return;
		
		var filter = this.ieFilters (el);

		var c = window.setInterval( function() {
			el.style.filter = "alpha(opacity="+ op + ")" + filter;
			el.style.display = 'block';	
			el.style.MozOpacity = (op/100);
			el.style.opacity = (op/100);
			
			if (op >= 100) {
				window.clearInterval (c);
				
				// ie8 bug fix to prevent crappy / dirty fonts
				el.style.filter = filter;
				
				if (typeof callback === 'function') 
					callback ();
					
				return;
			}
			
			
			op = ( op + 10 );
		},time || 50);
	},
	
	/**
	 * alias for fadeout
	 * so we have fadeOut () and fadeIn ()
	 */
	fadeOut : function (el, invisible, startopacity, time, callback, endopacity) { this.fadeout (el, invisible, startopacity, time, callback, endopacity)},
	
	/**
	 * drop functions
	 * @param: object el: the dom objct you want to stretch or shrink
	 * @param callback function : the callback function (optional)
	 * @param speed integer : The number of pixels to drop within a second(optional)
	 * @param milliseconds integer: Number of milliseconds to drop an item. Only used if speed is ommitted(optional)
	 * @author: JV august 2008
	 * this includes _drop (),  getElementHeight (), dropcounter,	defaultDropTime,	drops
	 * !! there is a problem with padding of the droppable elements
	 *
	 * syntax: 
	 * <div onclick="FLEXAEFFECTS.drop (dom.node ('myid'))">klik</div>
	 * <div id=myid>lorem ipsum</div>
	 * <style>
	 *	#myid {
	 *		width:300px;
	 *		font-family:georgia;
	 *		font-size:0.8em;
	 *		overflow:hidden;
	 *		height:1px;
	 *		border:10px red solid;
	 *		padding:10px;
	 *		display:none;
	 * }
	 * </style>
	 */

	drop : function (el, callback, speed, milliseconds) {
		
		if (typeof el !='object')
			return ;

		if (el.getAttribute ("__FLEXAEFFECTSDROP__") == 'true') 
			return;
		
		// if the element is buzy; set a flag;
		// remove flag in d.prototype.step whan finished
		el.setAttribute ("__FLEXAEFFECTSDROP__", true);
		var d = this._drop (el, this.dropcounter, callback, speed, milliseconds);
		
		this.drops['d' + this.dropcounter++] = d;
		
		d.run ();
	},

	/**
 	 * internal function of drop ()
	 */
	_drop : function (el, key, callback, speed, milliseconds) {
		
		// key: when were done; we'll delete the this.drops[key]

		var d = function () {}
		
		/**
		* here we start with the drop actions
		*/
		d.prototype.run = function () {
			el.style.overflow = 'hidden';
			if(el.style.display == 'none'){
				el.style.height = '1px';
			}
			el.style.display = 'block';
			
			// I can't handle padding in the element
			// this is a bug // problem
			//so: set the padding-top an -bottom to 0px
			el.style.paddingTop = '0px';
			el.style.paddingBottom = '0px';

			var maxHeight =  el.scrollHeight - 1;
			var offsetHeight = parseInt (FLEXAEFFECTS.getElementHeight (el));
			
			if (el.style.height == '100%') {
				var plusmin = 'min';
			} else if (el.style.height == '') {
				var plusmin = 'plus';
			} else {
				var plusmin = offsetHeight < maxHeight ? 'plus': 'min';
			}
			
			if(typeof speed === "number"){
				seconds = maxHeight / speed;
			}else if(typeof milliseconds === "number"){
				seconds = milliseconds / 1000;
			}else{
				seconds = FLEXAEFFECTS.defaultDropTime / 1000;
			}
			var cosStep = Math.PI / (30 * seconds);
			var loopTime = 32; //begin with a minimum of 32ms for each step() call (will be changed on the fly to draw nicer/quicker)
			var d = new Date();
			startTime = d.getTime();
			this.step ( el, maxHeight, plusmin, this, 0, cosStep, loopTime, startTime, 0, 0);
		}
		
		/**
		 * recursive for every step
		 */
		 d.prototype.step = function (el, maxHeight, plusmin, obj, currentCos, cosStep, minimumLoopTime, startTime, numberOfSteps, totalWaitingTime) {
			
			//<IE only code>
			//offsetHeight seems to change while running the step function :-S
			newMaxHeight = el.scrollHeight - 1;
			if(newMaxHeight != maxHeight){
				maxHeight = newMaxHeight;
				if(typeof speed === "number"){
					seconds = maxHeight / speed;
				}else if(typeof milliseconds === "number"){
					seconds = milliseconds / 1000;
				}else{
					seconds = FLEXAEFFECTS.defaultDropTime / 1000;
				}
				var cosStep = Math.PI / (15 * seconds);
			}
			//</IE only code>
			
			if ( 
				currentCos >= Math.PI
			 ) {
				//done dropping or minimizing
				if (plusmin=="min") {
					el.style.display = 'none';
				}else{
					el.style.height = '100%';
				}
				
				// at last we can add a call back function here
				if(typeof FLEXAEFFECTS.drops['d' + obj.key].callback =='function')
					FLEXAEFFECTS.drops['d' + obj.key].callback ();
					
				delete FLEXAEFFECTS.drops['d' + obj.key];
				el.removeAttribute ("__FLEXAEFFECTSDROP__");
	
				return;
	
			} else {
				//Generates a value between 0 and 1, with faster moving in the center
				
				relativeHeight = -0.5 * (Math.cos(currentCos) - 1);			
				if (plusmin == 'min') {
					//Makes the 0 to 1 value a 1 to 0 value.
					relativeHeight = 1 - relativeHeight;
				}
				height = maxHeight * relativeHeight;
				el.style.height = (height + 1) + 'px';
				currentCos += cosStep;
				//A littlebit of benchmarking on the Hertme showed that FF needs 80 ms for this function(without timeout), and IE  15ms.
				//A timeout of 65ms could be able to undo this difference in performance
				d = new Date();
				var endTime = d.getTime()
				numberOfSteps++;
				var brutoWaitingTime = endTime - startTime;
				var averageTime = (brutoWaitingTime - totalWaitingTime) / numberOfSteps;
				if(averageTime < minimumLoopTime){
					// when brutoWaitingTime is 0 the timer isn't precise enough yet.
					if(brutoWaitingTime !== 0 && (minimumLoopTime / 2) > averageTime){
						//We have more than 1/2 of the waiting time left, so we can double the drawing precision
						minimumLoopTime = minimumLoopTime / 2;
						cosStep = cosStep / 2;
					}
					waitingTime = minimumLoopTime - averageTime;					
				}else{

					if(averageTime > minimumLoopTime){
						//slow down!!! Can't handle current loopTime: half precision/double 
						minimumLoopTime = minimumLoopTime * 2;
						cosStep = cosStep * 2;
					}
					waitingTime = 1;
				}
				totalWaitingTime += waitingTime;
				window.setTimeout (FLEXAUTIL.apply(obj.step,[el, maxHeight, plusmin, obj, currentCos, cosStep, minimumLoopTime, startTime, numberOfSteps, totalWaitingTime]), waitingTime);
			}
		 }
		
		var di = new d ();
		di.key = key;
		di.el = el;
		di.callback = callback;
		return di;
	},
	
	/**
	 * horizontal slide
	 * a bit experimental (jan 2010)
	 * JV 
	 slider : the slider element (DOM Object). Slider has to have a parent element with a certain width and a overflow: hidden
	 helpiconwidth : how many pixels you should see when the slider is slided in
	 thespeed: optional. | 'slow' | 'normal' | 'fast' ; default is 'normal'
	 */
	hslide: function (slider, helpiconwidth, thespeed) {
			
		var thetime = thespeed=='slow'? 500: thespeed=='fast'? 100: 250;
		
		var helpcontainer = slider.parentNode;
		
		var marginleft = parseInt(FLEXAUTIL.getCSSStyle (slider,"marginLeft"));
		
		var helpwidth = parseInt(FLEXAUTIL.getCSSStyle (helpcontainer,"width"));
		
		var start = marginleft;

		var stop =  helpwidth - helpiconwidth;
		
		var interval = 20;
		
		var speed = (Math.ceil(helpwidth/(thetime/interval)))

		if (marginleft == 0 ) {
			var _marginleft = marginleft;
			
			var intid = window.setInterval (function () {
				_marginleft = _marginleft + speed;

				if (_marginleft <= stop) {
					slider.style.marginLeft = _marginleft + 'px';
				} else {
					slider.style.marginLeft = stop + 'px'
					window.clearInterval (intid);
				}
			}, interval);
		} 
		if (marginleft == stop ) {
			var _marginleft = marginleft;
			
			var intid = window.setInterval (function () {
				_marginleft = _marginleft - speed;

				if (_marginleft >= 0) {
					slider.style.marginLeft = _marginleft + 'px';
				} else {
					slider.style.marginLeft = '0px'
					window.clearInterval (intid);
				}
			}, interval);
		}
	},
	
	/**
	 * general getElementHeight function; mesure with padding
	 * @param: object el: the dom objct you want to stretch or shrink
	 * @return number: the number of pixels of the element height
	 * remember: the document has to be is the XHTML <doctype>
	 */
	getElementHeight : function (el) {
		var h = parseInt (FLEXAUTIL.getCSSStyle(el,'height'));
		h += parseInt (FLEXAUTIL.getCSSStyle(el,'padding-top'));
		h += parseInt (FLEXAUTIL.getCSSStyle(el,'padding-bottom'));
		return h;
	 },
	 
	/** internal counter for drop ()*/
	dropcounter:0,
	
	/** internal for drop (): the default drop time in ms */
	defaultDropTime: 150,
	
	/** internal for drop (): little stack */
	drops: {}
}

