/*
 * ====================================================================
 */

/*
 * Appends the value to the list separated with by a delimiter.
 *
 * @param list the original delimited list
 * @param value the value to add
 * @param delimiter if null, use comma as the delimiter
 *
 * @return The resulting list
 */
function addToDelimitedList(list, value, delimiter)
{
    var separation = ",";
    if (delimiter != null)
{
        separation = delimiter;
    }
    
	if (list.length > 0)
	{
        list += separation;
	}
	list += value;
	
	return list;
}

/*
 * Overrides TAB key functionality in the passed input control to insert two spaces instead of moving
 * focus to the next input control on the page.
 *
 * @param item - an input control
 * @param e - an event
 */
function catchTab(item, e)
{
	if (navigator.userAgent.match("Gecko"))
	{
		c = e.which;
	}
	else
	{
		c = e.keyCode;
	}

	if (c == 9)
	{
		replaceSelection(item, "  ");
		setTimeout("document.getElementById('" + item.id + "').focus();", 0);	
		
		return false;
	}   
}

/* 
 * Determines if the value is present within the comma-delimited list.
 *
 * @param list the delimited list
 * @param value the value to look for
 *
 * @return true if the value is present, false otherwise
 */
function checkDelimitedList(list, value)
{
    /*
     * We need to be careful about values that are substrings of existing values in the list. For
     * example, "tblHealthLog" should not be a match in a list like "tblHealthLog,tblStudent".
     * Therefore we split the string to check whole values rather than doing a simple "indexOf"
     * operation.
     */
    var found = false;

    var existingValues = list.split(',');
    for (var i = 0; i < existingValues.length; i++)
    {
        if (value == existingValues[i])
        {
            found = true;
            break;
        }
    }
    
    return found;
}

/*
 * Enables/disables the passed element and all its children. If true is passed, they will all be 
 * disabled. Otherwise enabled.
 *
 * @param element
 * @param disable
 */
function disableAllElements(element, disable) 
{
	try 
	{
    	element.disabled = disable;
    }
    catch(E)
    {}
                
    if (element.childNodes && element.childNodes.length > 0) 
    {
    	for (var i = 0; i < element.childNodes.length; i++) 
    	{
        	disableAllElements(element.childNodes[i], disable);
        }
    }
}



/*
 * Opens a popup window with the given url and dimensions in the specified browser window. The
 * window will be centered over the parent window. This method will append the session ID to the URL
 * if necessary.  If the keepOpen flag is true, then the popup will not close when the parent window
 * closes.
 *
 * @param url
 * @param width
 * @param height
 * @param windowName
 * @param extraOptions
 * @param xOffset
 * @param yOffset
 * @param keepOpen
 * @param align - left, right, or center (center if not provided)
 */
function doNamedPopup(url, width, height, windowName, extraOptions, xOffset, yOffset, keepOpen, align)
{
    var windowWidth = isMozillaDerivative() ? window.outerWidth : document.body.clientWidth;
    var windowHeight = isMozillaDerivative() ? window.outerHeight : document.body.clientHeight;

    var windowX = isMozillaDerivative() ? window.screenX : window.screenLeft;
    var windowY = isMozillaDerivative() ? window.screenY : window.screenTop;

    if (xOffset)
    {
        windowX += xOffset;
    }
    
    if (yOffset)
    {
        windowY += yOffset;
    }

    var left;
	if (align == "left")
    {
		left = 0;
	}
	else if (align == "right")
	{
		left = screen.availWidth - width - 25;
	}
	else
	{
		left = (windowWidth - width) / 2;
		left += windowX;
	}


    var top = windowY + (windowHeight - height) / 2;

    var standardOptions = "scrollbars=1,resizable=1,menubar=0,location=0";
    var windowOptions = (extraOptions == '' ? standardOptions : extraOptions) +
                        ",width=" + width +
                        ",height=" + height +
                        ",left=" + left +
                        ",top=" + top;

    /*
     * If present, pass the client-side deployment ID into the popup action. This will allow
     * the server to check for client-server deployment synchronization problems.
     */
	var paramChar = "?";
	if (url.indexOf(paramChar) != -1)
	{
		paramChar = "&";
	}
	
	var form = document.forms[0];
	if (form != null && form.elements['deploymentId'] != null && form.elements['deploymentId'].value != null)
	{
		url += paramChar + "deploymentId=" + form.elements['deploymentId'].value; 
	}


    popup = window.open(rewriteUrl(url), windowName, windowOptions);
    popup.focus();
    
    /*
     * If 'keepOpen', then null out the window handle of the popup so that the onUnload() method
     * (which calls popupClose()) does not close the window it just opened. 
     */
    if (keepOpen==true)
    {
    	popup = null;
}
}



/*
 * Redirects a popup window's parent to a specific URL.
 *
 * @param url
 */
function doParentRedirect(url)
{
	// Find the parent window
	var parentWin = findParent();

	if (parentWin != null)
	{
		// The parent window must have a non-empty name otherwise the call to open() will open a new window.
		parentWin.name = "parentWindow";
		parentWin.open(rewriteUrl(url), parentWin.name);
	}
}


/*
 * 
 *
 * @param url
 *
 * @return String
 */
function rewriteUrl(url)
{

    return url;
}


/*
 * Submits a popup window's parent form with the given user event. If the parent form name is null,
 * the first form in the parent window will be submitted.
 *
 * @param event
 * @param parentFormName
 */
function doParentSubmit(event, parentFormName)
{
	// Find the parent window
	var parentWin = findParent();

	// Submit the parent window.
	if (parentWin != null)
	{
		if (parentFormName != null)
		{
			parentForm = parentWin.document.forms[parentFormName];    
		}
		else
		{
			parentForm = parentWin.document.forms[0];
		}
		parentWin.doSubmit(event, parentForm);
	}
}

/*
 * Opens a picklist window with the given url.
 *
 * @param url
 * @param width
 * @param height
 * @param windowName
 */
function doPickList(url, width, height, windowName)
{
    if (width == null)
    {
        width = 400;
    }
    
    if (height == null)
    {
        height = 400;
    }
    
    if (windowName == null)
    {
        windowName = "pickList";
    }

	doNamedPopup(url, width, height, windowName, "");
}

/*
 * Opens a picklist window with the given url. If the picklist is single-select, the value in the
 * form element identified by elementName will be used as a search value.
 *
 * @param url
 * @param formName
 * @param elementName
 * @param searchParameter
 * @param width
 * @param height
 */
function doPickListSearch(url, formName, elementName, searchParameter, width, height)
{
	var searchValue = document.forms[formName].elements[elementName].value;
	url = url + "&" + searchParameter + "=" + searchValue;
	doPickList(url, width, height);
}

/*
 * Opens a popup window with the given url and dimensions. The window will be centered over the
 * parent window. Popups opened with this function all share the same browser window.
 *
 * @param url
 * @param width
 * @param height
 */
function doPopup(url, width, height)
{
    doNamedPopup(url, width, height, "remote", "");
}

/*
 * Redirects a window to a specific URL.
 *
 * @param url
 */
function doSelfRedirect(url)
{
	// The window must have a non-empty name otherwise the call to open() will open a new window.
	this.name = "mainWindow";
	this.open(rewriteUrl(url), this.name);
}


/*
 * Readies a value to be a parameter of a url by correctly escaping characters which could be 
 * mistaken as having a special meaning ('/','\','?','=','&','@'...etc)
 *
 * @param value
 *
 * @return String
 */
function encodeParameter(value) 
{
    value = escape(value);
    value = value.replace(/\//g,"%2F");
    value = value.replace(/\?/g,"%3F");
    value = value.replace(/=/g,"%3D");
    value = value.replace(/&/g,"%26");
    value = value.replace(/@/g,"%40");
    value = value.replace(/,/g,"%2C");
     
    return value;
}  

/*
 * Escapes jquery ids. Should be used in any lookup $(str) where special characters may exist. 
 * All ids which contain oids should use this method.
 * 
 * @param str
 * 
 * @return String
 */
function escapeJQuery(str) 
{ 
    return str.replace(/([#;&,\.\+\*~':"!\^\$\[\]\(\)=>|\/\\])/g, '\\$&'); 
} 
 
/*
 * Fades the opacity of an object from Start to End. 
 *
 * NOTE: Can also be done with JQuery, $('OBJECT').animate({opacity: 1.0}, 1000).fadeOut('SPEED');
 *
 * @param id
 * @param opacStart
 * @param opacEnd
 * @param millisec
 */
function fadeOpacity(id, opacStart, opacEnd, millisec) 
{ 
 	//speed for each frame 
 	var speed = Math.round(millisec / 100); 
 	var timer = 0; 
 	var i = 0;

 	//determine the direction for the blending, if start and end are the same nothing happens 
 	if(opacStart > opacEnd)
 	{ 
 		for(i = opacStart; i >= opacEnd; i--) 
 		{	 
 			setTimeout("setOpacity(" + i + ",'" + id + "');",(timer++ * speed)); 
 		} 
 	} 
 	else if(opacStart < opacEnd) 
 	{ 
 		for(i = opacStart; i <= opacEnd; i++) 
 		{
 			setTimeout("setOpacity(" + i + ",'" + id + "');",(timer++ * speed)); 
 		} 
	} 
}
 
/*
 * Find the parent window for a popup. It could be the window.opener for a windowed popup
 * or window.parent for an embedded popup (See: EmbeddedPopup)
 *
 * @return DOM Window object
 */
function findParent()
{
	var parentWin = null;
	if (this.opener != null)
	{
		parentWin = this.opener;
	}
	else if (window.parent != null)
	{
		parentWin = window.parent;
	}
	
	return parentWin;
}
 
/*
 * Finds the absolute X position passed object's left side.
 *
 * @param obj
 *
 * @return int
 */
function findPositionX(obj)
{
    var curleft = 0;
	
    if (obj.offsetParent)
    {
    	/*
    	 * Loop through all parent nodes of object. Increment width on offsetParent objects and
    	 * where any parent node is being scrolled. OffsetParent objects are what browsers use to
    	 * determine relative positioning, but other parent objects of the obj could be scrolled.
    	 */
    	var objOffsetParent = obj;
        do
        {
        	// only increment on offsetParent objects
        	if (objOffsetParent == obj)
        	{	
        		curleft += obj.offsetLeft;
        
        		objOffsetParent = objOffsetParent.offsetParent;
        	}
        	
        	if (obj.scrollLeft)
        	{
        		curleft -= obj.scrollLeft;
        	}
	    		 
        	obj = obj.parentNode;
        }
        while(obj.parentNode != null);
        
        var xy = getScrollCoordinates();
        curleft += xy[0];
	 }
     else if (obj.x)
     {
         curleft += obj.x;
     }
     
     return curleft;
}
	
/*
 * Finds the absolute Y position of the passed object's top side.
 *
 * @param obj
 *
 * @return int
 */
function findPositionY(obj)
{
    var curtop = 0;
	
    if (obj.offsetParent)
    {
    	/*
    	 * Loop through all parent nodes of object. Increment height on offsetParent objects and
    	 * where any parent node is being scrolled. OffsetParent objects are what browsers use to
    	 * determine relative positioning, but other parent objects of the obj could be scrolled.
    	 */
    	var objOffsetParent = obj;
        do
        {
        	// only increment on offsetParent objects
        	if (objOffsetParent == obj)
        	{
            	curtop += obj.offsetTop;
        
        		objOffsetParent = objOffsetParent.offsetParent;
        	}
        	
        	if (obj.scrollTop)
        	{
        		curtop -= obj.scrollTop;
        	}
	    		 
        	obj = obj.parentNode;
        }
        while(obj.parentNode != null);

        var xy = getScrollCoordinates();
        curtop += xy[1];
	 }
	 else if (obj.y)
	 {
	     curtop += obj.y;
	 }
     return curtop;
}

/*
 * Checks the given object's type. If it is an array then just return it. Otherwise create a one-
 * element array containing the object. This method is useful when dealing with radio or checkbox
 * input controls. If there is only one control in a group then Javascript does not automatically
 * create an array.
 *
 * @param object
 *
 * @return Array
 */
function forceElementToArray(object)
{
    var forcedArray;

    if (object.length)
    {
    	forcedArray = object;
    }
    else
    {
    	forcedArray = new Array(1);
    	forcedArray[0] = object;
    }
	
    return forcedArray;
}

/**
 * Returns a style value currently in use by the passed element.
 *
 * @param element
 * @param styleProperty
 *
 * @return String, style value
 */
function getEffectiveStyle(element, styleProperty)
{	
    var style = null;

    if (isInternetExplorer()) 
    {   
        style = element.currentStyle[styleProperty];
    }
    else
    {
        style = document.defaultView.getComputedStyle(element, null).getPropertyValue(styleProperty);
    }
    
    return style;
}

/*
 * Returns the element corresponding to the given ID. This method extends the default behavior of
 * document.getElementById() by ensuring that the ID of the returned element is exactly equal to the
 * original ID. Some browsers (such as Internet Explorer) perform a case-insensitive lookup in their
 * implementation of document.getElementById().
 *
 * @param id - the element ID to retrieve
 *
 * @return DOM object
 */
function getElementByIdSafe(id)
{
    var element = document.getElementById(id);
    
    if (element != null)
    {
        if (id != element.id)
        {
            element = null;
            
            // Search all elements in the document for a case-sensitive match, if possible.
            var elements = document.all;
            if (elements != null)
            {
                /*
                 * Search the elements array backwards. This is often more efficient since we assume
                 * the elements we create are toward the end of the array. This is the case for
                 * calls to this method in gradeInput.js.
                 */
                for (var i = elements.length - 1; i >= 0 ; i--)
                {
                    if (elements[i].id == id)
                    {
                        element = elements[i];
                        break;
                    }
                }
            }
        }
    }
    
    return element;
}

/*
 * Get the root aspen window (which may or may not have been opened by another window)
 * 
 * @return DOM Window object, 'this' or 'this.opener'
 */
function getParentX2Window()
{
    var parentWin = this.opener;

    /* see if this function exists on the parent */
    try
    {
        if(parentWin.getParentX2Window == null
           || (typeof parentWin.getParentX2Window == 'undefined'))
        {
            parentWin = this;
        }
    }
	catch(err)
    {
	    parentWin = this;
	}

    return parentWin;
}
 
/*
 * Returns a browser specific request object.
 *
 * @return XMLHttpRequest or ActiveXObject
 */
function getRequestObject()
{
    var requestObject = false;

    if (window.XMLHttpRequest) // Mozilla, Safari, ...
    {
        requestObject = new XMLHttpRequest();
    }
    else if (window.ActiveXObject) // Internet Explorer
    {
        requestObject = new ActiveXObject("Microsoft.XMLHTTP");
    }

    if (!requestObject)
    {
        alert('***** UNSUPPORTED BROWSER: Cannot create an XMLHTTP object.');
    }
    
    return requestObject;
}


/*
 * Retrieves the width of the scrollbars. This method is brute force, but independent and safe
 * across browser platforms and versions.
 * 
 * - Append two divs to the body and position them off screen
 * - Measure the width of the inner div
 * - Set the outer div to overflow
 * - Measure the width of the inner div (again)
 * - Return the difference of the two widths
 * - Remove the divs
 *
 * @return int
 */
function getScrollbarWidth()
{
    var noScrollWidth = 0;
    var scrollWidth = 0;
 	
    // Outer scrolling div
    var outerDiv = document.createElement('div');
    outerDiv.style.position = 'absolute';
    outerDiv.style.top = '-1000px';
    outerDiv.style.left = '-1000px';
    outerDiv.style.width = '100px';
    outerDiv.style.height = '50px';
    outerDiv.style.overflow = 'hidden';

    // Inner content div
    var innerDiv = document.createElement('div');
    innerDiv.style.width = '100%';
    innerDiv.style.height = '200px';
     
    outerDiv.appendChild(innerDiv);
    document.body.appendChild(outerDiv);

    noScrollWidth = innerDiv.offsetWidth;
    
    // Add the scrollbar. If the size doesn't change, try 'scroll' overflow
    outerDiv.style.overflow = 'auto';

    if (noScrollWidth - innerDiv.offsetWidth == 0)
    {
   	    outerDiv.style.overflow = 'scroll';
    }
    
    scrollWidth = innerDiv.offsetWidth;

    var SCROLLBAR_WIDTH = (noScrollWidth - scrollWidth);
    
    // Remove the scrolling div from the doc
    document.body.removeChild(document.body.lastChild);
    
    return SCROLLBAR_WIDTH;
}
 
 /**
  * Gets scroll coordinates;
  * 
  * @return Array(x,y)
  */
 function getScrollCoordinates() 
 {
 	var x;
 	var y;
 	
 	if (self.pageYOffset) // all except Explorer 
 	{ 
 		x = self.pageXOffset; 
 		y = self.pageYOffset; 
 	} 
 	else if (document.documentElement && document.documentElement.scrollTop) // Explorer 6 Strict 
 	{ 
 		x = document.documentElement.scrollLeft; 
 		y = document.documentElement.scrollTop; 
 	} 
 	else if (document.body) // all other Explorers 
 	{ 
 		x = document.body.scrollLeft; 
 		y = document.body.scrollTop; 
 	}
 	
 	return new Array(x, y);
 } 
 
/*
 * Returns the text content of the passed element. This convenience function handles browser
 * syntax variations.
 *
 * @param element
 *
 * @return String
 */
function getTextContent(element)
{
    var elementContent;
    if (isInternetExplorer())
    {
        elementContent = element.text;
    }
    else
    {
        elementContent = element.textContent;
    }
    
    return elementContent;
}


 /*
 * Creates HTML for a table containing n cells where one of the cells is highlighted.  This is used 
 * to create an animation for the timeout clock, updated once per second
 * 
 * @param index - a number to modulate against 'columns' to determine which table cell is highlighted
 * @param columns - the number of columns to create in the table
 *
 * @return String
 */
function getTimerAnimation(index, columns)
{
	 var html = '<table class="timerAnimation">';
	 for (i=0; i<columns; i++)
	 {
		 cellStyle = 'timerAnimationCell1';
		 if (index % columns == i)
		 {
			 cellStyle = 'timerAnimationCell2';
		 }
		 html = html + '<td class="'+cellStyle+'">&nbsp;</td>';
	 }
	html = html + '</tr></table>';

	return html;
}

 /*
  * Returns the window handle for the window that is supposed to have focus, i.e. the top most
  * window.  This is either the current window, or this window's popup.
  *
  * @return DOM Window object
  */
  function getTopWindowHandle()
  {
 	 var hWin = this;
 	 
      if (popup != null && !popup.closed)
      {
     	 hWin = popup;
      }
      return hWin;
  }
  
/*
 * Returns the height of the browser window. Browsers differ in where they store this 
 * information. Thus, we check the different locations to assure we get the value.
 *
 * @return int
 */
function getWindowHeight()
{
    var y = 0;

    if (self.innerHeight) //All except IE
    {
        y = self.innerHeight;
    }
    else if (document.documentElement && document.documentElement.clientHeight) //IE6 Strict Mode
    {
        y = document.documentElement.clientHeight;
    }
    else if (document.body) //Other IE
    {
        y = document.body.clientHeight;
    }

    return y;
}

/*
 * Returns the width of the browser window. Browsers differ in where they store this 
 * information. Thus, we check the different locations to assure we get the value.
 *
 * @return int
 */
function getWindowWidth()
{
    var x = 0;

    if (self.innerWidth) //All except IE
    {
        x = self.innerWidth;
    }
    else if (document.documentElement && document.documentElement.clientWidth) //IE6 Strict Mode
    {
        x = document.documentElement.clientWidth;
    }
    else if (document.body) //Other IE
    {
        x = document.body.clientWidth;
    }
  
    return x;
}

/*
 * Preloads a url without forwarding the browser to the address using AJAX. Then will redirect the
 * browser to the goUrl.
 * 
 * NOTE: This method is self referencing. You can pass it as many preload URLs as needed. The last 
 * URL passed will always be the one the browser is redirected to. That value can be explicitly set
 * to NULL if preloading is needed, but you don't want the browser to redirect away from the page. 
 * 
 * @param preLoadUrl
 * @param goUrl
 */
function goPreLoad(preLoadUrl, goUrl)
{
    var callback = null;
    if (arguments.length > 2)
    {
        var args = Array.prototype.slice.call(arguments);
    	args.splice(0, 1);
    	callback = args;
    }
	 
    $.ajax({
            type: "GET",
            url: preLoadUrl,
            async: false,
            success: function(){if (callback != null){goPreLoad.apply(this,callback);}else if(goUrl!=null){window.location=goUrl}},
            error: function(){$("#sra-status").text("Communication failure");},
            cache: false
    });
}

/*
 * Hides the loading cover.
 */
function hideLoadingCover()
{
	$("#loadingCover").hide();
}

/*
 * Includes the appropriate common stylesheet based on the client browser.
 *
 * @param media
 */
function includeCommonStylesheet(media)
{
    var browserSuffix = "";

    if (isInternetExplorer() || isOpera())
    {
        browserSuffix = "ie";
    }
    else
    {
        browserSuffix = "mo";
    }

    if (media == null)
    {
        media = "screen";
    }

    document.write("<link rel=StyleSheet href=\"css/common-" + browserSuffix + ".css\" type=\"text/css\" media=\"" + media + "\">");
}

/*
 * Includes the appropriate printable stylesheets based on the client browser. Two stylesheets are 
 * included: the common stylesheet and the printable-specific stylesheet.
 */
function includePrintableStylesheet()
{
    includeCommonStylesheet();
    includeCommonStylesheet("print");

    document.write("<link rel=StyleSheet href=\"css/printable.css\" type=\"text/css\" media=\"screen\">");
    document.write("<link rel=StyleSheet href=\"css/printable.css\" type=\"text/css\" media=\"print\">");
}

/*
 * Includes the appropriate stylesheets based on the client browser. Two stylesheets are included:
 * the common stylesheet and the context-specific stylesheet.
 *
 * @param context the resource name of the context
 */
function includeStylesheet(context)
{
    includeCommonStylesheet();
    document.write("<link rel=StyleSheet href=\"css/" + context + ".css\" type=\"text/css\" media=\"screen\">");
}

/*
 * Returns true if the client browser is Mozilla Camino, false otherwise.
 *
 * @return boolean
 */
function isCamino()
{
    return (navigator.userAgent.indexOf("Camino") != -1);
}

/*
 * Returns true if the client browser is Chrome, false otherwise.
 *
 * @return boolean
 */
function isChrome() 
{
	return (navigator.userAgent.indexOf("Chrome") != -1);
}
 
/*
 * Returns true if the client browser is Mozilla Firefox, false otherwise.
 *
 * @return boolean
 */
function isFirefox()
{
    return (navigator.userAgent.indexOf("Firefox") != -1);
}

/*
 * Returns true if the client browser is Internet Explorer, false otherwise.
 *
 * @return boolean
 */
function isInternetExplorer()
{
    return ((navigator.appName == "Microsoft Internet Explorer") && !isOpera());
}

/*
 * Returns true if the client browser is Internet Explorer 6 or lower, false otherwise.
 */
function isInternetExplorer6()
{
	var isIe6 = false /*@cc_on || @_jscript_version < 5.7 @*/;
	
    return isIe6;
}

/*
 * Returns true if the client browser is Internet Explorer 7, false otherwise.
 */
function isInternetExplorer7()
{
	var isIe7 = false /*@cc_on || @_jscript_version == 5.7 @*/;
	
    return isIe7;
}

/*
 * Returns true if the client browser is Internet Explorer 8 or greater, false otherwise.
 */
function isInternetExplorer8()
{
	var isIe8 = false /*@cc_on || @_jscript_version > 5.7 @*/;
	
    return isIe8;
}

/*
 * Returns true if the client browser is pure Mozilla (not a derivative like Netscape, Firefox,
 * Camino, Safari, etc.), false otherwise.
 *
 * @return boolean
 */
function isMozilla()
{
    return ((navigator.appName == "Netscape") && !isCamino() && !isFirefox() && !isNetscape() && !isSafari());
}

/*
 * Returns true if the client browser is any derivative of Mozilla (Mozilla, Netscape, Firefox,
 * Camino, Safari, etc.), false otherwise.
 *
 * @return boolean
 */
function isMozillaDerivative()
{
    return (navigator.appName == "Netscape");
}

/*
 * Returns true if the underlying client operating system is Macintosh, false otherwise.
 *
 * @return boolean
 */
function isMacintosh()
{
    return (navigator.appVersion.indexOf("Macintosh") != -1);
}

/*
 * Returns true if the client browser is Netscape, fals otherwise.
 *
 * @return boolean
 */
function isNetscape()
{
    return (navigator.userAgent.indexOf("Netscape") != -1);
}

/*
 * Returns true if the client browser is Opera, false otherwise.
 *
 * @return boolean
 */
function isOpera()
{
    return (navigator.userAgent.indexOf("Opera") != -1);
}

/*
 * Returns true if the client browser is Safari, false otherwise.
 *
 * @return boolean
 */
 function isSafari()
 {
     return ((navigator.userAgent.indexOf("Safari") != -1) && !isChrome());
 }

/*
 * Returns true if the underlying client operating system is Windows, false otherwise.
 *
 * @return boolean
 */
function isWindows()
{
    return (navigator.appVersion.indexOf("Windows") != -1);
}

/*
 * Returns true if the underlying client operating system is some derivative of UNIX (including
 * Linux), false otherwise.
 *
 * @return boolean
 */
function isX11()
{
    return (navigator.appVersion.indexOf("X11") != -1);
}

/**
 * Limit the characters in a given field
 * 
 * @param theEvent
 * @param theField - field to truncate if necessary
 * @param maxLength - length allowed
 *
 * @return true
 */
function limitText(theEvent, theField, maxLength)
{
	theEvent = theEvent || window.event;
	if (theEvent)
	{
		var content = (theField.getTextOnlyContent)? theField.getTextOnlyContent() : theField.value;		
		var keyCode = theEvent.charCode || theEvent.keyCode;
		if (maxLengthReached(content, maxLength))
		{
			// We use the pattern to prevent space characters
			var thePattern = /\s/g;
			if (String.fromCharCode(keyCode).match(thePattern) || // Space - theEvent.DOM_VK_SPACE => 32
					keyCode > 46 || // Delete key - theEvent.DOM_VK_DELETE => 46
					theEvent.altKey || theEvent.shiftKey || // Stop special characters
					keyCode == 16 || keyCode == 18) // Safari keyup need to stop DOM_VK_SHIFT => 16, DOM_VK_ALT => 18 
			{
				return stopBrowserEvent(theEvent);				
			}
		}		
		// Catch keyboard paste
		if ((theEvent.ctrlKey && theEvent.keyCode == 86) // theEvent.DOM_VK_V 
				|| (theEvent.shiftKey && theEvent.keyCode == 45)) // theEvent.DOM_VK_INSERT
		{
			trimField(theField, maxLength, false);
		}
	}
	
	return true;
}



/*
 * Close any open popups, and if this is a popup, close itself
 */
function popupClose()
{
    if (popup != null && !popup.closed)
    {
	    popup.popupClose();
    }
    if (this != getParentX2Window())
    {
    	this.close();
    }
}

/*
 * Removes the passed value from the passed delimited list.
 *
 * @param list the original delimited list
 * @param value the value to remove
 * @param delimiter if null, use comma as delimiter
 *
 * @return List
 */
function removeFromDelimitedList(list, value, delimiter)
{
    var newList = "";
    var separation = ',';
    if (delimiter != null)
    {
        separation = delimiter;
    }

    var existingValues = list.split(separation);
    for (var i = 0; i < existingValues.length; i++)
    {
        if (value != existingValues[i])
        {
            newList = addToDelimitedList(newList, existingValues[i]);
        }
    }
    
    return newList;
}

/**
 * Strips out HTML code. Add extra checks here as needed.
 * 
 * @param html
 * 
 * @return String
 */
function removeHTML(html)
{
	// Remove tags
	html = html.replace(/<\/?[^>]+(>|$)/g, "");
	
    // Remove special characters
    html = html.replace(/&nbsp;*/g, " ");
    html = html.replace(/&quot;*/g, "\"");
    html = html.replace(/&amp;*/g, "&");
    html = html.replace(/&lt;/g, "<");
    html = html.replace(/&gt;/g, ">");
    
    return html;
}
 
/*
 * Replaces the current text selection in the passed input control with the given replacement
 * string.
 * 
 * @param input
 * @param replaceString
 */
function replaceSelection(input, replaceString)
{
    if (input.setSelectionRange)
    {
        var selectionStart = input.selectionStart;
		var selectionEnd = input.selectionEnd;
		input.value = input.value.substring(0, selectionStart) + replaceString + input.value.substring(selectionEnd);
    
		if (selectionStart != selectionEnd)
		{ 
			setSelectionRange(input, selectionStart, selectionStart + 	replaceString.length);
		}
		else
		{
			setSelectionRange(input, selectionStart + replaceString.length, selectionStart + replaceString.length);
		}

	}
	else if (document.selection)
	{
		var range = document.selection.createRange();

		if (range.parentElement() == input)
		{
			var isCollapsed = range.text == '';
			range.text = replaceString;

			if (!isCollapsed) 
			{
				range.moveStart('character', -replaceString.length);
				range.select();
			}
		}
	}
}



/**
 * Saves the coordinates of the scroll window upon submit.
 */
function saveScrollCoordinates() 
{
	var form = document.forms[0];
	var xy = getScrollCoordinates();
	
	form.scrollX.value = xy[0]; 
	form.scrollY.value = xy[1];
	} 

/**
 * Uses the saved scroll coordinates to set the scroll position.
 */
function scrollToCoordinates() 
{
	var form = document.forms[0];
	
	// For popup windows
	if (form == null)
    {
		form = this;
    }
	
    window.scrollTo(form.scrollX ? form.scrollX.value : 0, form.scrollY ? form.scrollY.value : 0);
} 



/**
 * Updates the value of the hidden property that contains the actual boolean value of the checkbox.
 *
 * @param hiddenProperty - the name of the hidden property to update
 * @param checkbox - the checkbox input control that contains the user input
 */
function setBooleanValue(hiddenProperty, checkbox)
{
    checkbox.form.elements[hiddenProperty].value = checkbox.checked.toString();
}

/*
 *	Sets the HTML for the "contentArea" of a page.  This is used for obfuscating
 *  sensitive student/staff information when a session has timed out. 
 *
 * @param htmlData
 */
function setContentArea(htmlData)
{
	var textArea = document.getElementById("contentArea");
	if (textArea != null)
	{
		textArea.innerHTML = htmlData;
	}
}

/*
 * Sets focus to the first element in the form that is not hidden and is not a button and is not the
 * template selection control (which is recognized by the name "currentTemplateIndex").
 *
 * @param form
 */
function setDefaultFocus(form)
{
    var elements = form.elements;
    for (var i = 0; i < elements.length; i++)
    {
        var inputElement = elements[i];
        if (inputElement != null && inputElement.type != "hidden" &&
            inputElement.type != "button" && inputElement.name != "currentTemplateIndex")
        {
            try
            {
                inputElement.focus();
                break;
            }
            catch (e)
            {
                /*
                 * An element may not be able to receive focus for several reasons; such as being
                 * contained in a div or table that is hidden. If this occurs, try the next element.
                 */
            }
        }
    }
}


 
/**
 * Sets the initial state of the maximize/minimize icon.
 * 
 * @param maximizeTitle
 * @param minimizeTitle
 */
function setInitialMaximizedState(maximizeTitle, minimizeTitle)
{
	var layoutHeader = document.getElementById("layoutHeader");
	
	var maximized = layoutHeader.style.display == "";
	updateMaximizedImage(maximized, maximizeTitle, minimizeTitle);
	
	if (!maximized)
	{
		if (document.getElementById('dataGrid') != null)
		{
			UNAVAILABLE_WIDTH = 30;
		}
		else if (window.scrollTable)
		{
			UNAVAILABLE_WIDTH = 10;
			UNAVAILABLE_HEIGHT = 130;
		}
	}
}

/**
 * Change the opacity for different browsers.
 * 
 * @param opacity
 * @param id
 */
function setOpacity(opacity, id) 
{ 
	var object = document.getElementById(id).style; 
	object.opacity = (opacity / 100); 
	object.MozOpacity = (opacity / 100); 
	object.KhtmlOpacity = (opacity / 100); 
	object.filter = "alpha(opacity=" + opacity + ")"; 
}

/*
 * Makes a text selection in the passed input control at the given start and end positions.
 *
 * @param input
 * @param selectionStart
 * @param selectionEnd
 */
function setSelectionRange(input, selectionStart, selectionEnd)
{
    if (input.setSelectionRange)
    {
        input.focus();
        input.setSelectionRange(selectionStart, selectionEnd);
    }
    else if (input.createTextRange)
    {
        var range = input.createTextRange();
        range.collapse(true);
        range.moveEnd('character', selectionEnd);
        range.moveStart('character', selectionStart);
        range.select();
    }
}

/*
 * "Shims" a DIV element with its corresponding IFRAME element. This method should only be used by
 * an Internet Explorer browser.
 *
 * @param divId	- the ID of the DIV element that needs to be "shimmed", the corresponding IFRAME
 *                is assumed to have an ID equal to divId + 'Shim'
 */
function shim(divId)
{
    var divElement = getElementByIdSafe(divId);
    var iframeElement = getElementByIdSafe(divId + 'Shim');
    
    if (isInternetExplorer() && iframeElement!=null)
    {
	    iframeElement.style.width = divElement.offsetWidth;
	    iframeElement.style.height = divElement.offsetHeight;
        iframeElement.style.top = divElement.currentStyle.top;
        iframeElement.style.left = divElement.currentStyle.left;
        iframeElement.style.zIndex = divElement.currentStyle.zIndex - 1;
	    iframeElement.style.display = "block";
    }
}

/*
 * Displays a div over the passed container (a TD, DIV, etc) with a loading message.
 *
 * @param container
 */
function showLoadingCover(container)
{
	var loadingCover = document.getElementById("loadingCover");
	
	loadingCover.style.left = findPositionX(container);
	loadingCover.style.top  = findPositionY(container);
	loadingCover.style.width = container.offsetWidth;
	
	loadingCover.style.height = getWindowHeight() - 85;
	
	$("#loadingCover").show();
}

/**
 * Stop browser event
 *
 * @param theEvent, browser event to be handled
 *
 * @return false
 */
function stopBrowserEvent(theEvent)
{
	if (!theEvent.ctrlKey && ! theEvent.shiftKey && // Don't warn on paste
			theEvent.type == 'keyup' && // other key events may not be input
			theEvent.keyCode != 13) // Skip to close the box
	{
		alert(grabResource("message.truncate.limit"));
	}
	
	if (theEvent.preventDefault)
	{
		theEvent.preventDefault(); // Mozilla
	}
	else
	{
		theEvent.returnValue = false; // IE
	}
	
	return false;
}

 

 /**
  * Toggles visibility of all components of the default layout except the page body. Also swaps the
  * maximize and minimize icons.
  * 
  * @param maximizeTitle
  * @param minimizeTitle
  */
 function toggleMaximize(maximizeTitle, minimizeTitle)
 {
 	var form = document.forms[0];
 	
 	if (form.elements['maximized'] != null)
 	{
 		var maximized = "true" == form.elements['maximized'].value;

 		var layoutHeader = document.getElementById("layoutHeader");
 		layoutHeader.style.display = maximized ? "" : "none";
 	
 		var layoutVerticalTabs = document.getElementById("layoutVerticalTabs");
 		layoutVerticalTabs.style.display = maximized ? "" : "none";
 	
 		var layoutVerticalTabsContainer = document.getElementById("layoutVerticalTabsContainer");
 		layoutVerticalTabsContainer.style.width = maximized ? "100" : "3";
 	
 		if (document.getElementById('dataGrid') != null)
 		{
 			UNAVAILABLE_WIDTH = maximized ? 125 : 30;
 			
 			resizeGrid('dataGrid');
 		}
 		else if (window.scrollTable)
 		{
 			UNAVAILABLE_WIDTH = maximized ? 125 : 10;
 			UNAVAILABLE_HEIGHT = maximized ? 217 : 130;
 			
 			scrollTable();
 		}
 	
 		var aElements = document.getElementsByTagName('a');
 		for (var i = 0; i < aElements.length; i++)
 		{
 			var aElement = aElements[i];
 			if (aElement.id.startsWith("link_"))
 			{
 				aElement.href = updateMaximizedParam(aElement.href, maximized);
 			}
 		}		
 		
 		for (var optionId in optionsById)
 		{
 			var option = optionsById[optionId];
 			option.action = updateMaximizedParam(option.action, maximized);
 		}
 		
 		updateMaximizedImage(maximized, maximizeTitle, minimizeTitle);

 		maximized = !maximized;
 		
 		form.elements['maximized'].value = maximized;
 	}
 }


/**
 * Trim the given field to the desired length
 * 
 * @param field
 * @param maxLength 
 * @param showConfirm
 */
function trimField(field, maxLength, showConfirm)
{
    if (field.truncate)
  	{
  		var callTruncate = function (){field.truncate(showConfirm);};
  		setTimeout(callTruncate, 100);
  	}
  	else
  	{
  		if (field.value.length > maxLength)
  		{
  			var truncateText = true;
  			if (showConfirm && !confirm(grabResource("message.truncate.warning")))
  			{
  				truncateText = false;
  			}
  			
  			if (truncateText)
  			{
  				alert(grabResource("message.truncate.error"));
  				field.value = field.value.substring(0, maxLength);
 			}
 		}
 	}
}
  
/**
 * Truncate the characters in a given field
 * 
 * @param theEvent - UI event
 * @param field - field to truncate if necessary
 * @param maxLength - length allowed
 */
function truncateText(theEvent, field, maxLength)
{
	theEvent = theEvent || window.event;
	var showConfirm = true;
	if (theEvent)
	{
		/*
		 * In fire fox the paste event is called first and then the input.
		 * IE does not support the input event. IE also does not complete the paste
		 * so we have to get the clip board contents and handle the paste event.
		 */
		if (theEvent.type == 'paste' || theEvent.type == 'input')
		{
			showConfirm = false;
			var pasteContent = theEvent.clipboardData && theEvent.clipboardData.getData ?
					theEvent.clipboardData.getData('text/plain') : // Standard
						window.clipboardData && window.clipboardData.getData('Text') ?
								window.clipboardData.getData('Text') : // IE
									false;
			if (pasteContent)
			{
				field.value += pasteContent;
				trimField(field, maxLength, showConfirm);
				
				// Paste was handled. Prevent browser from processing event
				return stopBrowserEvent(theEvent);
			}
		}
	}
	// In case, we fail to retrieve clip-board data, like fire fox
	trimField(field, maxLength, showConfirm);
}

/*
 * Hides the "shim" IFRAME element corresponding to the a DIV element. This method should only be
 * used by an Internet Explorer browser.
 *
 * @param divId	- the ID of the DIV element that needs to be "unshimmed", the corresponding IFRAME
 *                is assumed to have an ID equal to divId + 'Shim'
 */
function unShim(divId)
{
	var iframeElement = getElementByIdSafe(divId + 'Shim');
	
    if (isInternetExplorer() && iframeElement!=null)
    {
        iframeElement.style.display = "none";
    }
}


/*
 * Updates the "disabled" property of an input control. This method also hides or displays any
 * associated "helper control" (e.g., the calendar for a date picker or the magnifying glass for a
 * pick list.
 *
 * @param formName - the name of the form
 * @param elementName - the name of the input control element
 * @param enable - either true or false
 */
function updateInputControl(formName, elementName, enable)
{
    var control = document.forms[formName].elements[elementName];
    control.disabled = !enable;
    
    var sibling = control.parentNode.parentNode.lastChild.firstChild;
    if (sibling != null && sibling.tagName == 'A')
    {
        sibling.style.display = (enable ? 'block' : 'none');
    }
}
 
/**
 * Updates the maximized parameter.
 * 
 * @param url
 * @param maximized
 * 
 * @return String, url
 */
function updateMaximizedParam(url, maximized)
{
	var maximizedParam = 'maximized=' + !maximized;
	
	if (url != null)
	{
		if (url.indexOf('maximized') != -1)
		{
			url = url.replace('maximized=' + maximized, maximizedParam);
		}
		else if (url.indexOf('?') != -1)
		{
			url = url.replace('?', '?' + maximizedParam + '&');
		}
		else if (url.indexOf('.do') != -1)
		{
			url = url.replace('.do', '.do?' + maximizedParam);
		}
	}

	return url;
}

/**
 * Updates the maximize/minimize icon to match the current state of the page.
 * 
 * @param maximized
 * @param maximizeTitle
 * @param minimizeTitle
 */
function updateMaximizedImage(maximized, maximizeTitle, minimizeTitle)
{
	var image = document.getElementById("maximizeImg");
	if (maximized)
	{
		image.src = "images/max-window.gif";
		image.title = maximizeTitle;
	}
	else
	{
		image.src = "images/restore-window.gif";
		image.title = minimizeTitle;
	}
}



/**
 * Validates the format of the passed email address.
 *
 * @param email
 */
function validateEmail(email)
{
	var regEx = /.+\@.+\..+/;
	var validated = false;
	
	if(email != null)
	{
		if(regEx.exec(email) != null)
		{
			validated = true;
		}
	}
	
	return validated;
}

/*
 * Validates onkeypress events are numeric.  e.g. <input type='text' onkeypress='validateNumeric(event)' />
 *
 * @param evt
 */
function validateInteger(evt)
{
   var theEvent = evt || window.event;
   var key = theEvent.keyCode || theEvent.which;
   key = String.fromCharCode( key );
   var regex = /[0-9]|[\x08\x09\x0D\x10\x25\x27\x23\x24]/; /* digits, bs, tab, enter, shift, left arrow, right arrow, home, end */ 
   if( !regex.test(key) )
   {
       theEvent.returnValue = false;
       theEvent.preventDefault();
	    }
}

/*
 * Returns true if at least one item in the control array has been selected, false otherwise.
 *
 * @param control
 *
 * @return boolean
 */
function verifySelection(control)
{
    var selected = false;
 
    if (control != null)
    {
        var controls = forceElementToArray(control);
        for (var i = 0; i < controls.length; i++)
        {
            if (controls[i].checked)
            {
                selected = true;
                break;
            }
        }
    }

    return selected;
}

/*
 * Add, remove or fire an event listener for an element. This method can safely handle multiple
 * listeners for an element for the same event. All listeners will be preserved and fired as needed.
 *   functions:  elementAddlistener
 *               elementRemoveListener
 *               elementFireEvent
 *
 * @param element  - form input element
 * @param type     - event name without 'on'. ex: 'change'
 * @param listener - listener function (no parens)
 */
function elementAddListener(element, type, listener)
{
	if (element != null)
	{
		if (element.addEventListener != null)
    	{
			element.addEventListener(type, listener, true);
    	}
    	else
    	{
    	    // Older IE do not support standard above, use specific function.
        	element.attachEvent('on' + type, listener);
    	}
	}
}

function elementRemoveListener(element, type, listener)
{
    if (element.removeEventListener)
    {
        element.removeEventListener(type, listener, false);
    }
    else
    {
        element.detachEvent('on' + type, listener);
    }
}

function elementFireEvent(element, type)
{
    if (element.dispatchEvent != null)	           
    {
        var eventObject = document.createEvent('HTMLEvents');
        eventObject.initEvent(type, true, false);
        element.dispatchEvent(eventObject);
    }
    else
    {
  	    // Older IE do not support standard above, use specific function.
        element.fireEvent('on' + type);
    }
}

 

/****************************************************************************************
 * Defines the embedded popup handling manager: EmbeddedPopup
 * All EmbeddedPopup functionality is contained within the object EmbeddedPopup
 * 
 * A manager object called EmbeddedPopup.popupManager can be used to perform 
 * all popup related activity.
 * 
 * To open an embedded popup window, call:
 * 
 *       EmbeddedPopup.popupManager.open('url', width, height, top)
 *       
 * To close an embedded popup window, call:
 * 
 *       EmbeddedPopup.popupManager.close();
 *       
 *    This close can be called from the parent window to close the child,
 *    or from within the child popup to close itself.
 *     
 *****************************************************************************************/
function EmbeddedPopup()
{
	 // Establish instance variables.
	this.showingFrame = false;
	this.documentNode = null;
	this.bodyNode     = null;
	this.divNode      = null;
	this.iframeNode   = null;
}

/*
 * Open the embedded popup window.
 * 
 * @param pUrl
 * @param pWidth
 * @param pHeight
 * @param pTop
 */
EmbeddedPopup.prototype.open = function (pUrl, pWidth, pHeight, pTop) 
{
	// Initialize the popup manager if necessary.
	this.initialize();
	
	if (!this.showingFrame && this.iframeNode != null && this.divNode != null)
	{
		this.url = pUrl;
		this.width = pWidth;
		this.height = pHeight;
		this.top = pTop;

		// Adjustment for small browser windows (i.e., for popups).
		var windowWidth = document.body.clientWidth;
		if (this.width > (windowWidth - 50))
		{
			this.width = windowWidth - 50;
		}
		// calculate  position left based on width.
			var left = (windowWidth - this.width) / 2;

		this.divNode.style.display = "block";

		this.iframeNode.style.left = left;
		this.iframeNode.style.top = this.top;
		this.iframeNode.style.width = this.width;
		this.iframeNode.style.height = this.height;
		this.iframeNode.style.display = "block";
		this.iframeNode.src = this.url;

		if (isMozilla())
		{
	    	// For Mozilla/DOM, the focus can be caught at the root of the document.
			elementAddListener(this.documentNode, 'focus', this.onfocus);
		}
		else
		{
	    	// For IE, find all non hidden input element to capture focus events.
	    	var elms = this.documentNode.forms[0].elements;
	    	for (var idx = 0; idx < elms.length; idx++)
	    	{
	    		var elm = elms[idx];
				if (elm.getAttribute("type") != "hidden")
				{
					elementAddListener(elm, 'focus', this.onfocus);
				}
	    	}
		}

    	this.showingFrame = true;
	}
}

/*
 * Open the cover pane to block the screen.
 */
EmbeddedPopup.prototype.openCover = function () 
{
	// Initialize the popup manager if necessary.
	this.initialize();
	
	if (!this.showingFrame && this.divNode != null)
	{
		this.divNode.style.display = "block";
    	this.showingFrame = true;
	}
}

/* 
 * Set the background opacity to the Percentage specified
 * 
 * @param percentage
 */ 
EmbeddedPopup.prototype.setBackgroundOpacity = function (percentage)
{
    if (this.divNode != null)
    {
    	// fade to the percentage starting with the current value
    	fadeOpacity(this.divNode.id, 60, percentage, 1000);
    }
}

/*
 * Initialize the embedded popup window.
 */
EmbeddedPopup.prototype.initialize = function () 
{
    if (!this.showingFrame && (this.bodyNode == null || this.iframeNode == null || this.divNode == null))
	{
    	this.documentNode = document;
    	this.bodyNode = document.body;
    	// Build cover div element.
    	this.divNode = document.createElement("div");
    	this.divNode.id="embeddedCover";
    	this.divNode.className="embeddedCoverClass";
    	this.divNode.style.display="none";
    	this.bodyNode.appendChild(this.divNode);
    	// Build embedded iframe.
    	this.iframeNode = document.createElement("iframe");
    	this.iframeNode.id="embeddedFrame";
    	this.iframeNode.className="embeddedFrameClass";
    	this.iframeNode.style.display="none";
    	this.bodyNode.appendChild(this.iframeNode);
	}
}

/*
 * Close the embedded popup window.
 */
EmbeddedPopup.prototype.close = function ()
{
    if (this.showingFrame && this.iframeNode != null && this.divNode != null)
	{
    	// Parent closing its child.
		this.iframeNode.style.display = "none";
		this.iframeNode.src = null;
		this.divNode.style.display = "none";

		if (isMozilla())
		{
	    	// For Mozilla/DOM, remove the focus listener.
			elementRemoveListener(this.documentNode, 'focus', this.onfocus);
		}
		else
		{
	    	// For IE, remove all focus listeners from non hidden input elements.
	    	var elms = this.documentNode.forms[0].elements;
	    	for (var idx = 0; idx < elms.length; idx++)
	    	{
	    		var elm = elms[idx];
				if (elm.getAttribute("type") != "hidden")
				{
					elementRemoveListener(elm, 'focus', this.onfocus);
				}
	    	}
		}
		this.showingFrame = false;
	}
    else
    {
    	// Child closing itself by calling to the parent.
    	if (window.parent != window)
    	{
    		window.parent.EmbeddedPopup.popupManager.close();
    	}
    }
}

/*
 * Close the cover pane.
 */
EmbeddedPopup.prototype.closeCover = function ()
{
    if (this.showingFrame && this.divNode != null)
	{
		this.divNode.style.display = "none";
		this.showingFrame = false;
	}
}

/*
 * An onfocus event trap.
 * 
 * While the overlay prevents the user from using the mouse to interact
 * with the main screen while the popup is up, they can still use <TAB>
 * to jump through fields behind the overlay.
 * This event should catch focus change into the main document and
 * move focus out to the popup window.
 * This currently works in firefox, but not IE.
 *
 * @param e
 */
EmbeddedPopup.prototype.onfocus = function (e)
{
    if ((EmbeddedPopup.popupManager.showingFrame) && 
    	(EmbeddedPopup.popupManager.iframeNode != null) && 
    	(EmbeddedPopup.popupManager.bodyNode != null))
	{
    	var elements;
    	if (EmbeddedPopup.popupManager.iframeNode.contentDocument != null)
    	{
    		// DOM/Firefox content document.
    		elements = EmbeddedPopup.popupManager.iframeNode.contentDocument.forms[0].elements;;
    	}
    	else if (EmbeddedPopup.popupManager.iframeNode.contentWindow != null)
    	{
    		// IE content document.
    		if (EmbeddedPopup.popupManager.iframeNode.contentWindow.document.forms.length > 0)
    		{
    			elements = EmbeddedPopup.popupManager.iframeNode.contentWindow.document.forms[0].elements;
    		}
    	}
    	// find a non-hidden input element. Set focus to it.
    	if (elements != null)
    	{
    		for (var idx = 0; idx < elements.length; idx++)
    		{
    			var elm = elements[idx];
    			if (elm.getAttribute("type") != "hidden")
    			{
    				elm.focus();
    				return;
    			}
    		}
    	}
	}
}

 /*
  * Fill a delimited resource string with values.
  * Example:
  * 
  * "This is a {0} string, {1}".fillDelimited("resource", "yay!")
  *   ==>
  * "This is a resource string, yay!"
 * 
 * @return String
  */
 String.prototype.fillDelimited = function()
 {
 	  //copy this string
 	  var ret = this;
 	  
 	  //loop through all arguments
 	  for(var i=0;i<arguments.length;i++)
 	  {
 		  //create a regex to match the next delimiter
 		  var regexString = "\\{"+i+"\\}";
 		  var regex = new RegExp(regexString, "g");

         //if the argument is null, replace with blank string
         var replace = arguments[i]==null ? "" : arguments[i];
 		  
 		  //replace the next delimiter with the next argument
 		  ret = ret.replace(regex, replace);
 	  }

 	  return ret;
}

 /*
  * Defines a trim() function to be used directly from a String object.
 * 
 * @return String
  */
 String.prototype.trim = function() 
 {
     return this.replace( /^\s*/, '').replace( /\s*$/, '' );
 }
  
/*
 * Defines a starts with function for strings.
 * 
 * @return String
 */
 String.prototype.startsWith = function(str)
 {
 	return (this.match("^" + str) == str);
 }

/**
 * Code to execute on page load
 */
// Create the instance of the embedded popup manager object.
EmbeddedPopup.popupManager = new EmbeddedPopup();

