/*
	COPYRIGHT NOTICE:

	This file, and all other files hosted on the Black Fire Networks website
	(http://www.bfnsoftware.com), are exclusive property of the Black Fire Networks.
	Redistribution in part or in whole, without explicit written permission from the
	Black Fire Networks is absolutely forbidden.  

	If you would like to use this code for your own personal projects, unrelated
	to any services the Black Fire Networks provides, and understand that all copyright
	notices must remain unaltered, please submit a request to support with the file name,
	and the reason you would like to use it.

	Copyright © 2006 Black Fire Networks.  All Rights Reserved.
*/
/*

	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ElementFader %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

*/
	/**
	 *	ElementFader
	 *	This class allows you to setup fade in and out effects on a set of elements.  Make sure you dont
	 *	add an element, and then add one of its children.  It is not necessary, and will cause undesired 
	 *	results.
	 *
	 *	When setting the maximum and minimum visibilities, keep in mind that the browser goes through
	 *	a transition phase when going from transparent to opaque, and from transparent to not visible.  This
	 *	trnasition phase consumes a bit of resources, and causes the effect to look bad.  For this reason,
	 *	you may want to use 1% visibile for minimum, and 99% visible for maximum.  The transparency at these
	 *	levels wont even be noticable.
	 *
	 *	You will probably need to play with different  values for steps and duration.  The longer the effect, the
	 *	more steps you will need for it to look good.  The shorter the duration, the fewer steps you will need.
	 *
	 *	Keep in mind this is a costly operation, and will consume reasonable CPU and memory.  For this reason, it
	 *	is not advised to use this effect on a continuous basis.
	 *	
	 *
	 *	@constructor
	 *
	 *	@param minimum The minimum percentage of visibility (0 - 100)
	 *	@param maximum The maximum percentage of visibility (0 - 100)
	 *	@param steps The number of steps to use to go from minimum to maximum (similar to frame rate)
	 *	@param duration The number of milliseconds to draw the effect out for
	 */
	function ElementFader(minimum, maximum, steps, duration) {
		this.i_minimum = minimum;		// The minimum visibility of this effect
		this.i_maximum = maximum;		// The maximum visibility of this effect
		this.i_steps = steps;			// The number of steps to use (similar to frame rate)
		this.i_duration = duration;		// The duration of the effect in milliseconds
		
		this.i_elements = Array();		// The elements being controlled by this transition
		
		this.i_stage = 0;			// The stage of the transition this effect is in
		this.i_actual_stage = 0;		// The actual tage the transition is in (if in the middle of a transition)
		
		this.i_timer;				// The timer when a transition is in progress
	}
	
	/**
	 *	Handler for when the transition has finished.  This will be cleared after the transition finishes, of if the 
	 *	transition was cancelled for a higher priority transition.
	 *
	 *	@param stage The final stage of the transition
	 *	@param fader The ElementFader object
	 */
	ElementFader.prototype.oncomplete = function(stage, fader) { }

	/**
	 *	Get/Set the current stage of the transition.  This is a number between 0 and 100, that represents the
	 *	percentage of maximum - minimum that has transpired.   For instance,  If your minimum was 30% and your 
	 *	maximum was 80%, and you set this method to 50%, the elements will be set to 55% visibility, because
	 *	55% is 50% of (80% - 30%)
	 *
	 *	If the elements are still in the middle of a transition, that transition will be stopped, and this
	 *	transition will take priority, starting where the other transition was stopped.
	 *
	 *	@param stage The percentage of the transition which has transpired
	 *	@param instant (Optional) If set to true, the effect will immediatly set the visibility to this stage, but
	 *			if false, or undefined, the elements will be transitioned to this stage gradually based on
	 *			the steps and duration values.
	 *
	 *	@return true
	 */
	ElementFader.prototype.stage = function(stage, instant) {
		if (stage != undefined) {
			this.i_stage = stage;
			if (instant) {
				this.i_actual_stage = stage;
				var inc = ((this.maximum() - this.minimum()) * (this.i_actual_stage / 100));
				this.setOpacity(inc);
			}
			else {
				if (this.i_timer != undefined) {
					clearInterval(this.i_timer);
					this.oncomplete = undefined;
				}
				var me = this;
				this.i_timer = setInterval(function() {
					me.processStep();
				}, (this.duration() / this.steps()));
			}
					
		}
		return this.i_actual_stage;
	}
	

	/**
	 *	Set the opacity of the elements under this effects control
	 *
	 *	@private
	 *
	 *	@param opacity (Optional) The opacity to set the elements to, between 0 and 100, if no opacity is provided, the
	 *				current opacity will be used
	 *	@param index (Optional) The index of hte item to set the opacity for, if no index is provided, all elements
	 *			will be effected.
	 *
	 *	@return true;
	 */
	ElementFader.prototype.setOpacity = function(opacity, index) {
		if (opacity == undefined) {
			opacity = ((this.maximum() - this.minimum()) * (this.i_actual_stage / 100));
		}
		for (var x = (index != undefined ? index : 0); x < (index != undefined ? index + 1 : this.i_elements.length); x++) {
			this.i_elements[x].style.filter = "alpha(opacity=" + opacity + ")";
			this.i_elements[x].style.MozOpacity = (opacity / 100);
			this.i_elements[x].style.opacity = (opacity / 100);
			this.i_elements[x].style.KhtmlOpacity = (opacity / 100);
		}
		return true;
	}
	
	/**
	 *	Process a step in the transition
	 *
	 *	@private
	 *
	 *	@return true
	 */
	ElementFader.prototype.processStep = function() {
		var stageInc = (100 / this.steps());
		
		if (this.i_actual_stage < this.i_stage) {
			// Going up
			if (this.i_stage - this.i_actual_stage < stageInc) {
				this.i_actual_stage = this.i_stage;
			}
			else {
				this.i_actual_stage += stageInc;
			}
		}
		else if (this.i_actual_stage > this.i_stage) {
			// Going down
			if (this.i_actual_stage - this.i_stage < stageInc) {
				this.i_actual_stage = this.i_stage;
			}
			else {
				this.i_actual_stage -= stageInc;
			}
		}
		else {
			// We are where we want to be, no further processing needed
			if (this.i_timer != undefined) {
				clearInterval(this.i_timer);
				this.i_timer = undefined;
				if (this.oncomplete != undefined) {
					this.oncomplete(this.i_stage, this);
					this.oncomplete = undefined;
				}
			}
			return true;
		}
		
		var inc = ((this.maximum() - this.minimum()) * (this.i_actual_stage / 100));
		this.setOpacity(inc);
	}
	
	/**
	 *	Remove all elements from this effect
	 *
	 *	@return true
	 */
	ElementFader.prototype.clearItems = function() {
		this.i_elements = Array();	
	}
	
	
	/**
	 *	Add an element to this effect
	 *
	 *	@param elem The element to add to the effect
	 *
	 *	@return the element that was just added
	 */
	ElementFader.prototype.addItem = function(elem) {
		this.i_elements[this.i_elements.length] = elem;
		this.setOpacity(undefined, this.i_elements.length - 1);
		return elem;
	}
	
	/**
	 *	Remove an element form the effect
	 *
	 *	@param elem The element to remove from the effect
	 *
	 *	@return true if the element was found and removed, false if it was not found, and was probably already removed.
	 */
	ElementFader.prototype.removeItem = function(elem) {
		for (var x = 0; x < this.i_elements.length; x++) {
			if (this.i_elements[x] == elem) {
				this.i_elements.splice(x, 1);
				return true;
			}
		}
		return false;
	}
	
	/**
	 *	Get/Set the minimum visibility of the effect. 
	 *
	 *	@param minimum (Optional) The new minimum for this effect
	 *
	 *	@return the current minimum of the fade effect.
	 */
	ElementFader.prototype.minimum = function(minimum) {
		if (minimum != undefined) {
			this.i_minimum = minimum;
		}
		return this.i_minimum;
	}
	
	/**
	 *	Get/Set the maximum visibility of this effect
	 *
	 *	@param maximum (Optional) The maximum visibility of this effect
	 *
	 *	@return the current maximum visiblity
	 */
	ElementFader.prototype.maximum = function(maximum) {
		if (maximum != undefined) {
			this.i_maximum = maximum;
		}
		return this.i_maximum;
	}
	
	/**
	 *	Get/Set the number of steps to use for the fade effect.  This is basically the frame rate of the effect.
	 *	
	 *	@param steps (Optional) The number of steps to use for this effect
	 *
	 *	@return the current number of steps used for this effect
	 */
	ElementFader.prototype.steps = function(steps) {
		if (steps != undefined) {
			this.i_steps = steps;
		}
		return this.i_steps;
	}
	
	/**
	 *	Get/Set the duration in milliseconds this effect should last for
	 *
	 *	@param duration (Optional) The number of milliseconds to extend the effect for
	 *
	 *	@return the current duration of this effect
	 */
	ElementFader.prototype.duration = function(duration) {
		if (duration != undefined) {
			this.i_duration = duration;
		}
		return this.i_duration;
	}