/*  Browser Compatibility */

window.fl_bIsLtIe5 = false;
document.write('<!--[if lt IE 5]>\n	<script>window.fl_bIsLtIe5=true;</script> \n<![endif]-->\n');

window.fl_bIsIe5 = false;
document.write('<!--[if IE 5]>\n	<script>window.fl_bIsIe5=true; window.fl_ieKeyword=\'IE IEB48 IE5\';</script> \n<![endif]-->\n');

window.fl_bIsIe6 = false;
document.write('<!--[if IE 6]>\n	<script>window.fl_bIsIe6=true; window.fl_ieKeyword=\'IE IEB48 IE6\';</script> \n<![endif]-->\n');

window.fl_bIsIe7 = false;
document.write('<!--[if IE 7]>\n	<script>window.fl_bIsIe7=true; window.fl_ieKeyword=\'IE IEB48 IE7\';</script> \n<![endif]-->\n');

window.fl_bIsIe8 = false;
document.write('<!--[if IE 8]>\n	<script>window.fl_bIsIe8=true; window.fl_ieKeyword=\'IE IE8\';</script> \n<![endif]-->\n');

window.fl_bIsGtIe7 = false;
document.write('<!--[if gt IE 7]>\n	<script>window.fl_bIsGtIe7=true;</script> \n<![endif]-->\n');

window.fl_bIsIe = (window.fl_bIsLtIe5  ||  window.fl_bIsIe5  ||  window.fl_bIsIe6  ||  window.fl_bIsIe7  ||  window.fl_bIsIe8  ||  window.fl_bIsGtIe7);

function fl_getIEVersionKeyword()		{  return((typeof(window.fl_ieKeyword) != 'undefined')  ?  window.fl_ieKeyword  :  null);  }
function fl_isIE()				{  return window.fl_bIsIe;  }
function fl_isIE7OrLower()		{  return (window.fl_bIsLtIe5  ||  window.fl_bIsIe5  ||  window.fl_bIsIe6 ||  window.fl_bIsIe7);  }
function fl_isIE6OrLower()		{  return (window.fl_bIsLtIe5  ||  window.fl_bIsIe5  ||  window.fl_bIsIe6);  }


function fl_addIEVersionClass()
{
	if (null === document.body)
	{
		setTimeout('fl_addIEVersionClass();', 200);
		return;
	}
	
	try
	{
		var test = document.body.className;
	}catch(e){
		setTimeout('fl_addIEVersionClass();', 200);
		return;
	}

	if (typeof(window.flbrowserdone) != 'undefined'  &&  window.flbrowserdone)  // already done
		return;
	window.flbrowserdone = true;

	var strKeyword = fl_getIEVersionKeyword();
	if (null !== strKeyword)  // null = not IE
	{
		var strClasses = document.body.className;
		if ('' !== strClasses)
		{
			var aClasses = strClasses.split(' ');
			var bFound = false;
			for (var i=0; i<aClasses.length; i++)
			{
				if (aClasses[i] == strKeyword)
				{
					bFound = true;
					break;
				}
			}
			if (!bFound)
			{
				document.body.className = strKeyword + ' ' + strClasses;  // prepend
			}
		}
		else  // so far no classes assigned
		{
			document.body.className = strKeyword;
		}
	}
}

fl_addIEVersionClass();

function fl_addIECompatibilityCssClasses()
{
	fl_addIEVersionClass();
	for (var i=0; i<document.all.length; i++)
	{
		//	In IE6, the CSS selector pattern "TagName[attribute=value]" doesn't work*, 
		//	so you can't do things like "input[type=checkbox]".
		//	*it actually rejects the entire CSS declaration, up to the closing brace; so this pattern
		//	cannot be used at all, not even in conjunction with other IE6 alternatives.
		var elem = document.all[i];
		if ('INPUT' == elem.tagName)
		{
			if ('checkbox' == elem.type)
			{
				//	This might be less elegant than using fl_addClassToElement(), but is a bit faster.
				//	We don't know how many of these elements we'll have so we have to be lean.
				if ('' === elem.className)
					elem.className = 'CHECKBOX' + elem.className;  // prepend
				else
					elem.className = 'CHECKBOX ' + elem.className;
			}
			else if ('radio' == elem.type)
			{
				if ('' === elem.className)
					elem.className = 'RADIO' + elem.className;
				else
					elem.className = 'RADIO ' + elem.className;
			}
			else if ('text' == elem.type  ||  'password' == elem.type)
			{
				if ('' === elem.className)
					elem.className = 'TEXTBOX' + elem.className;
				else
					elem.className = 'TEXTBOX ' + elem.className;
			}
		}
		else if ('SELECT' == elem.tagName)
		{
			if (elem.multiple)
			{
				if ('' === elem.className)
					elem.className = 'MULTIPLE' + elem.className;
				else
					elem.className = 'MULTIPLE ' + elem.className;
			}
		}
	}
}





function FL_WindowResizeHelper()
{
	this.Advise = FL_WindowResizeHelper_Advise;
	this.OnResize = FL_WindowResizeHelper_OnResize;
	this.__OnAfterResize = __FL_WindowResizeHelper_OnAfterResize;

	this.lastAfterResizeTimeoutId = null;
	this.notifyObjectList = [];
	this.windowObjectName = 'fl_windowResizeHelperObjectName';
	window[this.windowObjectName] = this;
	var tmpThis = this;

	if (null == document.body.onresize)
	{
		document.body.onresize = function() { tmpThis.OnResize(); };
	}
}

function FL_WindowResizeHelper_Advise(objectReference, objectMethodReference)
{
	if (typeof(objectReference) == 'object'  &&  (typeof(objectMethodReference) == 'function'  ||  typeof(objectMethodReference) == 'object'))
	{
		objectReference.__windowResizeHelperAdviseMethod = objectMethodReference;
		this.notifyObjectList.push(objectReference);
	}
	else
	{
		FL_ASSERT(false, 'bad params for FL_WindowResizeHelper_Advise()');
	}
}

function FL_WindowResizeHelper_OnResize()
{
	//	We cannot simply use an HTML "resize" event, because that is fired continuously while the window 
	//	is resizing on desktops where the user has opted to "show window contents while resizing".
	//	this.lastAfterResizeTimeoutId is used so the OnAfter method is only run after 
	//	the last request's timeout (prevents snowballing)
	if (null !== this.lastAfterResizeTimeoutId)
	{
		clearTimeout(this.lastAfterResizeTimeoutId);
		this.lastAfterResizeTimeoutId = null;
	}

	//	this timeout value controls the "wait time" after which we will think that the user has stopped resizing
	//	long enough that a resize event can be fired without too much performance impact.
	this.lastAfterResizeTimeoutId = setTimeout('window[\''+this.windowObjectName+'\'].__OnAfterResize()', 150);
}

function __FL_WindowResizeHelper_OnAfterResize()
{
	for (var i=0; i<this.notifyObjectList.length; i++)
	{
		var objectReference = this.notifyObjectList[i];
		if (typeof(objectReference) == 'object'  &&  typeof(objectReference.__windowResizeHelperAdviseMethod) != 'undefined')
		{
			objectReference.__windowResizeHelperAdviseMethod();
		}
	}
}


function fl_addScreenDpiClasses()
{
	var iDpi = window.external.getScreenDPI();
	if (120 == iDpi)
		fl_addClassToElement(document.body, 'DPI_120', true);  // true=prepend instead of append
}


//	When IE has many layers of elements showing/hiding, it can get very confused
//	and not display borders or sizes correctly, or leave ghost pixels behind.  Silently toggling
//	display and/or border properties seems to wake it up.
function fl_cleanUpIERendering(obj)
{
	if (typeof(obj) == 'undefined'  ||  null === obj)
	{
		FL_ASSERT(false);
		return;
	}
	
	var elementObj = null;
	if (typeof(obj) == 'string')  // element ID
	{
		elementObj = document.getElementById(obj);
	}
	else if (typeof(obj) == 'object')
	{
		if (typeof(obj.currentStyle) != 'undefined')  //OK for IE only
		{
			elementObj = obj;  // actual html element
		}
		else if (typeof(obj.GetWrapperElementObj) != 'undefined')  // a ViewContainer object
		{
			elementObj = obj.GetWrapperElementObj();  // try wrapper element first
			if (null === elementObj)
				elementObj = obj.GetElementObj();
		}
	}

	if (null !== elementObj  &&  typeof(elementObj.currentStyle) != 'undefined')  //OK for IE only
	{
		if ('none' !== elementObj.currentStyle.display)  //OK for IE only
		{
			var oldStyle = elementObj.style.display;
			elementObj.style.display = 'none';
			elementObj.style.display = oldStyle;
		}
		if ('hidden' !== elementObj.currentStyle.visibility)  //OK for IE only
		{
			var oldStyle = elementObj.style.visibility;
			elementObj.style.visibility = 'hidden';
			elementObj.style.visibility = oldStyle;
		}

		var tryBorderStyle = ('none' === elementObj.currentStyle.borderStyle)  ?  'solid'  :  'none';  // something different from what it is now (either adding or removing)
		var oldStyle = elementObj.style.borderStyle;
		elementObj.style.borderStyle = tryBorderStyle;
		elementObj.style.borderStyle = oldStyle;
	}
}

//	a more aggressive algorithm.  uses timeouts to make sure the toggle and the toggle-back are in separate threads.
//	more effective but may cause a very brief flicker.
function fl_cleanUpIERendering2(obj)
{
	if (typeof(obj) == 'undefined'  ||  null === obj)
	{
		FL_ASSERT(false);
		return;
	}
	
	var elementObj = null;
	if (typeof(obj) == 'string')  // element ID
	{
		elementObj = document.getElementById(obj);
	}
	else if (typeof(obj) == 'object')
	{
		if (typeof(obj.currentStyle) != 'undefined')  //OK for IE only
		{
			elementObj = obj;  // actual html element
		}
		else if (typeof(obj.GetWrapperElementObj) != 'undefined')  // a ViewContainer object
		{
			elementObj = obj.GetWrapperElementObj();  // try wrapper element first
			if (null === elementObj)
				elementObj = obj.GetElementObj();
		}
	}

	if (null !== elementObj  &&  typeof(elementObj.currentStyle) != 'undefined')  //OK for IE only
	{
		//	ready to go -- save the element reference to the window so the next thread can get it.
		var objWinNameSeed = '__fl_cleanUpIERendering2_elem';
		var objWinNameIncr = 1;
		var objWinName = objWinNameSeed + objWinNameIncr;
		while (typeof(window[objWinName]) != 'undefined')
		{
			objWinNameIncr++
			objWinName = objWinNameSeed + objWinNameIncr;
		}
		window[objWinName] = elementObj;

		var oldBorderStyle = elementObj.style.borderStyle;
		var tryBorderStyle = ('none' === elementObj.currentStyle.borderStyle)  ?  'solid'  :  'none';  // something different from what it is now (either adding or removing)
		var oldBorderWidth = elementObj.style.borderWidth;
		elementObj.style.borderStyle = tryBorderStyle;
		elementObj.style.borderWidth = '1px';
		setTimeout("__fl_cleanUpIERendering2_finish('"+objWinName+"', '"+oldBorderStyle+"', '"+oldBorderWidth+"');", 0);
	}
}

function __fl_cleanUpIERendering2_finish(objWinName, oldBorderStyle, oldBorderWidth)
{
	var elementObj = window[objWinName];
	elementObj.style.borderStyle = oldBorderStyle;
	elementObj.style.borderWidth = oldBorderWidth;
}

