/* This file contains utilities for controlling the look and feel of user screens */

/* Global warning timeout to login value */
var BrowserDetect = {
	init: function () {
		this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
		this.version = this.searchVersion(navigator.userAgent)
		|| this.searchVersion(navigator.appVersion)
		|| "an unknown version";
		this.OS = this.searchString(this.dataOS) || "an unknown OS";
	},
	searchString: function (data) {
		if( data == null || data.length < 0 )
			return null;
		for (var i=0;i<data.length;i++)	{
			var dataString = data[i].string;
			var dataProp = data[i].prop;
			this.versionSearchString = data[i].versionSearch || data[i].identity;
			if (dataString) {
				if (dataString.indexOf(data[i].subString) != -1)
					return data[i].identity;
			}
			else if (dataProp)
				return data[i].identity;
		}
		return null;
	},
	searchVersion: function (dataString) {
		var index = dataString.indexOf(this.versionSearchString);
		if (index == -1) return "unknown";
		return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
	},//ordered by obscure browsers first to better select the correct one
	dataBrowser: [
	{
		string: navigator.userAgent,
		subString: "Chrome",
		identity: "Chrome"
	},
	{
		string: navigator.userAgent,
		subString: "OmniWeb",
		versionSearch: "OmniWeb/",
		identity: "OmniWeb"
	},
	{
		string: navigator.vendor,
		subString: "Apple",
		identity: "Safari",
		versionSearch: "Version"
	},
	{
		prop: window.opera,
		identity: "Opera"
	},
	{
		string: navigator.vendor,
		subString: "iCab",
		identity: "iCab"
	},
	{
		string: navigator.vendor,
		subString: "KDE",
		identity: "Konqueror"
	},
	{
		string: navigator.userAgent,
		subString: "Firefox",
		identity: "Firefox"
	},
	{
		string: navigator.vendor,
		subString: "Camino",
		identity: "Camino"
	},
	{              // for newer Netscapes (6+)
		string: navigator.userAgent,
		subString: "Netscape",
		identity: "Netscape"
	},
	{
		string: navigator.userAgent,
		subString: "MSIE",
		identity: "Explorer",
		versionSearch: "MSIE"
	},
	{
		string: navigator.userAgent,
		subString: "Gecko",
		identity: "Mozilla",
		versionSearch: "rv"
	},
	{              // for older Netscapes (4-)
		string: navigator.userAgent,
		subString: "Mozilla",
		identity: "Netscape",
		versionSearch: "Mozilla"
	}
	],
	dataOS : [
	{
		string: navigator.platform,
		subString: "Win",
		identity: "Windows"
	},
	{
		string: navigator.platform,
		subString: "Mac",
		identity: "Mac"
	},
	{
		string: navigator.userAgent,
		subString: "iPhone",
		identity: "iPhone/iPod"
	},
	{
		string: navigator.platform,
		subString: "Linux",
		identity: "Linux"
	}
	]
};
BrowserDetect.init();
var brsVersion = BrowserDetect.version;
var isIE = BrowserDetect.browser.match(/.*MSIE.*|.*Explorer.*/) != null;

var timeoutWarningSeconds = null;
var timeoutWarningRemaining = null;
var timeoutForSession = null;
var timeoutIntervalId = null;
var timeoutToLoginId = null;
var timeoutDestination = null;
var buttonsActivated = false;

var hideLoader = function() {
	dojo.fadeOut({
		node:"preloader",
		duration:20,
		onEnd: function() {
			dojo.style( "preloader", "display", "none" );
		}
	}).play();
}
/*****************************************/
function startTimeoutWarning() {
  timeoutWarningRemaining = timeoutWarningSeconds;
  timeoutIntervalId = window.setInterval( timeWarning, 1000, "JavaScript" );
  window.focus();
}

function setTimeoutWarningSeconds( seconds ) {
  timeoutWarningSeconds = seconds;
}

function clearWarning( servletUrl ) {
  if( timeoutIntervalId != null )
    window.clearInterval( timeoutIntervalId );
  var element = document.getElementById( "refresh" );
  if( element != null ) {
    element.src = "";
    element.src = servletUrl;
  }
  element = document.getElementById( "timeOutWarningId" );
	if( element != null )
		element.style.display = "none";
  startTimeoutToWarning( (timeoutForSession - ( (timeoutWarningSeconds + 1) * 1000)), timeoutWarningSeconds );
  startTimeoutToDestination( timeoutDestination, timeoutForSession );
}

function startTimeoutToDestination( servletUrl, timeInMs ) {
  timeoutDestination = servletUrl;
  timeoutForSession = timeInMs;
  if( timeoutToLoginId != null )
    window.clearTimeout( timeoutToLoginId );
  timeoutToLoginId = window.setTimeout( "javascript:window.location='" + servletUrl + "'", timeInMs, "JavaScript" );
}

function startTimeoutToWarning( timeInMs, secondsToWarn ) {
  setTimeoutWarningSeconds( secondsToWarn );
  window.setTimeout( startTimeoutWarning, timeInMs, "JavaScript" );
}

function timeWarning() {
	try {
		if( timeoutIntervalId == null )
			return;
		var element = document.getElementById( "timeOutWarningId" );
		if( element == null )
			return;
		element.style.display = "block";
		var sec = " second";
		if( timeoutWarningRemaining > 1 )
			sec += "s";
		element.innerHTML = "Logging out in " + (timeoutWarningRemaining--) + sec + ".<br/><u>Click</u> to Cancel.";
		if( timeoutWarningRemaining < 0 ) {
			window.clearInterval( timeoutIntervalId );
			element.style.display = "none";
		}
	}
	catch( ex ) {
		// ignore the error
	}
}

/***************doNothing*****************/
// JAVASCRIPT FUNCTION -- DOES NOTHING (USED FOR THE HREF IN THE CALENDAR CALL)
function doNothing() {
}
/***************doNothing*****************/

/****************************Alternate Table Row Color***********************/
function alternateRowColor( tableId ) {
	var items = document.getElementById( tableId );
	if( items == null )
		return;
	var rows = items.rows;
	if( rows == null )
		return;
	for( var i = 0, j = 0; i < rows.length; i++ ) {
		if( rows[i].tagName.toLowerCase() == 'th' ) {
			j = 0;
			continue;
		}
		j++;
		if( j % 2 == 0 )
			rows[i].className = 'rowcolor1';
		else
			rows[i].className = 'rowcolor2';
	}
}
/*********************************END****************************************/

/*****************************************/
/* This section manages the toggling for all checkboxes displayed on screen */

// Set All CheckBoxes of a name pattern to the bFlag Value
function ToggleAllByNamePattern( FormObj, list, namePattern, bFlag ) {
  if( FormObj == null )
    return;
  var elements = FormObj.elements;
  var len = elements.length;
  var re = new RegExp( namePattern );
  for( var i = 0; i < len; i++ ) {
    if( elements[i].type == 'checkbox' && elements[i].name.match( re ) != null ) {
      SetCheckBox( elements[i], bFlag );
      if( list != null )
        updateCheckboxValueList( FormObj, list, elements[i] );
    }
  }
}

// Set the CheckBox.checked to the bFlag Value
function SetCheckBox( ObjCheckBox, bFlag ) {
  if( ObjCheckBox == null )
    return;
  if( ObjCheckBox.disabled == true && (ObjCheckBox.checked == true || bFlag) )
    ObjCheckBox.checked = false;
  else if( ObjCheckBox.checked != bFlag )
    ObjCheckBox.checked = bFlag;
}

// Set All CheckBoxes of a given name to the bFlag Value
function ToggleAll( FormObj, list, chkbox, bFlag ) {
  var cbName = chkbox.name;
  if (chkbox.checked)
    checkUncheck(FormObj, cbName, list, true);
  else
    checkUncheck(FormObj, cbName, list, false);
}

function checkUncheck( FormObj, cbName, list, bFlag ) {
  var len = FormObj.elements.length;
  var i=0;
  var ptr;
  for( i=0; i<len; i++) {
    ptr = FormObj.elements[i];
    if( ptr.type == 'checkbox' && ptr.name == cbName ) {
      if( ptr.disabled == true && (ptr.checked == true || bFlag) ) {
        if( ptr.checked == true )
          updateCheckboxValueList(FormObj, list, ptr);
        ptr.checked = false;
      }
      else if( ptr.checked != bFlag ) {
        ptr.checked = bFlag;
        updateCheckboxValueList( FormObj, list, ptr );
      }
    }
  }
}

function updateCheckboxValueList(FormObj, list, checkbox) {
  if( list == null )
    return;
  var selectedValues = list.value;
  var tmpValue = checkbox.value;
  if( tmpValue.length > 0 ) {
    var index = selectedValues.indexOf("<" + tmpValue + ">");
    if (index > -1) {
      var firsthalf = selectedValues.substring(0, index);
      var secondhalf = selectedValues.substring(index + tmpValue.length + 2);
      list.value = firsthalf + secondhalf;
    }
    else {
      list.value += "<" + tmpValue + ">";
    }
  }
}

/* This section manages the swapping of images on mouseover, mouseout, and mousedown events */

var PreLoadedNames = new Array();	// these two are expected to complement each other
var PreLoadedImages = new Array();
// this function will handle any number of arguments - expected to be image pathnames
function PreLoadImages() {
  if( PreLoadImages.arguments == null )
    return;
  var ple = PreLoadedNames.length - 1;	// element idx in the consecutive arrays
  if( ple < 0 )
    ple = 0;
  var cnt = PreLoadImages.arguments.length;
  var args = PreLoadImages.arguments;
  for( var i = cnt; --i > -1; ple++ ) {
    PreLoadedNames[ple] = args[i];
    PreLoadedImages[ple] = new Image();
    PreLoadedImages[ple].src = args[i];
  }
}

function CheckPreLoaded( file ) {
  if( PreLoadedNames != null && PreLoadedNames.length > 0 ) {
    for( var i = PreLoadedNames.length; --i > -1; ) {
      if( PreLoadedNames[i] == file )
        return( PreLoadedImages[i].src );
    }
  }
  return( null );
}

function SwapImage( img, file ) {
  var pl = CheckPreLoaded( file );
  if( pl != null )
    img.src = pl;
  else
    img.src = file;
}

/* Disable and Enable FixedButton objects */

function getButtonsActivated() {
	return buttonsActivated;
}

function setButtonsActivated( bActivated ) {
	buttonsActivated = bActivated;
	var fbt = document.getElementById( "fixedButtonTable" );
	if( fbt == null )
		return;

	if( isIE == true && brsVersion <= 7 ) {
		fbt.className = 'buttontable';
		fbt.style.backgroundColor = 'transparent';
		fbt.deleteRow( 0 );
		return;
	}
	fbt.style.left = 0;
	fbt.style.top = 0;
	Drag.init( fbt, null, 0, (getWidth() - fbt.offsetWidth - 10), 0, (getHeight() - fbt.offsetHeight - 10) );
	fbt.setAttribute( "Show", 'buttontable' );
}

function collapseRestore( tableId ) {
	var fbt = document.getElementById( tableId );
	if( fbt == null )
		return;
	var rows = fbt.rows;
	var oc = fbt.getAttribute( "Show" );
	if( oc == null || oc == 'buttontable' ) {
		oc = 'invisible';
		fbt.style.left = 0;
		fbt.style.top = 0;
	}
	else
		oc = 'buttontable';
	for( var i = 1; i < rows.length; i++ ) {
		if( rows[i].tagName.toLowerCase() == 'th' )
			continue;
		rows[i].className = oc;
	}
	fbt.setAttribute( "Show", oc );
}

var disabledIdList = null;
var disabledImages = null;

function removeFixedButton( strButtonRowId ) {
  if( strButtonRowId != null ) {
    var element = document.getElementById( strButtonRowId );
    if( element != null ) {
      element.className = "invisible";
    }
  }
}

function replaceFixedButton( strButtonRowId ) {
  if( strButtonRowId != null ) {
    var element = document.getElementById( strButtonRowId );
    if( element != null ) {
      element.className = "buttontable";
    }
  }
}

function DisableToolbarButtons( toolBarId ) {
	var tb = dijit.byId( toolBarId );
	if( tb == null )
		return;
	dojo.forEach( tb.getChildren(), function( item ) {
		item.set( 'disabled', false );
	});
}

function EnableToolbarButtons( toolBarId ) {
	var tb = dijit.byId( toolBarId );
	if( tb == null )
		return;
	var c = tb.getChildren();
	dojo.forEach( tb.getChildren(), function( item ) {
		item.set( 'disabled', true );
	});
}

function DisableFixedButtons( idListName, disImageFile ) {
  var idList = document.getElementsByName( idListName );
  if( idList == null )
    return;
  disabledIdList = new Array();
  disabledImages = new Array();
  var disabledIdx = 0;
  for( var j = idList.length; --j > -1; ) {
    var ids = idList[j].value.split( ' ' );
    for( var i = ids.length; --i > -1; ) {
      var element = document.getElementById( ids[i] );
      if( element != null ) {
        if( element.src != null ) {
          disabledImages[disabledIdx] = element.src;
          SwapImage( element, disImageFile );
        }
        element.disabled = true;
        disabledIdList[disabledIdx++] = ids[i];
      }
    }
  }
}

function EnableFixedButtons( idListName, normImageFile ) {
  if( EnableFixedButtons.arguments != null && EnableFixedButtons.arguments.length == 0 ) {
    // this is to re-enable the buttons that were disabled and then submit was cancelled.
    if( disabledIdList == null || disabledImages == null )
      return;
    for( var k = disabledIdList.length; --k > -1; ) {
      var re = document.getElementById( disabledIdList[k] );
      if( re != null ) {
        if( re.src != null )
          SwapImage( re, disabledImages[k] );
        re.disabled = false;
      }
    }
    disabledIdList = null;
    disabledImages = null;
    return;
  }
  var idList = document.getElementsByName( idListName );
  for( var j = idList.length; --j > -1; ) {
    var ids = idList[j].value.split( ' ' );
    for( var i = ids.length; --i > -1; ) {
      var element = document.getElementById( ids[i] );
      if( element != null ) {
        if( element.src != null )
          SwapImage( element, normImageFile );
        element.disabled = false;
      }
    }
  }
}

/**
 * This function will keep the 'fixedbuttons' class positioned
 * when the body is scrolled.
 * PRE-REQUISITE - the onscroll event of the body tag needs
 *		to call this function.  See HtmlFixedButton.java
 */
function moveButtons() {
  var dv = document.getElementsByTagName( "div" );
  if( dv == null )
    return;
  for( var i = 0, l = dv.length; i < l; i++ ) {
    if( dv[i].className == "fixedbuttons" ) {
      var yPos = (document.all) ? document.body.scrollTop : window.pageYOffset;
      dv[i].style.position = "absolute";
      dv[i].style.pixelLeft = 10;
      dv[i].style.pixelTop = (yPos + 10);
      break;
    }
  }
}
/* end of fixed buttons section */

/* this section substitutes options into a given html select object */

/**
 *	Send in the Id of the Select Element along with
 *        a comma separated string of Name=Value pairs.
 * NOTE: this function treats the 3rd, 4th, 5th and 6th argument as optional
 *	The selectedItems argument is a comma separated string -
 *        it will match to either the name or value.
 *      The sortByValue is a boolean that if true will sort by the value
 *        portion of the options array, otherwise the text portion
 *        will be used.  If this is not present no sort will be attempted
 *      The scale argument when present indicates that number formatting
 *        to the given scale is required on the display (Name) portion
 *        of the Name=Value pairs.
 *      The formatFunction is used to format the display (Name) portion
 *        of the Name=Value pairs.
 */
function SetOptions( selectId, options, selectedItems, sortByValue, scale, formatFunction ) {
  if( selectId == null || options == null )
    return;
  var sel = document.getElementById( selectId );
  if( sel == null )
    return;

  var toSelect = null;
  var cnt = 0;
  if( SetOptions.arguments.length > 2 ) {
    toSelect = new String( SetOptions.arguments[2] ).split( "," );
    cnt = toSelect.length;
  }
  var sortBy = null;
  if( SetOptions.arguments.length > 3 )
    sortBy = SetOptions.arguments[3];

  var selectedIdx = -1;
  sel.options.length = 0;	// clear existing options
  sel.selectedIndex = selectedIdx;

  var pairs = options.split( "," );
  if( pairs == null )
    return;

  var len = pairs.length;
  var newOpts = new Array( len );
  var scl = null;

  if( SetOptions.arguments.length > 4 ) {
    var allNumbers = true;
    scl = SetOptions.arguments[4];
    for( var i = 0; i < len; i++ ) {
      var opt = pairs[i].split( "=" );
      if( opt == null || opt.length < 1 || isNumeric( opt[0] ) == false ) {
        allNumbers = false;
        break;
      }
    }
    if( allNumbers == false )
      scl = null;
  }

  for( i = 0; i < len; i++ ) {
    opt = pairs[i].split( "=" );
    if( opt == null || opt.length < 1 )
      continue;
    var oOption = document.createElement( "OPTION" );
    if( scl != null ) {
      if( formatFunction != null )
        oOption.text = formatFunction( opt[0], scl );
      else
        oOption.text = currencyFormatted( opt[0], scl );
    }
    else if( formatFunction != null )
      oOption.text = formatFunction( opt[0] );
    else
      oOption.text = opt[0];
    if( opt.length >= 2 )
      oOption.value = opt[1];
    else
      oOption.value = opt[0];
    newOpts[i] = oOption;
  }

  if( sortBy != null )
    SelectSort( newOpts, 0, newOpts.length - 1, sortBy );

  if( toSelect != null ) {
    for( i = 0; i < len; i++ ) {
      for( var x = 0; x < cnt; x++ ) {
        if( newOpts[i].text == toSelect[x] || newOpts[i].value == toSelect[x] ) {
          newOpts[i].selected = true;
          if( selectedIdx == -1 )
            selectedIdx = i;
          break;
        }
      }
      sel.add( newOpts[i] );
    }
  }
  else {
    for( i = 0; i < len; i++ )
      sel.add( newOpts[i] );
  }

  if( selectedIdx != -1 )
    sel.selectedIndex = selectedIdx;
}

function CompareSelect( v1, v2, byValue ) {
  var sortLo = byValue ? v1.value : v1.text;
  var sortHi = byValue ? v2.value : v2.text;

  if( sortLo > sortHi )
    return( 1 );
  if( sortLo < sortHi )
    return( -1 );
  return( 0 );
}

function SelectSort( vec, loBound, hiBound, byValue )	{

  /**************************************************************
   This function adapted from the algorithm given in:
   Data Abstractions & Structures Using C++, by
   Mark Headington and David Riley, pg. 586.

   Quicksort is the fastest array sorting routine for
   unordered arrays.  Its big O is n log n.
   **************************************************************/
  var pivot, loSwap, hiSwap, temp, sortLo, sortHi;

  if( byValue == null )
    byValue = false;

  // Two items to sort
  if( hiBound - loBound == 1 ) {

    if( CompareSelect( vec[loBound], vec[hiBound], byValue ) > 0 ) {
      temp = vec[loBound];
      vec[loBound] = vec[hiBound];
      vec[hiBound] = temp;
    }
    return;
  }

  // Three or more items to sort
  pivot = vec[parseInt((loBound + hiBound) / 2)];
  vec[parseInt((loBound + hiBound) / 2)] = vec[loBound];
  vec[loBound] = pivot;
  loSwap = loBound + 1;
  hiSwap = hiBound;

  do {
    // Find the right loSwap
    while (loSwap <= hiSwap && CompareSelect( vec[loSwap], pivot, byValue ) <= 0 )
      loSwap++;

    // Find the right hiSwap
    while( CompareSelect( vec[hiSwap], pivot ) > 0 )
      hiSwap--;

    // Swap values if loSwap is less than hiSwap
    if (loSwap < hiSwap) {
      temp = vec[loSwap];
      vec[loSwap] = vec[hiSwap];
      vec[hiSwap] = temp;
    }
  } while (loSwap < hiSwap);

  vec[loBound] = vec[hiSwap];
  vec[hiSwap] = pivot;

  // Recursively call function...  the beauty of quicksort

  // 2 or more items in first section
  if (loBound < hiSwap - 1)
    SelectSort( vec, loBound, hiSwap - 1, byValue );

  // 2 or more items in second section
  if (hiSwap + 1 < hiBound)
    SelectSort( vec, hiSwap + 1, hiBound, byValue );
}

/* this section returns the value stored in a global cookie ( document.cookie ) */

// Retrieve the value of the cookie with the specified name.
function GetCookie( sName ) {
	// cookies are separated by semicolons
	var aCookie = document.cookie.split( "; " );
	for ( var i = 0; i < aCookie.length; i++ ) {
		// a name/value pair (a crumb) is separated by an equal sign
		var aCrumb = aCookie[i].split( "=" );
		if( sName == aCrumb[0] )
			return unescape( aCrumb[1] );
	}
	// a cookie with the requested name does not exist
	return null;
}

function SetCookie( name, value ) {
  var argv = SetCookie.arguments;
  var argc = SetCookie.arguments.length;
  var expires = (argc > 2) ? argv[2] : null;
	if( expires == null ) {
		expires = new Date();
		expires.setMonth( expires.getMonth() + 1 );
	}
  var path = (argc > 3) ? argv[3] : null;
  var domain = (argc > 4) ? argv[4] : null;
  var secure = (argc > 5) ? argv[5] : false;
  document.cookie = name + "=" + escape( value ) +
  ((expires == null) ? "" : ("; expires=" + expires.toUTCString())) +
  ((path == null) ? "" : ("; path=" + path)) +
  ((domain == null) ? "" : ("; domain=" + domain)) +
  ((secure == true) ? "; secure" : "");
}

function DeleteCookie( name ) {
  var exp = new Date();
  exp.setTime( exp.getTime() - 1000000000 );  // This cookie is history
  SetCookie( name, "", exp );
}

/* this section is to facilitate the removing of broadcast messages in SOSServlet */

function SetDeleteMessage( divId, msgId ) {	// the id of the div with the message and the column SchedSentNoteId value
  document.getElementById( divId ).style.display="none";
  var exp = new Date();
  exp.setYear( exp.getFullYear() + 1 );
	var name = "DeleteMessage";
  var c = GetCookie( name );
	var re = new RegExp( "[:].*" + msgId + "[:].*" );
  if( c == null || c.match( re ) != null )
    SetCookie( name, msgId, exp );
  else if( c != msgId )
    SetCookie( name, c + ":" + msgId, exp );
}

/* this section facilitates the hiding or display of the "Active" member info in the Banner frame */

function hidename() {
  var frm = window.parent[0];
  if( frm != null ) {
    var show = frm.document.getElementById( "showname" );
    if( show != null ) {
      show.style.display = "none";
      frm.document.getElementById( "hidename" ).style.display="block";
    }
  }
}

function showname() {
  var frm = window.parent[0];
  if( frm != null ) {
    var show = frm.document.getElementById( "showname" );
    if( show != null ) {
      show.style.display = "block";
      frm.document.getElementById( "hidename" ).style.display="none";
    }
  }
}

/* Change the Account Number Banner Text at the top of the page */
function changename( replacementDiv ) {
	var frm = window.parent[0];
	if( frm != null ) {
		var show = frm.document.getElementById( "showname" );
		if( show != null ) {
			show.innerHTML = replacementDiv;
		}
	}
}

/**
 * Show or Hide an element by id
 */
function showOrHide( frameNum, id, hide ) {
	var frm = window.parent[frameNum];
	if( frm != null ) {
		var element = frm.document.getElementById( id );
		if( element == null )
			return;
		if( hide == true )
			element.style.display = "none";
		else
			element.style.display = "block";
	}
}

/* Section assists in controlling the contents of popup help text */
function ShowTip( event, tipObj, text ) {
  if( event == null || tipObj == null || text == null || ShowTip.arguments.length < 3 )
    return;

  var TipVar = document.getElementById( tipObj );//tip was passed in as a string

  if( TipVar == null )
    TipVar = tipObj;	//tip was passed in as an object
  var width = 200;
  if( text.length > 400 )
    width = 250;
  if( text.length > 800 )
    width = 300;
	if( ShowTip.arguments.length > 3 )
		width = ShowTip.arguments[3];
  domTT_activate( TipVar, event, 'content', text, 'type', 'greasy', 'trail', true,
		'fade', 'out', 'direction', 'southwest', 'width', width, 'styleClass', 'domTTClassic' );
}

// find the object on the document - then attempt to focus on it
// strName - name of the object to find
function focusOnName( strName ) {
  if( strName == null )
    return;
  var objs = document.getElementsByName( strName );
  if( objs == null || objs.length > 1 )
    return;
  focusOnObject( objs[0] );
}

// Focus on checked RadioButton or CheckBox in a group or on any non-group object
function focusOnObject( obj ) {
  if( obj == null )
    return;
  if( window.focus != null )
    window.focus();
  if( obj.length == null ) {
    if( obj.focus != null ) {
      var theForm = obj.getAttribute( "form" );
      if( theForm != null && theForm.focus != null )
        theForm.focus();
      if( obj.type != null && obj.type != 'hidden' && obj.disabled != null && obj.disabled == false )
        obj.focus();
    }
  }
  else {
    var len = obj.length;
    if( obj.focus != null ) {
      if( obj.type != null && obj.type != 'hidden' && obj.disabled != null && obj.disabled == false )
        obj.focus();
    }
    for( var i = 0; i < len; i++ ) {
      theForm = obj[i].getAttribute( "form" );
      if( theForm != null && theForm.focus != null )
        theForm.focus();
      var type = new String( obj[i].type ).toLowerCase();
      if( type == 'hidden' )
        continue;
      if( type.match( "^checkbox|radio" ) ) {
        if( obj[i].checked != null && obj[i].checked == true &&
							obj[i].focus != null && obj[i].disabled != null && obj[i].disabled == false ) {
          obj[i].focus();
          break;
        }
      }
      else if( obj[i].focus != null && obj[i].disabled != null && obj[i].disabled == false ) {
        obj[i].focus();
        break;
      }
    }
  }
}

// This function takes a form object and checks to see if any of its element values have been modified since the page loaded.
// return false if all current values match those of the defaults, otherwise true
function formModified( formRef ) {
  for(var i = 0, j = formRef.elements.length; i < j; i++) {
    var myType = formRef.elements[i].type;
    if( myType == 'checkbox' || myType == 'radio' ) {
      if( formRef.elements[i].checked != formRef.elements[i].defaultChecked ) {
        return true;
      }
    }
    else if( myType == 'text' || myType == 'textarea' ) {
      if( formRef.elements[i].value != formRef.elements[i].defaultValue ) {
        return true;
      }
    }
    else if(myType == 'select-one' || myType == 'select-multiple') {
      for (var k = 0, l = formRef.elements[i].options.length; k < l; k++) {
        if( formRef.elements[i].options[k].selected != formRef.elements[i].options[k].defaultSelected ) {
          return true;
        }
      }
    }
    else
      continue;
  }
  return false;
}

/* this section allows for sorting of tables */

var sortBy = [ [-1], ['ASC'] ];	// this will toggle first to Ascending

function DrawTable( tableName ) {
  var j, newTable = "";
  var TableItems = eval( tableName + "TableItems" );

  for( j in TableItems ) {
    var count = 2;
    if( j%2 )
      count = 1;
    TableItems[j] = TableItems[j].replace( /rowcolor[12]/, "rowcolor" + count );
    newTable += TableItems[j];
  }

  document.getElementById(tableName).innerHTML = newTable;

  //if it does not exist, exit
  if( eval( "typeof "+tableName+"docImages"+" == 'undefined'" ) )
    return;

  var docImages = eval( tableName + "docImages" );
  if( docImages == null )
    return;

  var thisImg;
  for( var thisPic in docImages ) {
    thisImg = document.getElementById(docImages[thisPic]);
    thisImg.src = sortImgArray[2].src;
  }

  thisImg = document.getElementById( docImages[sortBy[0]] );
  if( thisImg == null )
    return;
  var whichPic = (sortBy[1] == 'ASC') ? 0 : 1 ;
  thisImg.src = sortImgArray[whichPic].src;
}

function SortTable( tableName, column, tableId ) {
  //Figure out if we'll be doing ascending or descending
  if( sortBy[0] == column )	{
    if( sortBy[1] == 'ASC' )
      sortBy[1] = 'DES';
    else
      sortBy[1] = 'ASC';
  }
  else {
    sortBy[0] = column;
    sortBy[1] = 'ASC';
  }

  var TableItems = eval( tableName + "TableItems" );
  //leave the first and last row alone!!
  if( TableItems.length > 3 )
    Quicksort( TableItems, 1, TableItems.length - 2, column );

  DrawTable( tableName );

	if( SortTable.arguments.length > 2 )
		alternateRowColor( tableId );
}

function Quicksort( vec, loBound, hiBound, column ) {

  var pivot, loSwap, hiSwap, temp;

  // Two items to sort
  if (hiBound - loBound == 1)	{
    if ( TableItemIsGreaterThan( vec[loBound], vec[hiBound], column ) )	{
      temp = vec[loBound];
      vec[loBound] = vec[hiBound];
      vec[hiBound] = temp;
    }
    return;
  }

  // Three or more items to sort
  pivot = vec[parseInt((loBound + hiBound) / 2)];
  vec[parseInt((loBound + hiBound) / 2)] = vec[loBound];
  vec[loBound] = pivot;
  loSwap = loBound + 1;
  hiSwap = hiBound;

  do {
    // Find the right loSwap
    while (loSwap <= hiSwap && !(TableItemIsGreaterThan( vec[loSwap], pivot, column )) )
      loSwap++;

    // Find the right hiSwap
    while ( TableItemIsGreaterThan( vec[hiSwap], pivot, column ) )
      hiSwap--;

    // Swap values if loSwap is less than hiSwap
    if (loSwap < hiSwap) {
      temp = vec[loSwap];
      vec[loSwap] = vec[hiSwap];
      vec[hiSwap] = temp;
    }
  } while (loSwap < hiSwap);

  vec[loBound] = vec[hiSwap];
  vec[hiSwap] = pivot;

  // Recursively call function...  the beauty of quicksort

  // 2 or more items in first section
  if (loBound < hiSwap - 1)
    Quicksort(vec, loBound, hiSwap - 1, column);


  // 2 or more items in second section
  if (hiSwap + 1 < hiBound)
    Quicksort(vec, hiSwap + 1, hiBound, column);
}

/* globals for Client Table sort function */
var reIsDate = new RegExp( "^([\\d]{2})\\/([\\d]{2})\\/([\\d]{4})(.*)" );	// is the data a date - MM/DD/YYYY
var reIsNumber = new RegExp( "^[\\-\\d\\.,\\$]+$" );	// is the data a number or amount
var reIsTaxId = new RegExp( "^(([\\d]{3})\\-([\\d]{2})\\-([\\d]{4}))|(([\\d]{2})\\-([\\d]{7}))$" );
var reInput = new RegExp( "<+input[\\S\\s]*?>+", "gi" );	// find input tags to replace with &nbsp;
var reTags = new RegExp( "<+[\\S\\s]*?>+", "gi" );	// find html tags - to replace with '*'
var reNoComma = new RegExp( "[,\\$]", "g" );	// remove comma or Dollar Sign
var reNoDash = new RegExp( "[-]", "g" );	// remove the '-' characters
/* globals for Client Table sort function */

function TableItemIsGreaterThan( item_a, item_b, column ) {
  item_a = item_a.replace( reInput, "&nbsp;" );	// allow input to look like data to make column #'s correct
  item_b = item_b.replace( reInput, "&nbsp;" );	// although it wouldn't work to sort it
  item_a = item_a.replace( reTags, "*" );
  item_b = item_b.replace( reTags, "*" );

  //Split using a regex doesn't have consistant results across browsers (ie drops blank elements)
  var a = item_a.split( "*" );
  var b = item_b.split( "*" );

  //ignore blank columns in the array (this seems odd, but it's exactly what ie was doing)
  var len = a.length;
  var nonBlankIndex = 0;
  for( var i = 0; i < len; i++ ) {
    if( a[i] != "" ){
      a[nonBlankIndex] = a[i];
      b[nonBlankIndex] = b[i];
      nonBlankIndex++;
    }
  }

  var colA = a[column].toLowerCase();
  var colB = b[column].toLowerCase();

  // test for SSN - TaxId first it will also look like a number
  if( reIsTaxId.test( colA ) && reIsTaxId.test( colB ) ) {
    //if they look like SSN or TaxId then make them int
    colA = parseInt( colA.replace( reNoDash, "" ) );
    colB = parseInt( colB.replace( reNoDash, "" ) );
  }
  else if( reIsNumber.test( colA ) && reIsNumber.test( colB ) ) {
    //If they look like numbers, sort like numbers!!
    colA = parseFloat( colA.replace( reNoComma, "" ) );
    colB = parseFloat( colB.replace( reNoComma, "" ) );
  }
  else if( reIsDate.test( colA ) && reIsDate.test( colB ) )	{
    //If they look like dates, sort like dates!! - put the year first
    var match = reIsDate.exec( colA );
    colA = match[3] + "/" + match[1] + "/" + match[2] + " " + match[4];

    match = reIsDate.exec( colB );
    colB = match[3] + "/" + match[1] + "/" + match[2] + " " + match[4];
  }

  if( (colA > colB && sortBy[1] == 'ASC') || (colA < colB && sortBy[1] == 'DES') )
    return( true );
  else
    return( false );
}

/* end sorting tables section */

/* externally load via innerHTML - Activate the APPLET */
function loadObject( divID, html ) {
  var div = document.getElementById( divID );
  if( div == null )
    return;
  div.innerHTML = html;
}

/**
 * load and activate the File Upload applet
 * divID - id of div tag for applet rendering
 * visible - true or false string - true to indicate user interaction
 * destFolder - root folder on server as destination for files
 * destFunction - javascript callback function for success indication
 * SOSSessionID - session number
 * source - filePath to be uploaded or string to be saved when command is AdobeConfig
 * deleteOnSuccess - true or false or AdobeConfig
 * command - set to AdobeConfig to send source as contents of AdobeConfigJs
 * Note: source, deleteOnSuccess and command are optional arguments
 * */
function loadUploadObject( divID, visible, destFolder, destFunction, SOSSessionID, source, deleteOnSuccess, command ) {
	var re = new RegExp( "\\\\", "g" );
	destFolder = destFolder.replace( re, "/" );
	var html = '<applet codebase="/" MAYSCRIPT ' +
		'code="com.sos.applet.FileUpload.class" ' +
		'archive="FileUpload.jar,WinRegistry-3.4.jar" ' +
		'height="1" width="1" name="FileUpload"> ' +
		'<param name="Visible" value="' + visible +
		'"> <param name="Destination" value="' + destFolder +
		'"> <param name="JSFunction" value="' + destFunction +
		'"> <param name="SOSSessionID" value="' + SOSSessionID + '"> ';
	if( loadUploadObject.arguments.length > 5 ) {
		source = source.replace( re, "/" );
		html += '<param name="Source" value="' + source + '"> ';
	}
	if( loadUploadObject.arguments.length > 6 )
		html += '<param name="DeleteOnSuccess" value="' + deleteOnSuccess + '"> ';
	if( loadUploadObject.arguments.length > 7 )
		html += '<param name="Command" value="' + command + '"> '
	html += ' </applet>';
	loadObject( divID, html );
}

/* save and reposition the scroll bar */

/**
 * Restore the Scroll Bar Coordinates
 * xOffset value to scroll to
 * yOffset value to scroll to
 */
function scrollToCoordinates( xOffset, yOffset ) {
  window.scrollTo( xOffset, yOffset );
}

/**
 * Save the Scroll Bar Coordinates
 * xObject is hidden object to save the xOffset value to
 * yObject is the hidden object to save the yOffset value to
 */
function saveScrollCoordinates( xObject, yObject ) {
  xObject.value = getXScrollOffset();
  yObject.value = getYScrollOffset();
}

/**
 * Get the X Scroll Offset Value from the document
 */
function getXScrollOffset() {
	var iebody = (document.compatMode && document.compatMode != "BackCompat") ? document.documentElement : document.body;
	return document.all ? iebody.scrollLeft : pageXOffset;
}

/**
 * Get the Y Scroll Offset Value from the document
 */
function getYScrollOffset() {
	var iebody = (document.compatMode && document.compatMode != "BackCompat") ? document.documentElement : document.body;
	return document.all? iebody.scrollTop : pageYOffset;
}

/**
 * Browser independant access to window width
 */
function getWidth() {
	var x = 0;
	if( self.innerWidth )
		x = self.innerWidth;
	else if( document.documentElement && document.documentElement.clientHeight )
		x = document.documentElement.clientWidth;
	else if( document.body )
		x = document.body.clientWidth;
	return x;
}

/**
 * Browser independant access to window height
 */
function getHeight() {
	var y = 0;
	if( self.innerHeight )
		y = self.innerHeight;
	else if( document.documentElement && document.documentElement.clientHeight )
		y = document.documentElement.clientHeight;
	else if( document.body )
		y = document.body.clientHeight;
	return y;
}

/* end of save and reposition the scroll bar */

/* Format numbers */

//Function strToCurr()
//Author: Greg Burgess
//Purpose: This function takes one parameter (a string representing a currency amount) which it validates
//formats and returns.
//Takes an optional 2nd argument to specify scale - defaults to 2
//Example strToCurr("12.5")   --> 12.50
//	  strToCurr("12")      --> 12.00
//	  strToCurr("12.59") --> 12.60

function strToCurr( newValue ) {
  var errorCode = false;
  var scale = 2;

  if( strToCurr.arguments.length > 1 )
    scale = strToCurr.arguments[1];

  dolAmount = parseFloat( newValue );
  if( isNaN( dolAmount ) )
    errorCode = true;

  if( errorCode == true ) {
    alert( 'Please enter a valid amount.' );
    if( window.event != null )
      window.event.returnValue = false;
    return( appendZeroToPrecision( 0, scale ) );
  }

  var div = Math.pow( 10, scale );
  var dolAmount = Math.round( dolAmount * div );

  return( currencyFormatted( (dolAmount / div), scale ) );
}

// Format a number to currency format with optional scale (default is 2)
function currencyFormatted( amount ) {
  var scale = 2;
  if( currencyFormatted.arguments.length > 1 )
    scale = currencyFormatted.arguments[1];
  var i = parseFloat( amount );
  if( isNaN( i ) ) {
    i = 0.00;
  }
  i = Math.abs(i);
  var round = appendZeroToPrecision( 0, scale ) + 5;
  var mult = "1";
  for( i = 0; i < scale; mult += "0", i++ );
  mult = 1 + appendZeroToPrecision( 0, scale );
  i = parseInt( (i + round) * 100 );
  i = i / mult;
  var s = new String( i );
  if( s.indexOf( '.' ) < 0 )
    s += '.';
  s = appendZeroToPrecision( amount, scale );

  return( s );
} // function currencyFormatted()

// Format a number to contain commas and be padded to the given scale
function commaFormatted( amount, scale ) {
  var delimiter = ",";
  amount = new String( amount );
  if( amount.indexOf( delimiter ) >= 0 )
    amount = removeCommas( amount );

  var idx = amount.indexOf( '.' );
  if( scale > 0 ) {
    if( idx == 0 )
      amount = "0" + amount;
    if( idx < 0 )
      amount += ".0";
  }
  var amt = parseFloat( amount );
  if( isNaN( amt ) )
    return( appendZeroToPrecision( 0, scale ) );

	amount = new String( amt );
  var minus = '';
  if( amt < 0 )
    minus = '-';

  var a = amount.split( '.', 2 );
  var d = a[1];
  var i = parseInt( a[0] );

  i = Math.abs( i );
  var n = new String( i );
  a = [];
  while( n.length > 3 )	{
    var nn = n.substr( n.length - 3 );
    a.unshift( nn );
    n = n.substr( 0, n.length - 3 );
  }
  if( n.length > 0 )
    a.unshift( n );

  n = a.join( delimiter );
  if(d && d.length && d.length < 1 || ("" + d) == 'undefined' )
    amount = n;
  else
    amount = n + '.' + d;

  if( scale > 0 )
    amount = appendZeroToPrecision( amount, scale );

  return( minus + amount );
} // function commaFormatted()


function appendZeroToPrecision( amount, scale ) {
  amount = new String( amount );
  if( scale > 0 ) {
    var idx = amount.indexOf( '.' );
    if( idx < 0 )
      amount += ".0";
    for( var i = amount.length - amount.indexOf( '.' ) - 1; i < scale; amount += '0', i++ );
  }
  return( amount );
}

function removeCommas( amount ) {
  amount = new String( amount );
  var a = amount.split( ',' );
  var len = a.length;
  if( len <= 0 )
    return( amount );
  var newAmount = "";
  for( var i = 0; i < len; i++ ) {
    newAmount += a[i];
  }
  return( newAmount );
}

function sumValues( list, cnt ) {  			// this will assume a scale of 2, but will accept an optional scale argument
  var totVal = 0;
  var scale = 2;
  if( sumValues.arguments.length > 2 )
    scale = sumValues.arguments[2];

  var mult = Math.pow( 10, scale );
  for( var x = 0; x < cnt; x++ )
    totVal += Math.round( (list[x] * mult) );
  return( strToCurr( ("" + (totVal / mult)), scale ) );
}

function sumFieldValues( fields, cnt ) {		// this will assume a scale of 2, but will accept an optional scale argument
  var scale = 2;
  if( sumFieldValues.arguments.length > 2 )
    scale = sumFieldValues.arguments[2];

  var values = new Array( cnt );
  for( var x = 0; x < cnt; x++ )
    values[x] = removeCommas( fields[x].value );
  return( sumValues( values, cnt, scale ) );
}

function isNumeric( strValue ) {
  var re = new RegExp( "^-{0,1}[0-9]+$|^-{0,1}[0-9]+\\.[0-9]*$|^-{0,1}[0-9]*\\.[0-9]+$" );
  strValue = removeCommas( strValue );
  return( re.test( strValue ) );
}
/* END Format numbers */
/* String functions extension */
String.prototype.trim = function() {
  return this.replace( /^\s+|\s+$/g, '' );
}

String.prototype.leftTrim = function() {
  return this.replace( /^\s+/g, '' );
}

String.prototype.rightTrim = function() {
  return this.replace( /\s+$/g, '' );
}
/* end of String functions */

/**
 * X-browser event handler attachment and detachment
 *
 * @argument obj - the object to attach event to
 * @argument evType - name of the event - DONT ADD "on", pass only "mouseover", etc
 * @argument fn - function to call
 * @argument useCapture - the event handler should be executed in the capturing or in the bubbling phase.
 * If you’re not certain whether you want capturing or bubbling, use false (bubbling).
 */
function addEvent( obj, evType, fn, useCapture ) {
  if( obj.addEventListener ) {
    obj.addEventListener( evType, fn, useCapture == null ? false : useCapture );
    return true;
  }
	else if( obj.attachEvent ) {
    var r = obj.attachEvent( "on" + evType, fn );
    return r;
  }
	else
    return false;
}

function removeEvent( obj, evType, fn, useCapture ) {
  if( obj.removeEventListener ) {
    obj.removeEventListener( evType, fn, useCapture == null ? false : useCapture );
    return true;
  }
	else if( obj.detachEvent ) {
    var r = obj.detachEvent( "on" + evType, fn );
    return r;
  }
	else {
    alert( "Handler could not be removed" );
    return false;
  }
}

function fireOnClickEvent( objId ) {
	var target = document.getElementById( objId );
	if( document.dispatchEvent ) { // W3C
		var oEvent = document.createEvent( "MouseEvents" );
		oEvent.initMouseEvent( "click", true, true, window, 1, 1, 1, 1, 1, false, false, false, false, 0, target );
		target.dispatchEvent( oEvent );
	}
	else if( document.fireEvent ) { // IE
		target.fireEvent( "onclick" );
	}
}


