// ---
/*
	FaT is developed by Robert Nyman, http://www.robertnyman.com
	For more information and copyright information, please see http://www.robertnyman.com/fat
*/
var FaT = {
	// Customization parameters
	overlayId : "fat-dim-overlay",
	clickOverlayToClearFocus : true,
	clickDocumentToClearFocus : false,
	useClearFocusHelpText : true,
	useClearFocusHelpText : true,
	clearFocusHelpText : "Press Esc to clear focus",
	defaultEvent : "mouseover",
	defaultFocusClass : "fat-focused-elm",	
	originalFadeLevel : 0.5,
	elmOriginalFadeLevel : 1, // 1 is totally opaque
	fadeIncrement : 0.1,	
	timeForFadeIncrement : 200, // Milliseconds
	timeForElmFadeIncrement : 100, // Milliseconds
	timeBeforeFocus : 500, // Milliseconds
	
	// FaT parameters
	timer : null,	
	focusElements : null,
	currentElm : null,
	strIdParam : null,
	fadeInParam : null,
	fadeOutParam : null,
	forceClearFocusParam : null,
	functionToCall : "setFocus()",
	overlay : null,	
	focusEvent : "",
	forceClearFocus : false,
	specificElmFocus : false,
	currentFadeLevel : 0.5,
	fadeSpecificElm : false,
	fadeTimer : null,
	fadeOutAfterFadeIn : false,
	fadeTimeIncrementToUse : this.timeForFadeIncrement,
	focusCount : 0,
	currentFocusCount : 0,
	
	init : function (){
		if(document.getElementById){
			this.overlay = $(this.overlayId);
			if(this.overlay){
				this.focusElements = getElementsByClassName(document, "*", "fat");
				this.applyEvents();
				this.useMSFilter = typeof this.overlay.style.filter != "undefined";
			}
		}
	},
	
	applyEvents : function (){
		 var oElm;
		 switch(this.defaultEvent){
		 	case "click":
				for(var i=0; i<this.focusElements.length; i++){
					oElm = this.focusElements[i];
					oElm.onclick = FaT.clickElm;
				}
				break;
			case "mouseover":
				for(var i=0; i<this.focusElements.length; i++){
					oElm = this.focusElements[i];
					oElm.onmouseover = FaT.mouseOverElm;
					oElm.onmouseout = FaT.mouseOutElm;
				}
				break;
		 }		 
		 if(this.clickOverlayToClearFocus){
		 	this.overlay.onclick = function (){
				FaT.clearFocus();                   
			};			
		 }
		 if(this.clickDocumentToClearFocus){
		 	this.addEvent(document, "click", function(){FaT.clearFocus();}, false);
		}
	},
	
	clickElm : function (oEvent){
		var oEvent = (typeof oEvent != "undefined")? oEvent : event;
		FaT.startTimer(oEvent, this);                 
	},
	
	mouseOverElm : function (oEvent){
		var oEvent = (typeof oEvent != "undefined")? oEvent : event;
		FaT.startTimer(oEvent, this);                 
	},
	
	mouseOutElm : function (oEvent){
		var oEvent = (typeof oEvent != "undefined")? oEvent : event;
		FaT.clearFocus(oEvent);				
	},
		
	startTimer : function (oEvent, oElm){
		if(this.currentElm && this.currentElm != oElm){
			this.clearFadeAndFocus();
		}
		this.currentElm = oElm;
		this.focusEvent = oEvent.type;
		this.functionToCall = (this.currentElm.className.search(/fat-only-this/) != -1)? "FaT.setFocusToElm()" : "FaT.setFocus()";
		this.timer = setTimeout(FaT.functionToCall, FaT.timeBeforeFocus);
    },
	
	stopTimer : function (oElm){
		clearTimeout(FaT.timer);
    },
    
    setOverlaySize : function (){
		if(this.overlay){
			var oDimBackground = this.overlay.style;
        	var arrWinSizeAndScroll = this.getWinSizeAndScroll();
        	oDimBackground.width = arrWinSizeAndScroll[0] + arrWinSizeAndScroll[2] + "px";
        	oDimBackground.height = arrWinSizeAndScroll[1] + arrWinSizeAndScroll[3] + "px";
		}
	},
		
	setFocus : function (strId, fadeIn, fadeOut, forceClearFocus){
		var oElm = (typeof strId != "undefined")? $(strId) : null;
		if(this.currentElm && oElm && this.currentElm != oElm){
			this.clearFadeAndFocus();
		}
		this.currentElm = (typeof strId != "undefined")? $(strId) : this.currentElm;		
		var oElm = this.currentElm;
		if(oElm){
			this.strIdParam = (typeof strId != "undefined")? strId : null; 
			this.fadeInParam = (typeof strId != "undefined")? fadeIn : null;
			this.fadeOutParam = (typeof strId != "undefined")? fadeOut : null;
			this.forceClearFocusParam = (typeof strId != "undefined")? forceClearFocus : null;
			var strClassName = oElm.className;
			if(strClassName.search(this.defaultFocusClass) == -1){
				var strCustomClass = "";
				if(strClassName.search(/fat-custom-[\w\d]+[\s$]?/i) != -1){
					strCustomClass = strClassName.replace(/.*fat-custom-([\w\d\-]+).*/i, "$1");
				}
				oElm.className = ((strClassName.length > 0)? (strClassName + " ") : "") + this.defaultFocusClass + ((strCustomClass.length > 0)? " " : "") + strCustomClass;
			}
			if(strClassName.search(/fat-multiple-\d+/) != -1){
				this.focusCount = parseInt(strClassName.replace(/.*fat-multiple-([\d]+).*/i, "$1"), 10);
				this.currentFocusCount++;
				if(this.currentFocusCount == this.focusCount){
					this.focusCount = 0;
					this.currentFocusCount = 0;
				}
			}
			if(!this.specificElmFocus){
				this.setOverlaySize();
				this.overlay.style.display = "block";
			}			
			if(forceClearFocus){
				this.forceClearFocus = true;
			}
			this.fadeSpecificElm = this.specificElmFocus && (fadeIn || fadeOut);
			this.fadeTimeIncrementToUse = (this.fadeSpecificElm)? this.timeForElmFadeIncrement : this.timeForFadeIncrement;
			if(fadeIn){
				this.currentFadeLevel = 0;
				this.fadeOutAfterFadeIn = fadeOut;
				this.fadeIn();
			}
			else if(fadeOut){
				this.fadeOutAndClearFocus();
				if(this.specificElmFocus){
					this.currentFadeLevel = this.elmOriginalFadeLevel;
				}
			}
			else if(forceClearFocus){			
				this.clearFocus();
			}
			if(this.useClearFocusHelpText && this.focusEvent.search(/mouseover/i) == -1){
				oElm.setAttribute("title", this.clearFocusHelpText);
				this.overlay.setAttribute("title", this.clearFocusHelpText);
			}
			var intOffsetTop = oElm.offsetTop;
			var intOffsetElmBottom = intOffsetTop + oElm.offsetHeight;			
			var arrWinSizeAndScroll = this.getWinSizeAndScroll();
			if(intOffsetElmBottom > (arrWinSizeAndScroll[1] + arrWinSizeAndScroll[3]) || intOffsetTop < arrWinSizeAndScroll[3]){
				window.scrollTo(arrWinSizeAndScroll[2], intOffsetTop);
			}
			if(this.specificElmFocus){
				this.specificElmFocus = false;
			}
		}
	},
	
	setFocusToElm : function (strId, fadeIn, fadeOut, forceClearFocus){
		this.specificElmFocus = true;
		this.functionToCall = "setFocusToElm()";
		this.setFocus(strId, fadeIn, fadeOut, forceClearFocus);
	},
	
	clearFocus : function (oEvent, forceClearFocus){
		this.stopTimer();
		if((typeof forceClearFocus == "undefined" || !forceClearFocus) && this.focusCount > 0 && this.currentFocusCount < this.focusCount){
			return (this.functionToCall.search(/setFocusToElm/) != -1)? this.setFocusToElm(this.strIdParam, this.fadeInParam, this.fadeOutParam, this.forceClearFocusParam) : this.setFocus(this.strIdParam, this.fadeInParam, this.fadeOutParam, this.forceClearFocusParam);
		}
		var oElm = this.currentElm;
		if(oElm){
			var bIsChildOfCurrentElm = false;
			if(typeof oEvent != "undefined" && typeof oEvent == "object"){
				var oEventTarget = (typeof oEvent.relatedTarget != "undefined")? oEvent.relatedTarget : oEvent.toElement;
				if(oEventTarget){
					while(!bIsChildOfCurrentElm && oEventTarget && oEventTarget.nodeName && oEventTarget.nodeName.search(/body/i) == -1){
						if(oEventTarget == oElm){
							bIsChildOfCurrentElm = true;
							break;
						}
						oEventTarget = oEventTarget.parentNode;
					}
				}
			}
			if(!bIsChildOfCurrentElm){
				var strClassName = oElm.className;
				var oRegExp = new RegExp(("\\s?" + this.defaultFocusClass), "gi");
				var strRegularClass = strClassName.replace(oRegExp, "");
				if(strClassName.search(/fat-custom-[\w\d]+[\s$]?/i) != -1){
					var strCustomClass = strClassName.replace(/.*fat-custom-([\w\d\-]+).*/i, "$1");
					oRegExp = new RegExp("\\s" + strCustomClass + "$", "i");
					strRegularClass = strRegularClass.replace(oRegExp, "");
				}
				oElm.className = strRegularClass;			
				this.currentElm = null;		
				this.overlay.style.display = "none";
				if(this.useClearFocusHelpText){
					oElm.removeAttribute("title");
					this.overlay.removeAttribute("title");
				}
				this.focusCount = 0;
				this.currentFocusCount = 0;
			}
		}
	},
	
	fadeIn : function (fadeOut){
		this.currentFadeLevel = this.currentFadeLevel + this.fadeIncrement;
		var intEndFadeLevel = (this.fadeSpecificElm)? this.elmOriginalFadeLevel : this.originalFadeLevel;
		if(this.currentFadeLevel < intEndFadeLevel){
			this.fadeTimer = setTimeout("FaT.fadeIn()", FaT.fadeTimeIncrementToUse);
		}
		else if(this.fadeOutAfterFadeIn){			
			this.fadeOutAndClearFocus();
			var intEndFadeLevel = (this.fadeSpecificElm)? this.elmOriginalFadeLevel : this.originalFadeLevel;
		}
		else if(this.focusCount > 0 && this.currentFocusCount < this.focusCount){
			this.currentFadeLevel = 0;
			return (this.functionToCall.search(/setFocusToElm/) != -1)? this.setFocusToElm(this.strIdParam, this.fadeInParam, this.fadeOutParam, this.forceClearFocusParam) : this.setFocus(this.strIdParam, this.fadeInParam, this.fadeOutParam, this.forceClearFocusParam);
		}
		else{
			this.currentFadeLevel = intEndFadeLevel;
			clearTimeout(this.fadeTimer);
			if(this.forceClearFocus){
				this.clearFocus();
				this.forceClearFocus = false;
			}
		}
		this.setFade();
	},
	
	fadeOutAndClearFocus : function (){		
		this.currentFadeLevel = this.currentFadeLevel - this.fadeIncrement;
		if(this.currentFadeLevel > 0){
			this.fadeTimer = setTimeout("FaT.fadeOutAndClearFocus()", FaT.fadeTimeIncrementToUse);
		}
		else{
			if(this.fadeSpecificElm){
				this.currentFadeLevel = this.elmOriginalFadeLevel;
				this.setFade();
			}
			this.currentFadeLevel = this.originalFadeLevel;
			this.clearFocus();
			//clearTimeout(this.fadeTimer); 
		}
		this.setFade();
	},
	
	clearFadeAndFocus : function (){
		if(this.fadeSpecificElm){
			this.currentFadeLevel = this.elmOriginalFadeLevel;
			this.setFade();
		}
		this.currentFadeLevel = this.originalFadeLevel;
		this.clearFocus(false, true);
		clearTimeout(this.fadeTimer);              
	},
	
	setFade : function (){
		// This line is b/c of a floating point bug in JavaScript
		this.currentFadeLevel = Math.round(this.currentFadeLevel * 10) / 10;
		var oElm = (this.fadeSpecificElm)? this.currentElm : this.overlay;
		if(oElm){
			if(this.useMSFilter){
				oElm.style.filter = "progid:DXImageTransform.Microsoft.Alpha(opacity=" + (this.currentFadeLevel * 100) + ")";
			}
			else{
				oElm.style.opacity = this.currentFadeLevel;
			}
		}
	},
	
	getWinSizeAndScroll : function (){
		var intWidth = document.body.offsetWidth;
		var intHeight = (typeof window.innerHeight != "undefined")? window.innerHeight : (document.documentElement && document.documentElement.clientHeight > 0)? document.documentElement.clientHeight : document.body.clientHeight;		
		var intXScroll = (typeof window.pageXOffset != "undefined")? window.pageXOffset : document.body.scrollLeft;		
		var intYScroll = (typeof window.window.pageYOffset != "undefined")? window.window.pageYOffset : (document.documentElement && document.documentElement.scrollTop > 0)? document.documentElement.scrollTop : document.body.scrollTop;
		return [intWidth, intHeight, intXScroll, intYScroll];
	},
	
	captureKeyPressed : function (oEvent){
		var intKey = oEvent.keyCode;
		// If the escape key is pressed
		if(intKey == 27){
			this.clearFocus();
		}
	},
	
	closeSession : function (oEvent){		
		this.removeEvent(window, "load", function(){FaT.init();}, false);
		this.removeEvent(window, "scroll", function(){FaT.setOverlaySize();}, false);
		this.removeEvent(window, "resize", function(){FaT.setOverlaySize();}, false);
		this.removeEvent(document, "keydown", function(oEvent){
			var oEvent = (typeof oEvent != "undefined")? oEvent : event;
			FaT.captureKeyPressed(oEvent);
		}, false);
		FaT = null;
		delete FaT;
	},
	
	addEvent : function (oObject, strEvent, oFunction, bCapture){
		if(oObject){
			if(oObject.addEventListener){
				oObject.addEventListener(strEvent, oFunction, bCapture);
			}
			else if(window.attachEvent){
				oObject.attachEvent(("on" + strEvent), oFunction)
			}
		}
	},

	removeEvent : function (oObject, strEvent, oFunction, bCapture){
		if(oObject){
			if(oObject.removeEventListener){
				oObject.removeEventListener(strEvent, oFunction, false);
			}
			else if(window.detachEvent){
				oObject.detachEvent(("on" + strEvent), oFunction)
			}
		}
	}
};
// ---
FaT.addEvent(window, "load", function(){FaT.init();}, false);
FaT.addEvent(window, "unload", function(){FaT.closeSession();}, false);
FaT.addEvent(window, "scroll", function(){FaT.setOverlaySize();}, false);
FaT.addEvent(window, "resize", function(){FaT.setOverlaySize();}, false);
FaT.addEvent(document, "keydown", function(oEvent){
	var oEvent = (typeof oEvent != "undefined")? oEvent : event;
	FaT.captureKeyPressed(oEvent);
}, false);
// ---
// Utility functions
function getElementsByClassName(oElm, strTagName, strClassName){
	var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
	var arrReturnElements = new Array();
	strClassName = strClassName.replace(/\-/g, "\\-");
	var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
	var oElement;
	for(var i=0; i<arrElements.length; i++){
		oElement = arrElements[i];		
		if(oRegExp.test(oElement.className)){
			arrReturnElements.push(oElement);
		}	
	}
	return (arrReturnElements)
}
// ---
function $(strId){
	return document.getElementById(strId);
}
// ---
if(typeof Array.prototype.push != "function"){
	Array.prototype.push = ArrayPush;
	function ArrayPush(value){
		this[this.length] = value;
	}
}
// ---
