/****m* axsionics.js
 * DESCRIPTION
 *  New JavaScript based AXSionics Flickering renderer.
 *  Uses W3C DOM JavaScript functions to create an image tag for each component
 *  image and shows/hides them by manipulating the CSS style information.
 *  This avoids the cache validation issue of IE6.
 *
 *  Overview over the important functions:
 *    axsSetupFlickering(message)
 *    		Sets up a flickering with the specified message. The flickering
 *			starts automatically as soon as all component images are loaded
 *          from the server.
 *
 *    axsStartFlickering()
 *    		Start flickering after it has been stopped by axsStopFlickering()
 *    		or an exception.
 *
 *    axsStopFlickering()
 *    		Stop the flickering.
 *
 *  Overview over the HTML elements and ids expected by this script:
 *
 *    axs_pre_load (optional)
 *    		Element shown while component images are loaded by the browser.
 *    		In the example HTML file, this is a div section containing a
 *    		progress bar.
 *
 *    axs_progress_bar (optional)
 *    		Pogress bar for preload section. Should be an image tag. Controlled
 *    		using the CSS width attribute of the element. Width is specified in
 *          pixels. The maximal width (all images loaded) of the progress bar
 *    		is specified in the global variable "axs_pbarwidth".
 *
 *    axs_components (mandatory)
 *    		Parent element where the component images are added to. In the
 *    		example this is a div tag.
 * NOTE
 *  If an exception occurs, the current exception handler will stop the
 *  flickering and display a message box describing the exception. To change
 *  this behaviour, please edit the axsExceptionHandler() function.
 *
 *  To conserve bandwidth, the script only loads the component images needed to
 *  display the message.
 *******/

/****v* axs_msg
 * DESCRIPTION
 *  Global variable for flickering message string.
 */
var axs_msg = '';
/******/

/****v* axs_cnt
 * DESCRIPTION
 *  Global variable for number of code frames in message.
 */
var axs_cnt = 0;
/******/

/****v* axs_idx
 * DESCRIPTION
 *  Global variable for current position/index in message.
 */
var axs_idx = 0;
/******/

/****v* axs_prv
 * DESCRIPTION
 *  Global variable for previous position in message.
 *  The previous position is not stored as index, but as id string of the HTML
 *  element that shows the component image for the previous code frame.
 */
var axs_prv = '';
/******/

/****v* axs_intid
 * DESCRIPTION
 *  Global variable for the interval timer id.
 */
var axs_intid = 0;
/******/

/****v* axs_delay
 * DESCRIPTION
 *  Global variable for the frame delay (interval time).
 *  It contains the number of milliseconds each frame is supposed to be shown.
 * NOTES
 *  Values lower than about 40ms are likely to cause problems with some browser/
 *  computer sceen combinations.
 */
var axs_delay = 40;
/******/

/****v* axs_loaded
 * DESCRIPTION
 *  Global variable for number of component images loaded.
 *  It is used to control the progress bar and start the flickering once all
 *  images are loaded.
 */
var axs_loaded = 0;
/******/

/****v* axs_maxload
 * DESCRIPTION
 *  Global variable for number of component images to load.
 */
var axs_maxload = 0;
/******/

/****v* axs_pbarwidth
 * DESCRIPTION
 *  Global variable for maximal width of progress bar in pixels.
 */
var axs_pbarwidth = 460;
/******/

/****f* axsExceptionHandler
 * DESCRIPTION
 *  Dummy error handler.
 *  Actions taken depend on site design and specifications.
 * SOURCE
 */
function axsExceptionHandler(exception) {
	axsStopFlickering();
	return;
	
	/* replace with error handling code*/
	if (axs_intid === 0) {
		window.clearInterval(axs_intid);
		axs_intid = 0;
	}
	alert('Caught exception: '+exception);
	/* replace with error handling code*/
	
}
/******/

/****f* axsCheckDomFunctions
 * DESCRIPTION
 *  Check if W3C DOM functions needed by the flickering exist.
 * RETURN VALUE
 *  boolean					true if functions exist, false if not
 * SOURCE
 */
function axsCheckDomFunctions() {
	return ( document.getElementById && document.createElement ) ? true : false;
}
/******/

/****f* axsSetMessage
 * DESCRIPTION
 *  Set the message. Don't call from outside this script! Use
 *  axsSetupFlickering() instead, as it makes sure all images needed are
 *  loaded.
 *  Validates the string and updates the relevant global variables.
 * INPUT
 *  message:string			flicker message string
 * OUTPUT
 *  global axs_msg			new (sanitized) message
 *  global axs_cnt			length of message in frames
 *  global axs_idx			index of first frame in message ( = 0 )
 * SOURCE
 */
function axsSetMessage(message) {
	// --- VARIABLES
	var tmpMsg, tmpCnt, codeStr, codeVal, isValid, i;

	// --- IMPLEMENTATION
	isValid = false;
	
	tmpMsg = message.toLowerCase();
	tmpCnt = tmpMsg.length / 2;
	
	// don't accept empty messages
	if (tmpCnt !== 0) {
	
		// check code string for invalid characters and frame values
		isValid = true;
		for (i = 0; (i < tmpCnt) && isValid; i++) {
			codeStr = tmpMsg.charAt(2*i) + tmpMsg.charAt(2*i+1);
			codeVal = parseInt('0x'+codeStr, 16);
			isValid = (codeVal >= 0) && (codeVal <= 63);
		}
		
		// if message is valid, assign it to global variables
		if (isValid === true) {
			axs_msg = tmpMsg;
			axs_cnt = tmpCnt;
			axs_idx = 0;
		}
	}

	return isValid;
}
/******/

/****f* axsShowNextFrame
 * DESCRIPTION
 *  Shows the next frame of the flickering message.
 *  Hides the element displaying the image of the current code frame and shows
 *  the element containing the image of the next code frame.
 *  Called by the interval timer.
 * INPUT
 *  global axs_prv:string		id string of current flickering element shown
 *  global axs_msg:string		flicker message string (sanitized)
 *  global axs_idx:number		index in message
 * OUTPUT
 *  global axs_prv:string		updated id string string of current flickerin
 *  							element shown.
 *  global axs_idx:number		updated index
 * SOURCE
 */
function axsShowNextFrame() {
	// --- VARIABLES
	var nextCode;
	
	// --- IMPLEMENTATION
	
	// next code
	nextCode = 'code'+axs_msg.charAt(2*axs_idx)+axs_msg.charAt(2*axs_idx+1);
	
	try {
		// hide previous element
		document.getElementById(axs_prv).style.display = 'none';
		
		// show next element
		document.getElementById(nextCode).style.display = '';

		// remember id of currently visible element for later hiding		
		axs_prv = nextCode;
				
		// advance position in message
		axs_idx = ++axs_idx % axs_cnt;		
	}
	catch (e) {
		// exceptions in this function are considered fatal
		axsExceptionHandler(e);
	}
}
/******/

/****f* axsStartFlickering
 * DESCRIPTION
 *  Starts the flickering.
 *  Creates an interval timer that calls the axsShowNextFrame() function.
 *  If the flickering is already running, the function destroys the old interval
 *  timer before creating the new one, reading the axs_delay variable in the
 *  process.
 * INPUT
 *  global axs_intid:numbe		id of current interval timer or 0 if flickering
 *  							isn't running.
 * OUTPUT
 *  global axs_intid:number		id of interval timer
 * SOURCE
 */
function axsStartFlickering() {
	
	// remove old interval timer if flickering is already running
	if (axs_intid !== 0) {
		window.clearInterval(axs_intid);
	}
	
	// install interval timer
	axs_intid = window.setInterval(axsShowNextFrame, axs_delay);
}
/******/

/****f* axsStopFlickering
 * DESCRIPTION
 *  Stops the flickering.
 *  Deletes the interval timer that calls the axsShowNextFrame() function.
 * INPUT
 *  global axs_intid:numbe		id of current interval timer or 0 if flickering
 *  							isn't running.
 * OUTPUT
 *  global axs_intid:number		0 (not running -> no timer)
 * SOURCE
 */
function axsStopFlickering() {
	if (axs_intid !== 0) {
		window.clearInterval(axs_intid);
		axs_intid = 0;
	}
}
/******/

/****f* axsOnComponentImageLoad
 * DESCRIPTION
 *   Event handler for the "onload" event of the component images.
 *   Updates the progress bar and starts the flickering once all images are
 *   loaded.
 * INPUT
 *  global axs_loaded			number of component images loaded
 *  global axs_maxload			total number of component images to load
 * OUTPUT
 *  global axs_loaded			updated number component of images loaded
 * NOTE
 *  If no progress bar image with the specific id exists, the function silently
 *  skips this step.
 * SOURCE
 */
function axsOnComponentImageLoad() {
	// --- VARIABLES	
	var img, width;
	
	// --- IMPLEMENTATION
	
	// one more image loaded
	axs_loaded++;

	// adjust width of progress bar image according to number of component
	// images loaded out of the "axs_maxload" needed
	width = (axs_loaded / axs_maxload) * axs_pbarwidth;
	img = document.getElementById('axs_progress_bar');
	if (img !== null) {
		img.style.width = width+'px';
	}
	
	// start flickering if all images are loaded
	if (axs_loaded >= axs_maxload) {
		axsStartFlickering();	
	}
}
/******/

/****f* axsShowPreloadSection
 * DESCRIPTION
 *  Show the preload section.
 *  The function hides the currently displayed flickering element and makes the
 *  preload section visible. The function will not raise an error if the preload
 *  section doesn't exist.
 * INPUT
 *  global axs_prv:string		id string of element currently shown
 * OUTPUT
 *  global axs_prv:string		id string of preload section (so it can be
 *  							hidden by other functions)
 * SOURCE
 */
function axsShowPreloadSection() {
	// --- VARIABLES
	var	retVal, element;

	// --- IMPLEMENTATION

	retVal = false;	
	if (document.getElementById) {
		
		// hide previous element
		if (axs_prv !== '') {
			element = document.getElementById(axs_prv);
			if (element !== null) {
				element.style.display = 'none';
			}			
		}
		
		// show preload element
		element = document.getElementById('axs_pre_load');
		if (element !== null) {
			element.style.display = '';		// show preload element
			axs_prv = 'axs_pre_load';		// remember currently shown element
			retVal = true;
		}
	}
	return retVal;
}
/******/		

/****f* axsLoadComponentImages
 * DESCRIPTION
 *  Loads the component images for the flickering.
 *  The function creates a list of the codes occuring in the current flicker
 *  message and loads the relevant component images.
 * INPUT
 *  global axs_msg:string		flicker message string
 * OUTPUT
 *  adds image elements for the code images to the HTML document
 * SOURCE 
 */
function axsLoadComponentImages() {
	// --- VARIABLES
	var usedFrames, codeStr, frame, dst, img, i;
	
	// --- IMPLEMENTATION
	
	// build list of frames used in the message (don't waste bandwidth by
	// downloading component images that aren't needed to display the
	// message)
	usedFrames = [];
	for (i = 0; i < axs_cnt; i++) {
		codeStr = axs_msg.charAt(2*i) + axs_msg.charAt(2*i+1);
		usedFrames[codeStr] = codeStr;
	}

	// manually count entries in "used frames" list, as array.length will
	// not return a correct result for associative arrays. Save value as
	// number of component images that need to be loaded.
	axs_maxload = 0;
	for (frame in usedFrames) {
		if (usedFrames.hasOwnProperty(frame)) {
			axs_maxload++;	
		}
	}

	// use DOM functions to create the elements containing the component
	// images. The elements are created "hidden" and assigned the code id
	// of the component images they contain. The elements are then added
	// to the "axs_components" section of the HTML file.
	try {
		// get reference to destination element and append the tags for the
		// for the component images to it
		dst = document.getElementById('axs_components');
		if (dst !== null ) {
			for (frame in usedFrames) {
				if (usedFrames.hasOwnProperty(frame)) {
					if ( document.getElementById('code'+frame) === null ) {
						img = document.createElement('img');
						if (img !== null) {
							img.id = 'code'+frame;
							img.style.display = 'none';
							img.onload = axsOnComponentImageLoad;
							img.src = 'images/'+frame+'.gif';
							dst.appendChild(img);
						}
						else {
							// unable to create element for component image
							throw new Error('failed to create <img> element');
						}
					}
				}
			}
		}
		else {
			// unable to access "axs_components" section
			throw new Error('unable to access "axs_components" section!');	
		}
	}
	catch (e) {
		// fatal error, call error handler
		axsExceptionHandler(e);
	}
}
/******/

/****f* axsSetupFlickering
 * DESCRIPTION
 *	Setup function for the AXSionics JavaScript flickering.
 *  The function first checks if the necessary DOM functions are supported by
 *  the browser and aborts if not. As it will manipulate the message string
 *  global and component image sections in the HTML it stops the flickering
 *  (if it is already running) and sets the (new) message. If the message is
 *  valid, the function shows the preload section of the HTML document and
 *  loads the component images into the component section.
 * INPUT
 *  message:string				flicker message string
 * SOURCE
 */
 function axsSetupFlickering(message) {
	// check if W3C DOM	operations are supported
	if ( axsCheckDomFunctions() ) {
		
		// stop flickering while we manipulate the message
		axsStopFlickering();
		
		// check if message looks valid and set it
		if ( axsSetMessage(message) ) {

			// show preload section with progress bar
			axsShowPreloadSection();
			
			// start loading component images
			axsLoadComponentImages();
		}		
	}
}
/******/
//t
