/**
 * LBI.common
 * @version 1.0
 * @author LBi - http://www.lbi.com/en
 * @requires jQuery Core 1.4.1 - http://www.jquery.com/
 * @requires jQuery UI 1.7.2 - http://ui.jquery.com/
*/
/*jslint bitwise: true, eqeqeq: true, passfail: false, nomen: true, plusplus: false, undef: true, evil: true */
/*global window, document, navigator, $, jQuery, */

var LBI = window.LBI || {};
/**
 * @namespace Common re-used functionality.
 */
LBI.common = {	
	version					: 1.0,	
	
	identJSClass			: 'hasJS',
	dynamicInputSelector	: '.dyna-text',
	dynamicInputFocusClass	: 'focused',
	ajaxQueryParam			: 'rc=1',
	newWindowClass			: 'newwin',
	newWindowText			: 'This link will open a new window',
	webSafeChar				: '<span class="webSafeChar"> </span>',
	printLinkClass			: 'printwin',
	printLinkText			: 'This link will open the Print dialog',
	
	/**
	 * Add class to body to identify presence of JS.
	 * <p>
	 * Use hasJS.css instead to control load flicker etc.
	 */
	identJS: function() {
		$('body').addClass(LBI.common.identJSClass);
	},
	
	sortNumeric: function(b,a) {
		return a < b ? -1 : (a > b) ? 1 : 0;
	},
	isUnsignedInteger: function (s) {
		return (s.toString().search(/^[0-9]+$/) === 0);
	},
	/**	
	 * Returns object of all queries within a string.
	 * <p>
	 * Will return undefined for no query string.
	 * 
	 * @param {Object} 	theString
	 * @return {Object}	key:values of query string
	 */
	getStringQueries: function(theString) {
		// returns object of all queries within a string
		if (typeof theString !== 'string') {
			return;			
		}
		
		if (theString.indexOf('?') > -1) {
			// make sure you get query side of url
			theString = theString.split('?')[1];
		}
		
		var qs = theString, qsKey, qsValue, stringElements = {};
		// make an array of query string items
		qs = qs.split("&");
		// create object
		for (var i = qs.length - 1; i >= 0; i--) {
			qsKey = qs[i].split("=")[0];
			qsValue = qs[i].split("=")[1];
			stringElements[qsKey] = qsValue;
		}
		return stringElements;

	},
	/** 
	 * Splits a string that would not normally wrap (like and email address) with wrapping characters.
	 * <p>
	 * Since wrapping characters are not supported in IE6 without East Asian language support an empty 
	 * styled <span> is used instead. This leads to some accessibility issues.
	 * 
	 * @param (String) myString
	 * @return {String} 
	 */
	webSafeString: function (myString) {
		var stringAsArray = myString.split("");
		var stringLength = stringAsArray.length;
		var newArray = [];
		for (var i=0; i < stringLength; i++ ) {
			newArray.push(stringAsArray[i],LBI.common.webSafeChar);
		}
		var newString = newArray.join("");
		return newString;
	},
	/**
	 * Strip out and return local page anchor from URL.
	 * 
	 * @param 	{Object} anchor
	 * @return 	Return the anchor portion of the URL (or false if no anchor)
	 */
	urlGetAnchor: function(anchor) {
		if ( anchor.href.indexOf("#") >= 0 ) { //Check for anchorness
			anchor.destination = anchor.href.slice(anchor.href.indexOf("#")+1);
			return anchor.destination;
		} else {
			return false;
		}
	},
	
	/**
	 * New window/popup function.
	 * <p>
	 * Add the openInNewWindow function to the onclick event of links with a specified class name.
	 * 
	 * @return	{Boolean} Returns false if window not open
	 */
	getNewWindowLinks: function() { 
		$('a').each(function (i) {
			if ($(this).hasClass(LBI.common.newWindowClass)) {
				$(this).title = $(this).title + " " + LBI.common.newWindowText;
				$(this).click(function () {
			    	var newWindow = window.open(this.getAttribute('href'), '_blank');
					if (newWindow) {
						if (newWindow.focus) {
							newWindow.focus();
						}
					}
					return false;
			    });
			}
		});
	},
	
	/**
	 * Print dialog function.
	 * <p>
	 * Add the window.print function to the onclick event of links with a specified class name.
	 */
	getPrintLinks: function() { 
		$('a.' + LBI.common.printLinkClass).live('click', function() {
			var printWin = window.print();
			return false;
		});
	},
	
	/**
	 * Input field text population.
	 * <p>
	 * Takes current value of form inputs and handles clearing and repopulating on focus.
	 */
	dynamicInputText: function() {
		$(LBI.common.dynamicInputSelector).each(function (i) {
			var target = this;
			target.savedText = target.value; // keep track of the original input value
			target.onfocus=function(){
				$(this)[0].value = jQuery.trim($(this)[0].value);
				if ($(this)[0].value === this.savedText) {
					$(this)[0].value = "";
				}
				$(this).addClass(LBI.common.dynamicInputFocusClass);
			};
			target.onblur=function(){
				$(this)[0].value = jQuery.trim($(this)[0].value);
				if ($(this)[0].value === "") {
					$(this)[0].value = this.savedText;
				}
				$(this).removeClass(LBI.common.dynamicInputFocusClass);
			};
		});
	},
	
	/**
	 * Equal height box columns.
	 * <p>
	 * Takes an array of elements and sets style to the maxiumum height.
	 * 
	 * @param (Array) boxes	 
	 */
	boxHeights: function(boxes) {
		var heights = [];
		for (var i=0;i<boxes.length;i++) {
			if (navigator.userAgent.toLowerCase().indexOf('opera') === -1) {
				heights.push(boxes[i].scrollHeight);
			} else {
				heights.push(boxes[i].offsetHeight);
			}
		}
		heights.sort(this.sortNumeric);
		var maxh = heights[0];
		for (var j=0;j<boxes.length;j++) {
			boxes[j].style.height = maxh+"px";
		}
	},
	
	/**
	 * Get the left position for an object relative to the upper left viewport corner.
	 * 
	 * @param {Object} element The DOM element
	 * @returns {Number} Number of pixels across from the upper left viewport corner.
	 */
	getAbsoluteLeft: function(element) {
		var oLeft, oParent;
		// Get left position from the parent object
		oLeft = element.offsetLeft;
		// Parse the parent hierarchy up to the document element   
		while (element.offsetParent !== null) {
			// Get parent object reference
			oParent = element.offsetParent;  
			// Add parent left position
			oLeft += oParent.offsetLeft;
			element = oParent;
		}
		return oLeft;
	},
	
	/**
	 * Get the top position for an object relative to the upper left viewport corner.
	 * 
	 * @param {Object} element The ID of the DOM element
	 * @returns {Number} Number of pixels down from the upper left viewport corner.
	 */
	getAbsoluteTop: function(element) {
		var oTop, oParent;
		// Get top position from the parent object
		oTop = element.offsetTop;
		// Parse the parent hierarchy up to the document element
		while (element.offsetParent !== null) {
			// Get parent object reference 
			oParent = element.offsetParent;
			// Add parent top position
			oTop += oParent.offsetTop;
			element = oParent;
		}
		return oTop;
	},
	
	/**
	 * @namespace Common AJAX functionality.
	 */
	ajax: {		
		bufferFieldID	: 'ajaxVirtualBufferUpdate',		
		/**
		 * Insert form field for buffer update
		 */
		prepareBuffer: function() {
			var objHidden = document.createElement('input');
			
			objHidden.setAttribute('type', 'hidden');
			objHidden.setAttribute('value', '1');
			objHidden.setAttribute('id', LBI.common.ajax.bufferFieldID);
			objHidden.setAttribute('name', LBI.common.ajax.bufferFieldID);

			document.body.appendChild(objHidden);
		},
		/**
		 * Updates value of hidden form field to nudge screen readers into recognising page state change.
		 * 
		 * @see LBI.common.ajax.prepareBuffer()
		 */
		updateBuffer: function() {
			var objHidden = document.getElementById(LBI.common.ajax.bufferFieldID);			
			if (objHidden) {
				if (objHidden.getAttribute('value') === '1') {
					objHidden.setAttribute('value', '0');
				} else {
					objHidden.setAttribute('value', '1');
				}
			} else {
				LBI.common.ajax.prepareBuffer();
				LBI.common.ajax.updateBuffer();
			}		
		},
		/**
		 * Update the page buffer for assistive tech and focus on optional element.
		 *
		 * @param {Object} focusEL
		 * @param {Boolean} timeout
		 */
		pageUpdated: function (focusEL, timeout) {
			// Update page 'buffer'
			LBI.common.ajax.updateBuffer();
			// If an element is provided focus it
			if (focusEL) {
				if ($.isArray(focusEL) || (focusEL.length > 0)) {
					// If focusEL is an array object
					focusEL[0].focus();
				} else {
					// If focusEL is a single object
					focusEL.focus();
				}
			}
		},	
		/**
		 * Takes a string (URL expected) and appends parameter to identify as AJAX request for backend processing.
		 * 
		 * @param {String}	URL
		 * @return {String}	An AJAXed URL
		 */	
		tagUrl: function(url) {
			// 
			var prefix =(url.indexOf('?') < 0 ) ? "?" : "&" ;
			var ajaxURL = url + prefix + LBI.common.ajaxQueryParam;
			return ajaxURL;
		}
	},
	
	
	/**
	 * Parse version string.
	 * <p>
	 * Parse the version strings with a simple function and return them as objects with appropriate properties whose values are integers. 
	 * Once in this form, we can compare them with simple mathematics.
	 * 
	 * @param 	{String} str
	 * @return 	{Object} Return the major, minor and patch numbers
	 */
	parseVersionString: function(str) {
	    if (typeof(str) !== 'string') { return false; }
	    var x = str.split('.');
	    // parse from string or default to 0 if can't parse
	    var maj = parseInt(x[0], 10) || 0;
	    var min = parseInt(x[1], 10) || 0;
	    var pat = parseInt(x[2], 10) || 0;
	    return {
	        major: maj,
	        minor: min,
	        patch: pat
	    };
	},
	
	/**
	 * If within a frame kill the frame and reload at top
	 */
	frameKill: function() {
		var top;
		var self;
		if (top !== self) {
			top.location.href = self.location.href;
		}
	},
	
	/**
	 * Escapes special characters in DOM ID strings.
	 * <p>Used with jQuery when an ID has special characters. For example, JSF outputs IDs with colons separating namespaces, 
	 * which breaks jQuery's getElementById implementation. This function will escape any such characters in the ID string.
	 * @param {String} id The DOM ID string containing special characters to be escaped.
	 * @returns {String} A DOM ID string with the special characters escaped.
	 */
	escapeSpecialCharsInId: function(id) {
		return '#' + id.replace(/:/g,"\\:").replace(/\./g,"\\.");
	},
	
	onPageFlash: function() {
		if ($(".flashContent").length !==0){
			$(".videoHolder").removeClass("hidden");
			$(".fallback").addClass("hidden");
			$(".audioDescription").addClass("hidden");

			
			
			if($(".autoplay").length !==0 || $(".onHit").length !==0){
				if($(".autoplay").length !==0){
					$(".autoplay").each(function(){
						var videoLinks = $(".flashContent #videoContainer a", this);
						$(videoLinks).each(function(){
							var flashType= LBI.common.getPEClassInfo(this,"F_");
							
							var videoId = LBI.common.getPEClassInfo(this,"V_");
							
							var height = LBI.data.flashType[flashType].height + "px";
							var width = LBI.data.flashType[flashType].width + "px";
							var videoHeight = LBI.data.flashType[flashType].height;
							var videoWidth = LBI.data.flashType[flashType].width;
							
							if($("#endImage").length !=- 0){
								var endimage = document.getElementById("endImage");
								var endImagePath = endimage.href;
							}
							else{
								
							}
							
							var interactiveUrl = LBI.data.interactiveDemo;
		
							var flashvars = {};
							if (this.href.indexOf(".flv") !== -1) {
								var videoLink = this.href;
								flashvars.videoSource= videoLink;
								flashvars.width = videoWidth;
								flashvars.height = videoHeight;
								flashvars.autoplay = false;
								flashvars.muted = true;
								flashvars.showInteractive = true;
								flashvars.endImage = endImagePath;
								flashvars.launchUrl = interactiveUrl;
								swfobject.embedSWF(LBI.data.flashPlayer01, videoId, width, height, "9.0.0", "expressInstall.swf",flashvars, LBI.data.pageVideoOptions.params);
							} else {
								var flashFile = this.href;
								swfobject.embedSWF(flashFile, videoId, width, height, "9.0.0", "expressInstall.swf",flashvars,LBI.data.pageSWFOptions.params);
							}
						})
					})
				}
				
				if ($(".onHit").length !==0){
					
					$(".onHit").each(function(){
						var videoLinks = $(".flashContent a", this);
						var videoThumbs = $(".externalTrigger", this);
						$(videoLinks).click(function(){
							var flashType = LBI.common.getPEClassInfo(this,"F_");
							var videoId = LBI.common.getPEClassInfo(this,"V_");
							
							var height = LBI.data.flashType[flashType].height + "px";
							var width = LBI.data.flashType[flashType].width + "px";
							var videoHeight = LBI.data.flashType[flashType].height;
		
							var videoWidth = LBI.data.flashType[flashType].width;
			
							var flashvars = {};
							if (this.href.indexOf(".flv") !== -1) {
								var videoLink = this.href;
								flashvars.videoSource= videoLink;
								flashvars.width = videoWidth;
								flashvars.height = videoHeight;
								flashvars.autoplay = true;
								flashvars.muted = false;
								flashvars.showInteractive = false;
								swfobject.embedSWF(LBI.data.flashPlayer01, videoId, width, height, "9.0.0", "expressInstall.swf",flashvars, LBI.data.pageVideoOptions.params);
							} else {
								//var flashFile = this.href;
								//swfobject.embedSWF(flashFile, videoId, width, height, "9.0.0", "expressInstall.swf");
							}
							
							return false;
						})
						
						if($(".videoThumbHold").length !==0){
							$(".videoThumbHold").hover(
								function(){
									$(this).closest(".videoThumbHold").addClass("mouseover");
								},
								function(){
									$(this).closest(".videoThumbHold").removeClass("mouseover");
								}
							)
						}
						
						$(videoThumbs).click(function(){
							if($(".videoThumbHold").length !==0){
								$(".videoThumbHold").removeClass("active");
								$(this).closest(".videoThumbHold").addClass("active");
							}
							var flashType = LBI.common.getPEClassInfo(this,"F_");
							var videoId = LBI.common.getPEClassInfo(this,"V_");
							
							var height = LBI.data.flashType[flashType].height + "px";
							var width = LBI.data.flashType[flashType].width + "px";
							var videoHeight = LBI.data.flashType[flashType].height;
		
							var videoWidth = LBI.data.flashType[flashType].width;
			
							var flashvars = {};
							if (this.href.indexOf(".flv") !== -1) {
								var videoLink = this.href;
								flashvars.videoSource= videoLink;
								flashvars.width = videoWidth;
								flashvars.height = videoHeight;
								flashvars.autoplay = true;
								flashvars.muted = false;
								flashvars.showInteractive = false;
								swfobject.embedSWF(LBI.data.flashPlayer01, videoId, width, height, "9.0.0", "expressInstall.swf",flashvars, LBI.data.pageVideoOptions.params);
							} else {
								var flashFile = this.href;
								swfobject.embedSWF(flashFile, videoId, width, height, "9.0.0", "expressInstall.swf");
							}
							
							return false;
						})	
					
					})
					
				}
				/*
				else if ($(".onHit").length !==0){				
					$(videoLinks).click(function(){
						var flashType = LBI.common.getPEClassInfo(this,"F_");
						var videoId = LBI.common.getPEClassInfo(this,"V_");
						var captionFile = LBI.common.getPEClassInfo(this,"C_");
						var fallBackImage = LBI.common.getPEClassInfo(this,"fallback");
						
						var height = LBI.data.flashType[flashType].height + "px";
						var width = LBI.data.flashType[flashType].width + "px";
						var videoHeight = LBI.data.flashType[flashType].height;
						var videoWidth = LBI.data.flashType[flashType].width;
						var captionSource = "null&captions.file=" + LBI.data.flashPath + captionFile;
						var videoSkin =  LBI.data.flashPath + "bt_test_skin.swf";
						
	
						var flashvars = {};
						if (this.href.indexOf(".flv") !== -1) {
							var videoLink = this.href;
							flashvars.file= videoLink;
							flashvars.width = videoWidth;
							flashvars.height = videoHeight;
							flashvars.autostart = true;
							flashvars.mute = false;
							flashvars.controlbar = "over";
							flashvars.audioName="null&audiodescription.file=http://www.longtailvideo.com/jw/upload/corrie.mp3";
							flashvars.skin = videoSkin;
							flashvars.image = fallBackImage;
							flashvars.captionsname = captionSource;
							//flashvars.captionState = "null&captions.state";
							//flashvars.audioState = "null&audiodescription.state";
							flashvars.plugins = "captions-1, audiodescription-1";
							swfobject.embedSWF(LBI.data.flashPlayer01, videoId, width, height, "9.0.0", "expressInstall.swf",flashvars, LBI.data.pageVideoOptions.params);
						} else {
							var flashFile = this.href;
							swfobject.embedSWF(flashFile, videoId, width, height, "9.0.0", "expressInstall.swf");
						}
						
						return false;
					})
					
				}*/
				
			}
			
			
			else {				
				var videoLinks = $(".flashContent a");
				$(videoLinks).each(function(){					
					var flashType = LBI.common.getPEClassInfo(this,"F_");
					var videoId = LBI.common.getPEClassInfo(this,"V_");
					
					var height = LBI.data.flashType[flashType].height + "px";
					var width = LBI.data.flashType[flashType].width + "px";
					var videoHeight = LBI.data.flashType[flashType].height;
					var videoWidth = LBI.data.flashType[flashType].width;
	
					var flashvars = {};
					if (this.href.indexOf(".flv") !== -1) {
						var videoLink = this.href;
						flashvars.videoSource= videoLink;
						flashvars.width = videoWidth;
						flashvars.height = videoHeight;
						flashvars.autoplay = false;
						flashvars.muted = false;
						flashvars.showInteractive = false;
						swfobject.embedSWF(LBI.data.flashPlayer01, videoId, width, height, "9.0.0", "expressInstall.swf",flashvars, LBI.data.pageVideoOptions.params);
					} else {
						var flashFile = this.href;
						swfobject.embedSWF(flashFile, videoId, width, height, "9.0.0", "expressInstall.swf");
					}
				})
				
			}
		}	
	},
	
	//get the contents between ( and ) marks attached to a classname that starts with a given marker
 	getPEClassInfo: function(el,marker){
		var fullClass = el.className;
		var info = fullClass.substring(fullClass.indexOf(marker+"(")+marker.length+1);
		info = info.substring(0,info.indexOf(")"));
		return info;
	},
	
	
	clearEvents : function(id) {
            var area = document.getElementById(id);
            var nodeName, evt, areaElms;
            var unbind = function(events, elm) {
                for(evt in events) {
                    if(events.hasOwnProperty(evt)) {
                        jQuery(elm).unbind(evt);           
                    }
                }                
            };
            // get all events in jQuery cache
            for(var ref in jQuery.cache) {
                if(jQuery.cache.hasOwnProperty(ref)) {
                    if(typeof jQuery.cache[ref].events !== "undefined") { // if it has events attached
                        if(typeof jQuery.cache[ref].handle.elem.nodeName !== "undefined") { // if is a DOM node
                            nodeName = jQuery.cache[ref].handle.elem.nodeName;
                            areaElms = jQuery(nodeName, area).filter(function() { // see if element is present in area
                                return (this === jQuery.cache[ref].handle.elem) ? jQuery.cache[ref].handle.elem : false;
                            });
                            if(areaElms !== false) { // if node is present in the area
                                 unbind(jQuery.cache[ref].events, areaElms);
                            }
                        }
                    }
                }
            }
        }
	
};/* /LBI.common */
