// requires getElementsByClassName-1.0.1.js http://www.robertnyman.com/2008/05/27/the-ultimate-getelementsbyclassname-anno-2008/

function CrossFader
(
	sName,				// instance name
	containerId,		// id of the containing item - helps us narrow where to search
	itemClass,			// class of the items we want crossfading
	itemTag,			// tag of the items we want cross fading
	delay,				// delay between fades (in milliseconds)
	fadeLength			// time it takes to fade an item completely(milliseconds)
)
{
	// set up default values
	if(!fadeLength)
	{
		fadeLength = 750; // this is quite a quick fade
	}
	
	var name = sName;
	var objItems = getElementsByClassName(itemClass, itemTag, document.getElementById("containerId")); // get the objects we'll be fading
	var numObjects = objItems.length;	// the number of items
	var iCurrent = 0;					// the current item that will be displayed
	var iNext = 1;						// the next item in to display
	
	var playIntervalID;					// holds the playback interval - this is assigned in the Init(), and is cleared when autoplay is interrupted
	
	var opacStep = Math.floor((60/fadeLength*100));
	
	// public properties
	this.NumObjects = function(){return numObjects;};
	this.CurrentItem = function(){return iCurrent;};
	this.NextItem = function(){return iNext;};
	
	this.FadeIn = function(i, opacStart, opacEnd)
	{
		objItems[i].style.display = "block"; // make sure the item is visible, not just opaque

		if(opacStart >= opacEnd)
		{
			SetOpacity(i, opacEnd);
			//Trace('Fade in: ' + i, "complete!");
			return;
		}
		
		if(opacStart <= opacEnd)
		{
			//Trace(i, "start: " + opacStart + " end: " + opacEnd);
			//opacity = Math.ceil((opacEnd+opacStart)*0.50) ;
			opacity = opacStart + opacStep; //opacity = opacStart + 24; - now takes into account how long the fade should take
			
			SetOpacity(i, opacity);
			fadeInTimeOutID = setTimeout(sName + ".FadeIn(" + i + ", " + opacity + ", " + opacEnd + ")", 60);
		}
	}
	
	this.FadeOut = function(i, opacStart, opacEnd)
	{
		if(opacStart > opacEnd)		
		{
			//opacStart = Math.floor(opacStart*0.50);
			opacStart = opacStart - opacStep; //opacStart -= 24; - now takes into account how long the fade should take
			SetOpacity(i, opacStart);
			fadeOutTimeOutID = setTimeout(sName + ".FadeOut(" + i + ", " + opacStart + ", " + opacEnd + ")", 60);
		}
		else if(opacStart <= opacEnd)
		{
			SetOpacity(i, opacEnd);
			objItems[i].style.display = "none"; // make sure the item is invisible, not just transparent
			//Trace('Fade out: ' + i, "complete!");
		}
	}
	
	// sets the opacity of an object to opacity
	function SetOpacity(i, opacity)
	{	
		var obj = objItems[i];
		try{obj.style.opacity = (opacity/100);} catch(err){}
	    try{obj.style.MozOpacity = (opacity/100); } catch(err){}
		try{obj.style.KhtmlOpacity = (opacity/100); } catch(err){}
		try{obj.style.filter = "alpha(opacity=" + opacity + ")"; } catch(err){}
	}
		
	this.JumpTo = function(i)
	{
		if(i > (numObjects-1))
		{
			Trace("Error jumping to item", "index " + i );
			return false;
		}
		
		if(iCurrent != i)
		{
			// stop the auto play back
			clearInterval(playIntervalID);
		
			// cancel any fade in our outs that are currently in progress
			try
			{
				clearTimeout(fadeInTimeOutID);
				clearTimeout(fadeOutTimeOutID);
			}
			catch(err)
			{
			}
			
			
			// found in the selected Item, fade out the current
			eval(sName + ".FadeIn(" + i + ",0, 100)");
			eval(sName + ".FadeOut(" + iCurrent + ",100,  0)")
			
			
			iCurrent = i;
			
			// update the next items to display
			if(i == (numObjects-1)) // i was the last item
			{
				iNext = 0;
			}
			else if(i == 0) // i was the first item
			{
				iNext = 1;
			}
			else
			{
				iNext = iCurrent + 1;
			}
			
			// continue the automatic playback
			playIntervalID = setInterval(sName + ".Play()", 12000); // after 10 seconds... should not have this hardcoded
			
			return true;
		}
		
		return false;
	}
	
	this.Play = function()
	{
		//Trace("seq", iCurrent + " " + iNext);
		
		//setTimeout(sName + ".FadeIn(" + iNext + ",0, 100)", 0);
		//setTimeout(sName + ".FadeOut(" + iCurrent + ",100,  0)", 0);
		//FadeIn(iNext, 0, 100);
		//FadeOut(iCurrent, 100, 0);
		eval(sName + ".FadeIn(" + iNext + ",0, 100)");
		eval(sName + ".FadeOut(" + iCurrent + ",100,  0)")
		
		// attached event for whenever the item changes (fades the next item)
		this.changeCallBack(iNext);
				
		// clean the following code - it can probably be done a lot quicker with modulo %
		if(iNext == (numObjects-1))
		{
			iCurrent++;
			iNext = 0;
		}
		else if(iCurrent == (numObjects-1))
		{
			iCurrent=0;
			iNext = 1;
		}
		else
		{
			iCurrent++;
			iNext++;
		}
	
	}
	

	// initialise
	function Init()
	{
		// only animate if the number of objects is more than 1
		if(numObjects > 1)
		{
			iNext = 1;
			
			// sett all but the first as hidden
			for( i=1; i<numObjects; i++ )
			{	
				SetOpacity(i, 0);
				objItems[i].style.display = "none";
			}
		
			// start fading
			playIntervalID = setInterval(sName + ".Play()", delay);
			
		}
	}	
	
	// register callback function for when the CrossFader changes the current displayed item
	// function must take single parameter i (corresponding to the current item being displayed);
	this.changeCallBack = function(i){};
	this.RegisterChangeCallBack = function( callBackFunction )
	{
		this.changeCallBack = callBackFunction;
	}
	
	
	function Trace(category, msg)
	{
		try
		{
			debugCrossFader = document.getElementById("debugCrossFader"); // if this object exists, write to it debugging information
		
			if(debugCrossFader.value.length > 300)
			{
				debugCrossFader.value = "";
			}
			var d = new Date();
			debugCrossFader.value = d.getTime() + " " + category + ": " + msg + "\n" + debugCrossFader.value;
		}
		catch(err)
		{
			// swallow the error
		}
	}
	
	
	Init();
}

