/************************************************************************

	Copyright (C) 2007 Olympia Computing Company. All Rights Reserved. 
	http://www.schoolmaster.com/

	WARNING: This software program is protected by copyright law 
	and international treaties. Unauthorized modification, reproduction or
	distribution of this program, or any portion of it, may result
	in severe civil and criminal penalties, and will be prosecuted
	to the maximum extent possible under the law.

*************************************************************************/


// this is the int navigation position id of the
// page which is currently being displayed

var currentPgID = -1;
var pageObj = null;

// the progress indicator will check this
// if the request has not been copmleted yet,
// the user will be shown a "still thinking"
// progress indicator; when the response comes
// back, this will be reset to true
var requestCompleted = true;
var progressIndicator = null;

// when btns or icons are added, they will
// be added to these arrays, so that when it is
// time to clear the btns or icons, the js
// will know which elems to remove
var iconsToClear = new Array();
var buttonsToClear = new Array();

// this will hold a list of js nodes which
// were added by a page navigation and which will
// therefore be removed when a new page is loaded
var nodesAdded = new Array();

// popup-divs may have their own js nodes
// these will need to be cleared out when the
// popup-div is closed so they don't accumulate
// simply adding them to the nodesAdded above
// isn't enough because >1 popup can be shown
// before the user actually navigates away, and we
// don't want the js from each popup interfering with
// with the others
var jsNodeForPopup = null;
// if popup windows want to use this code to
// post forms by calling opener.postFormFromPopup
// this var will get set to point to the
// form they want posted by the postFormFromPopup function
var formToPostFromPopup = null;

//This variable is used by the change monitor code.
//It tracks the state of the data on a page.
var hasChanged = false;
//This variable tracks the function that will be used to save changes when
//the user chooses the save and continue option from the Lose Data warning.
var saveFunction = "";
//This variable tracks which function will be called to appropriately continue
//the navigation after a save or discard of the data.
var callBackFunction = "";
//This variable is optional and tracks the function that is used to reset the data on 
//a page when a navigation is cancelled. This is primarily used to reset drop down menus.
var cancelFunction = null;
// hold onto the record navigator's search img - IE needs to replace this everytime
var recNavSearchImg = null;

// this js object represents a dhtml node
// which was added to this document at some
// point as a response to a navigation request
// (either a js reference, js text, or a css
//  reference) - this object contains a reference
// to the xml node and to the name of the div
// which was updated during the navigation event
function DynamicNode(xmlNode, divUpdated) {
	this.node = xmlNode;
	this.divName = divUpdated;		
}

function addDynamicNode(xmlNode, divUpdated) {
	var newNode = new DynamicNode(xmlNode, divUpdated);
	nodesAdded.push(newNode);
}

// removes all of the dynamic nodes
// which had been added due to navigation
// to any div on the page
function removeAllNodes() {
	var headElem = document.getElementById("head");
	var numOfNodes = nodesAdded.length;
	
	for (var n=0; n<numOfNodes; n++) {
		try {
			headElem.removeChild(nodesAdded[n].node);
			// help garbage collector by setting these to null
			nodesAdded[n].node = null;
			nodesAdded[n] = null;
		} catch (ex) {
			// ignore this
		}	
	}
	nodesAdded = new Array(); // clean it out
}

// removes all of the dynamic nodes
// where were added as a result of navigating
// to the div whose name is passed in as a parameter
function removeAllNodesForDiv(divName) {
	var headElem = document.getElementById("head");
	var nodesForDiv = getAllNodesForDiv(divName);
	var numOfNodes = nodesForDiv.length;
	for (var n=0; n<numOfNodes; n++) {
		try {
			headElem.removeChild(nodesForDiv[n].node);	
		} catch (ex) {
			// ok to ignore this
		}
	}
}

// returns a js array of all of the dynamic
// nodes which were added as a result of navigating
// to the div whose name is passed in as a parameter
function getAllNodesForDiv(divName) {
	var nodesForDiv = new Array();
	
	var numOfNodes = nodesAdded.length;
	for (var n=0; n<numOfNodes; n++) {
		if (nodesAdded[n].divName == divName) {
			nodesForDiv.push(nodesAdded[n]);
		}
	}
	
	return nodesForDiv;
}

// this function reloads the entire <html> pg, not just a single <div>
// it is called mainly to refresh the menus for those few times when the user
// does something, like add their first gb, which requires the menus to get reloaded
// the url passed in as a param should be in this format:
// http://localhost/smweb/SchoolmasterWeb.aspx?1d=13#navpos|13
// where the "13" in the example is the nav pos id
function reloadWholePg(url) {
    window.location = url;
}

//This function tracks changes made to the current view.
//When a change is made this function is called.
function changeMade() {
	hasChanged = true;
}


function keyPressed() {
    try {
	    if (browserIsIE()) {
            if (saveFunction != null && 
                    event.keyCode == 19 &&
			        window.event.ctrlKey &&
			        window.event.shiftKey) {
		        setTimeout('eval(saveFunction + "()");',0);
		        closePopup();
                return false;
	        }
        }
    }
    catch (ex) {
        // do nothing
    }
	
}

//This function installs the change monitor on a given view.
//It iterates through all the forms and attaches the changeMade() method
//to each element onchange event.
//The only exception is when either the form or the element has the 
//skipChange attribute. In this case, no change is made to the onchange event
//of the form/element. 
function installChangeMonitor(saveFunctionName)
{
	//save the saveFunction for the current view
	saveFunction = saveFunctionName;
	if (browswerIsFF()) {
	    window.onkeypress = function (e) {
	        var ctrlDown = e.ctrlKey;
	        var shiftDown = e.shiftKey;
	        var sDown = e.which == 83;

	        if (shiftDown  == true && ctrlDown == true && sDown == true) {
	            closePopup();
	            setTimeout('eval(saveFunction + "()");',0);
	            return false;
	        }
	    }
	}
	//Step through each form
	var formArray = document.forms;
	for(var i = 0; i < formArray.length; i++)
	{
		//Verify that the current form should be changed.
		if(!(formArray[i].getAttribute("skipChange")))
		{
			//Step through each element in the current form.
			var elementArray = formArray[i].elements;
	
			for(var j = 0; j < elementArray.length; j++)
			{
				//Verify that the current element should be changed.
				if(!(elementArray[j].getAttribute("skipChange")))
				{
					//If the current element has an onchange and the onchange doesn't already 
					//include the changeMade() function, preceed the original onchange event with a
					//call to changeMade(). If the onchange event already includes changeMade(), this
					//indicates that this element has been visited.
					if(	elementArray[j].onchange && !elementArray[j].onchange.toString().indexOf("changeMade") > -1)
					{
						elementArray[j].onchange = new Function("javascript: changeMade(); var origOnChange = " + elementArray[j].onchange + "; origOnChange(); return true;");
					}
					else
					{
						//Otherwise, set the onchange funcion equal to the changeMade function.
						elementArray[j].onchange = changeMade;
			
					}
					
				}
			}
		}
		
	
		
	}
}

//This function checks to see if changes have been made, and prompts the user accordingly.
function checkChanges(callbackFunc, cancelFunc)
{
	//If change haven't been made the callback function is called and nothing is done.
	if(!hasChanged)
	{
		eval(callbackFunc);
	}
	else
	{
		//If a change has been made, the callback and cancel functions are saved.
		callBackFunction = callbackFunc;
		cancelFunction = cancelFunc;
		//Then pop-up a window to warn the user that data will be lost
		//popUpPrompt("LoseChangeWarning.aspx", "LoseChangeWarning", 125,400);	
		
		var elem = document.getElementById("changeMonitorDiv");
		elem.style.visibility = "visible";	
		elem.style.display = "inline";	
	}
}


// this function will get called when a navigation
// position should show up within a pop-up window
// rather than in the main content area of this page
function popUp(queryString, titleStr, height, width) 
{
    popUpPrompt("NavController.aspx?" + queryString, titleStr, height, width);
}

// if allowPgEditing is true, this will be a non-modal dialog, allowing
// the user to edit the pg showing below the popup
function popUpPrompt(url, windowName, height, width, allowPgEditing)
{
    var popupContentElem = document.getElementById("popupContentDiv");
    popupContentElem.style.height = height;
    popupContentElem.style.width = width;
    
    height = height+30; // adding 30 to account for popup footer height 
    var bodyHeight = document.getElementById('aboveFooter').offsetHeight;
	var bodyWidth = document.getElementById('aboveFooter').offsetWidth;
	
	var left = (bodyWidth/2) - (width/2);
	var top = (bodyHeight/2)- (height/2);

    var popupElem = document.getElementById("popupDiv");
    popupElem.style.left = left;
    popupElem.style.top = top;
   // popupElem.style.height = height;
    popupElem.style.width = width;
    
    var popupContentElem = document.getElementById("popupContentDiv");
    popupContentElem.style.height = height;
    
    var footerElem = document.getElementById("popupFooterDiv");
    footerElem.innerHTML = ""; // clear this out
    popupContentElem.innerHTML = ""; // clear this out
    
    
    // need to add a random value so that IE won't return a cached
    // version of the .aspx pg with stale data in it
    var containsQueryStr = false;
    var indexOfQ = url.indexOf("?");
    if (indexOfQ > 0) {
        containsQueryStr = true;
    }
     if (containsQueryStr == true) {
        url = url + "&foo=" + Math.random();
    } else {
        url = url + "?foo=" + Math.random();
    }
    
    // for some reason, this needs to be a get, not a post:
    if (!allowPgEditing) {
        httpRequest("get",url,true,modalPopupResponseHandler);
    }
    else {
        httpRequest("get",url,true,nonModalPopupResponseHandler);
    }
}

function popUpPrintView(url, windowName)
{
    var bodyHeight = document.getElementById('aboveFooter').offsetHeight;
	var bodyWidth = document.getElementById('aboveFooter').offsetWidth;
	
	var left = (bodyWidth/2) - (800/2);
	var top = (bodyHeight/2) - (600/2) + 50;
	
	return window.open(url, windowName,
	"toolbar=no, location=no, directories=no, status=no, " + //
	"menubar=no, scrollbars=yes, resizable=yes, width = 800, " + //
	"height=600, left=" + left + " , top=" + top);	
}

function modalPopupResponseHandler(resp) {
    if(request.readyState == 4){
		if (request.status == 200) {
			var resp =  request.responseText;
			popupResponse(resp, true);
		}
		else {
		    alert("A problem occurred with communicating between the XMLHttpRequest object and the server program. " + request.status);
	    }
	}
}

function nonModalPopupResponseHandler(resp) {
    if(request.readyState == 4){
		if (request.status == 200) {
		    var resp =  request.responseText;
		    popupResponse(resp, false);
		}
		else {
		    alert("A problem occurred with communicating between the XMLHttpRequest object and the server program. " + request.status);
	    }
	}
}
function popupResponse(resp, isModal) {
	var resp =  request.responseText;

    //first, clear out any other popup's on-load function
    this.onPopupLoad = null;
    
    // append the js text to the existing script tag
    // addJSText makes sure this will get cleaned up/removed
    // when the user navigates away from this navposition
    var scriptText = getScriptText(resp);
    removeOldJSNode(); // clear out any js from the last popup
    var jsNode = addJSText(scriptText, "content");
    jsNodeForPopup = jsNode;
	
	// get txt of the btns before removing the btn from the content area
	var btnsText = getPopupBtnsText(resp);
	
	var popupElem = document.getElementById("popupDiv");
	popupElem.style.visibility = "visible";
	//opacity("popupDiv", 0, 100, 1000);

    if (isModal) {
        var bkgrndElem = document.getElementById("popupBkgndDiv");
        bkgrndElem.style.visibility = "visible";
        opacity("popupBkgndDiv", 0, 50, 1000);
        makeUnDraggable(document.getElementById('popupDiv'));
    } 
    
    else {
        // make the popup-div drag and drop-able
        var scrollDiv = document.getElementById("aboveFooter");
        initDragDrop(scrollDiv, 5, 5, 1200, 1200);
        makeDraggable(document.getElementById('popupDiv'));
    }

    var contentElem = document.getElementById("popupContentDiv");
    var displayMe = getBodyText(resp);
    displayMe = trim(displayMe);
    		
    // take btns out of the text that goes into the content area
    displayMe = displayMe.replace(btnsText, ""); 
    contentElem.innerHTML = displayMe;
    
    // now setup the buttons in the footer area
    var footerElem = document.getElementById("popupFooterDiv");
    if (btnsText) {
        footerElem.innerHTML = "<center>" + btnsText + "</center>";
    }
    
    try {
        if (onPopupLoad) {
            setTimeout('onPopupLoad()', 400);
        }
    } catch (ex) {
        // it's ok if there is no onPopupLoad defined
    }
        
		
} // end of function popupResponseHandler

function removeOldJSNode() {
    try {
	    var headElem = document.getElementById("head");
	    if (headElem != null && jsNodeForPopup != null) {
	        headElem.removeChild(jsNodeForPopup);	
	        jsNodeForPopup = null; // clear out for garbage collector
	    }
	} catch (ex) {
	    // ignore this
	}
}

// returns just the text between the open and close <body> html tags
function getBodyText(htmlStr) {
    var theBodyText = "";
    var lowerHtmlStr = htmlStr.toLowerCase();
    var startIndex = lowerHtmlStr.indexOf("<body");
    if (startIndex > -1) {
        // find the first > after startIndex
        startIndex = lowerHtmlStr.indexOf(">", startIndex);
        if (startIndex > -1) {
            startIndex += 2; // we want to start after that tag
            var endIndex = htmlStr.indexOf("</body>");
            if (endIndex > startIndex) {
                theBodyText = htmlStr.substring(startIndex, endIndex);
            }
        }
    } 
    return theBodyText;
}

// returns just the text between the open and close <script> html tags
function getScriptText(htmlStr) {
    var theScriptText = "";
    var lowerHtmlStr = htmlStr.toLowerCase();
    var startIndex = lowerHtmlStr.indexOf("<script>");
    if (startIndex > -1) {
        // find the first > after startIndex
        if (startIndex > -1) {
            startIndex += 8; // we want to start after that tag
            var endIndex = htmlStr.indexOf("</script>", startIndex);
            if (endIndex > startIndex) {
                theScriptText = htmlStr.substring(startIndex, endIndex);
            }
        }
    } 
    return theScriptText;
}

// returns just the text between the open div tag with the id of "popupBtns" and the end of that div tag
function getPopupBtnsText(htmlStr) {
    var theBtnText = "";
    var lowerHtmlStr = htmlStr.toLowerCase();
    var startIndex = lowerHtmlStr.indexOf("popupbtns");
    if (startIndex > -1) {
        // find the first > after startIndex
        startIndex = lowerHtmlStr.indexOf(">", startIndex);
        if (startIndex > -1) {
            startIndex += 2; // we want to start after that tag
            var endIndex = htmlStr.indexOf("</div>", startIndex);
            if (endIndex > startIndex) {
                theBtnText = htmlStr.substring(startIndex, endIndex);
            }
        }
    } 
    return theBtnText;
}

function closePopup() {
	setTimeout("document.getElementById('popupDiv').style.visibility='hidden'", 200 );
    setTimeout("document.getElementById('popupBkgndDiv').style.visibility='hidden'", 1050 );
    opacity("popupBkgndDiv", 50, 0, 1000);
}

// user hit the back or forward btn
function historyChange(newLocation, historyData) {
	var navPos = getNavPos(newLocation);
	navigate(navPos);
}

// utility function for getting the navPosition
// out of the "newLocation" string when the user
// hit the back or forward button
function getNavPos(newLocation) {
	var navPos = newLocation;
	var indexOfPipe = newLocation.indexOf("|");
	if (indexOfPipe > -1) {
		navPos = newLocation.substr(indexOfPipe + 1);
	}
	return navPos;
}

// this is a generic function for handling all navigation:
// it will be called by all menus, submenus, etc. which the user might click to navigate
// it uses the ajax libraries referenced above to
// send a request to the navigation controller .aspx page, posting
// the following navigation details:
//		the desired pg location (ex: class mark entry)
//		the selected "items", if any (ex: class id, student id, subject id)
//		the selected "view", if any (ex: mark entry by student or by subject)
//	[the pg location would be read in from the menu selection,
//  the selected items would come from the selector drop-down,
//  the selected view would come from the view drop-down]	

function continueNavigation(id)
{
	// logic for progress indicator:
	// set requestCompleted to false
	// with a 500 ms delay, call the 
	// showProgressIndicator function
	// the navResponseHandler will set
	// the requestCompleted to true once
	// the response has come back, so the 
	// progress indicator won't bother showing
	// anything if the response comes back within 500 ms
	requestCompleted = false;
	window.setTimeout('showProgressIndicator()', 800);

	// fix for the back button; works with historyChange function above
	dhtmlHistory.add("navpos|"+id, true);
	
	// initializes ajax call	
	httpRequest("post","NavController.aspx",true,navResponseHandlerResetCacheManager,"id="+id);
}

//This function checks for changes using continueNavigation as the callback.
function navigate(id) {

	checkChanges("continueNavigation('" + id + "');");			
}


//This function is called from the LoseChangeWarning popup.
//It is used to submit the users choice and continue appropriately.
function submitLoseChangeChoice(choice)
{
	
	if(choice == 'cancel')
	{
		//If the navigation is cancelled reset selector and view drop down choices
		
		setupViews(pageObj);
		setupSelector(pageObj);
		//Then call the cancel function if available, to reset the rest of the page.
		if(cancelFunction)
		{
			setTimeout('eval("' + cancelFunction +'");', 0);
		}
	
	}
	else
	{

		if(choice == 'save')
		{
			//save then continue navigation
				
			setTimeout('eval(saveFunction + "()");',0);
		}
		//Continue navigation
		
		//At this point either the changes have been saved or they are being
		//discarded so set hasChange to false.
		hasChanged = false;
		
		//Continue navigation by calling the callback function.
		setTimeout('eval("' + callBackFunction + '");',0);		
		
	}
	
	var elem = document.getElementById("changeMonitorDiv");
	elem.style.visibility = "hidden";
	elem.style.display = "none";
			
}

function showProgressIndicator() {
	if (requestCompleted == false) {
		// something really interesting happens here . . .
		if (progressIndicator == null) {
			progressIndicator = document.getElementById("progressIndicator");
		}
		if (progressIndicator) {
			progressIndicator.style.visibility = "visible";
		}
	}
}

function hideProgressIndicator() {
	requestCompleted = true;
	
	// something really interesting happens here . . .
	if (progressIndicator == null) {
		progressIndicator = document.getElementById("progressIndicator");
	}
	if (progressIndicator) {
		progressIndicator.style.visibility = "hidden";
	}
	
	// hide the really fascinating progress widget now . . .
}
function saveUserPref(prefID, theValue) {
    var queryString = "pref=" + prefID + "&value=" + encodeURIComponent(theValue) + "&foo=" + Math.random();
    httpRequest("get","GuiUtil/UserPrefHandler.aspx?" + queryString, true, nothing);
}

function nothing() {
    // do-nothing callback for ajax
    // ok, it does something - reset the session timeout warning countdown
    startSessionTimeout();    
}

function startSessionTimeout() {
    // we want to give them a couple of minutes to spare, just to account for network latency . . .
    var time = sessionDurationInMS >= (120 * 1000) ? sessionDurationInMS - (120 * 1000) : sessionDurationInMS - (60 * 1000);
    sessionTimeoutWarningHandle = setTimeout('secsRemaining = 60;continueCountDown = true; showSessionTimeoutWarning();', time); 
}

//This function post a form TO a popup. The popup should
//be page registered in the NavPageFinder. This post goes through 
//NavController.aspx
function postFormToPopUp(form, titleStr, height, width)
{
	var queryString= getQueryStrFromForm(form)
	popUp(queryString,titleStr,height,width);

}


// this is needed to work around a firefox bug
// https://bugzilla.mozilla.org/show_bug.cgi?id=317600
// the key is to call the setTimeout, even with a timeout of zero,
// so that "this" window, rather than the popup window is
// considered the "owner" of the ajax call to post the form
// otherwise, when the popup is closed before the ajax
// response arrives, errors will occur in the response handling
function postFormFromPopUp(form) {
	formToPostFromPopup = form;
	window.setTimeout('postForm()', 0);
}

// this is the generic function for posting a form
// using ajax.  All forms passed in as a parameter should
// include a field with the name id and the value pointing
// to the NavPositionID of the page which will handle
// the form submission.  All of the posts go to the
// NavController.aspx front controller.
function postForm(form,skipCacheManagerReset) {
	if (form == null) {
		form = formToPostFromPopup;
	}

	var queryString= getQueryStrFromForm(form)

	// logic for progress indicator:
	// set requestCompleted to false
	// with a 500 ms delay, call the 
	// showProgressIndicator function
	// the navResponseHandler will set
	// the requestCompleted to true once
	// the response has come back, so the 
	// progress indicator won't bother showing
	// anything if the response comes back within 500 ms
	requestCompleted = false;
	window.setTimeout('showProgressIndicator()', 500);
	
	if(skipCacheManagerReset)
	{
	    httpRequest("post","NavController.aspx",true,navResponseHandler, queryString);
	}
	else
	{
	    httpRequest("post","NavController.aspx",true,navResponseHandlerResetCacheManager, queryString);
	}
}
//This function combines all inputs from the given 
		//form into a query string in name/value pairs.
		function getQueryStrFromForm(form)
		{
			var queryString= "";
			var numberElements =  form.elements.length;
			for(var i = 0; i < numberElements; i++)  {
				var theValue = form.elements[i].value;
				
				// special case for radio btns and check boxes -
				// include them only if they are checked
				if (form.elements[i].type == "radio" ||
						form.elements[i].type == "checkbox") {
					if (form.elements[i].checked == true) {
						theValue = form.elements[i].value;
					}
					else {
						continue; 
					}
				}
				
				// special case for mulitple select lists
				if (form.elements[i].type == "select-multiple") {
				
					theValue = ""; // clear it out before the loop
					var ops = form.elements[i].options;
					if (ops != null) {
						for (var n=0; n<ops.length; n++) {
							if (ops[n].selected) {
								theValue = theValue + ops[n].value + ",";
							}
						}
					}
					
					// remove the trailing comma
					var lastIndexOfComma = theValue.lastIndexOf(",");
					if (lastIndexOfComma == theValue.length - 1) {
						theValue = theValue.substring(0, theValue.length - 1);
					}
				}
	
				if(i < numberElements-1)  {
					queryString += form.elements[i].name+"="+
								encodeURIComponent(theValue)+"&";
				} else {
					queryString += form.elements[i].name+"="+
								encodeURIComponent(theValue);
				}
			}
		
			return queryString;
		}

function navResponseHandler()
{
	if(request.readyState == 4){
		if(request.status == 200) {
			var resp =  request.responseText;
			
			navResponseHandlerContinue(resp)
		} else {
			alert("A problem occurred with communicating between the XMLHttpRequest object and the server program. " + request.status);
		}
	}//end outer if
}	

function navResponseHandlerResetCacheManager()
{
	if(request.readyState == 4){
		if(request.status == 200) {
			var resp =  request.responseText;
			
			
			    //New page is being processed, reset hasChanged.
			    hasChanged = false;
			    
			    navResponseHandlerContinue(resp)
			} else {
			alert("A problem occurred with communicating between the XMLHttpRequest object and the server program. " + request.status);
		}
	}//end outer if
}	
	
// this is a generic ajax asynchronous callback handler
// which does the following:
// checks the readyState and status of the request and does the error handling
// if there are no errors, it grabs the request.responseText and:
//		creates a js object based on the request.responseText
//		grabs the content area's inner html from the js object
//		grabs the list of js references and adds them to the header tag
//		grabs the list of css references and adds them to the header tag
//		grabs the javascript text and creates a new <script> tag whose
//			inner text is set to this js text and adds this to the header tag
function navResponseHandlerContinue(resp) {

            // reset the sessionTimeoutWarningHandle
            // we're actually going to show the warning 2 mins before they actually timeout
            // to account for network latency between client and server
            hideSessionTimeoutWarning();
            startSessionTimeout();
			
			try {
			
				// >>> 11/16/2K6 for now, it's ok to leave this
				// >>> call to hideProgressIndicator here - we always
				// >>> want to hide it, even if prog info comes back
				// >>> because it's an all-or-nothing situation right
				// >>> now, but in the future, we may want to move this
				// >>> call and hide the prog indic only if some real
				// >>> content comes back, and maybe update or change
				// >>> the progress indic if we find out from the server
				// >>> that something has changed, but the prog isn't done yet
				hideProgressIndicator();
				
				// reset the background pg of above footer element
				// just in case a previous pg had a unique background
				var aboveFooterElem = document.getElementById('aboveFooter');
		        if (aboveFooterElem != null) {
			        aboveFooterElem.style.background = "";
		        }
			
				pageObj = eval( "(" + resp + ")" );
				
				if (pageObj != null) {
					// calling isError will display any error msg
					var thisIsAnErrorMsg = isError(pageObj);
					var thisIsProgressInfo = isProgInfo(pageObj);
							
					if (!thisIsAnErrorMsg && !thisIsProgressInfo) {
						getPageID(pageObj);
						try {
						    removeOldNodes(pageObj);
						} catch (ex) {
						    // ok to ignore: print view won't need removeOldNodes
						    // but it will need the others
						}
						setupJsRefs(pageObj);
						setupCssRefs(pageObj);
						setupJsText(pageObj);
						setupContent(pageObj);
						try {
						    setupBreadCrumb(pageObj);
						    setupConfirmOrErrorMsg(pageObj);
						    setupViews(pageObj);
						    setupSelector(pageObj);
						    hideShowSelectors();
						    setupButtons(pageObj);
						    setupIcons(pageObj);
						    setupRecordNavigator(pageObj);
						} catch (ex) {
						    // ok to ignore: print view won't need above calls
						    // but it will need the tryOnContentLoad call
						}
						
						setTimeout('tryOnContentLoad()', 400);
					}
				}
			} catch (ex) {
				if (resp.indexOf("LoginForm") > -1) {
					// the user timed-out and is being 
					// redirected to the login pg, so 
					// send them there
					window.location = "./Login.aspx";
				}
			}
	
}

function tryOnContentLoad() {
	try {
		// looks like we need a minor
		// delay to ensure that the function
		// really is loaded first
		if (onContentLoad) {
			setTimeout('onContentLoad()', 100);
		}
	} catch (ex) {
		// ok to ignore;
		// there may not be a onContentLoad() function
	}
}

// returns true if there is an error message
// otherwise returns false; also sets any
// error messages in the pgObj if this is an error msg
function isError(pgObj) {
	var thisIsAnErrorMsg = false;
	if (pgObj.errorHtml != null) {
		var elem = document.getElementById("content");
		if (elem != null) {
			thisIsAnErrorMsg = true;
			elem.innerHTML = pgObj.errorHtml;
		}
		elem = document.getElementById("breadCrumb");
		if (elem != null) {
			elem.innerHTML = "";
		}
	}
	return thisIsAnErrorMsg;
}

function getPageID(pgObj) {
	if (pgObj.currentPgID != null) {
		currentPgID = pgObj.currentPgID;
	}
}

				
// returns true if this is progress information
// otherwise returns false; also sets any
// error messages in the pgObj if this is an error msg
function isProgInfo(pgObj) {
	var thisIsProgInfo = false;
	if (pgObj != null && pgObj.progressInfo != null) {
		
		// >>> DO SOMETHING CLEVER HERE... cz 11/16/2K6 <<<
		
		//alert(pgObj.progressInfo);
		thisIsProgInfo = true;
	}
	
	return thisIsProgInfo;
}

function removeOldNodes(pgObj) {
	// before adding new dynamic content
	// first remove any dynamic content
	// which had been added due to a navigation
	// even to the same div - if the div is
	// "content" or not listed, then remove
	// all of the previously added dynamic nodes
	
	// it is possible that the recordNavigator span was moved into the
	// breadcrumb - make sure to move it back to the body before the
	// breadcrumb contents are reset
	
	var bcDiv = document.getElementById("breadCrumb");
    var navSpan = document.getElementById("recordNavigator");
    var bodyDiv = document.getElementById("bodyDiv");
    bodyDiv.appendChild(navSpan);
	
	if (pgObj.putContentHere != null) {
		removeAllNodesForDiv(pgObj.putContentHere);
	} else {
		removeAllNodes();
	}
}

function setupContent(pgObj) {
	var div = document.getElementById("content");
	
	// if the json returned from the ajax call
	// specifies a particular div, then dump the
	// contents returned into that div, otherwise
	// use the "content" div as the default place
	// to put the content
	if (pgObj.putContentHere != null) {
		var specifiedDiv = document.getElementById(pgObj.putContentHere);
		if (specifiedDiv != null) {
			div = specifiedDiv;
		}
	}
	div.innerHTML = pgObj.contentHtml;
}

function setupBreadCrumb(pgObj) {
    setBreadCrumbTxt(pgObj.breadCrumb);
}

// returns just the crumb html without the record navigator node
function getBreadCrumbTxt() {
    var bcDiv = document.getElementById("breadCrumb");
    var txt = bcDiv.innerHTML;
    return txt;
}

function setBreadCrumbTxt(crumbTxt) {
	var bcDiv = document.getElementById("breadCrumb");
	bcDiv.innerHTML = crumbTxt;
}

		
function updateConfMsg(msg) {
	var confirmMsgDiv = document.getElementById("confirmMsg");
	var errorMsgDiv = document.getElementById("errorMsg");
	
	
	errorMsgDiv.innerHTML = "";
	confirmMsgDiv.innerHTML = msg;
	
	
	highlightConfirm();
	setTimeout('unhighlightConfirm();', 8000);
}		
		
function setupConfirmOrErrorMsg(pgObj) {
	var confirmMsgDiv = document.getElementById("confirmMsg");
	var errorMsgDiv = document.getElementById("errorMsg");
	
	
	// the rule is that we'll show only an error
	// or a confirmation msg, never both - so if both
	// exist in the pgObj, use only the error message
	if (pgObj.errorMsg) {
		errorMsgDiv.innerHTML = pgObj.errorMsg;
		confirmMsgDiv.innerHTML = "";
		
		
		errorMsgDiv.style.visibility = "visible";
		confirmMsgDiv.style.visibility = "hidden";
		
		
		highlightError();
		setTimeout('unhighlightError()', 8000);
		
	} 
	else if (pgObj.confirmMsg) {
		errorMsgDiv.innerHTML = "";
		confirmMsgDiv.innerHTML = pgObj.confirmMsg;
		
		
		errorMsgDiv.style.visibility = "hidden";
		confirmMsgDiv.style.visibility = "visible";
		
		
		highlightConfirm();
		window.setTimeout('unhighlightConfirm();', 8000);
		
	} 
	else 
	{
		errorMsgDiv.innerHTML = "";
		confirmMsgDiv.innerHTML = "";
		errorMsgDiv.style.visibility = "hidden";
		confirmMsgDiv.style.visibility = "hidden";
	}
}

function highlightError() {
    var errorMsgDiv = document.getElementById("errorMsg");
    errorMsgDiv.style.font = 'normal normal bold 10pt Verdana';
    errorMsgDiv.style.background = "#D8E1ED";
}

function unhighlightError() {
    var errorMsgDiv = document.getElementById("errorMsg");
    errorMsgDiv.style.font = 'normal normal normal 10pt Verdana';
    errorMsgDiv.style.background = "white";
}

function highlightConfirm() {
    var confirmMsgDiv = document.getElementById("confirmMsg");
    confirmMsgDiv.style.font = 'normal normal bold 10pt Verdana';
    confirmMsgDiv.style.background = "#D8E1ED";
}

function unhighlightConfirm() {
    var confirmMsgDiv = document.getElementById("confirmMsg");
    confirmMsgDiv.style.font = 'normal normal normal 10pt Verdana';
    confirmMsgDiv.style.background = "white";
}

function setupJsRefs(pgObj) {
	var jsRefsArray = pgObj.jsRefs;
	
	var divName = "content";
	if (pgObj.putContentHere != null) {
		divName = pgObj.putContentHere;
	} 
	
	for (var j=0; j<jsRefsArray.length; j++) {
		addJSRef(jsRefsArray[j], divName);
	}
}

function setupCssRefs(pgObj) {
	var cssRefsArray = pgObj.cssRefs;
	
	var divName = "content";
	if (pgObj.putContentHere != null) {
		divName = pgObj.putContentHere;
	} 
	
	for (var c=0; c<cssRefsArray.length; c++) {
		addCSSRef(cssRefsArray[c], divName);
	}
}

function setupJsText(pgObj) {
	var divName = "content";
	if (pgObj.putContentHere != null) {
		divName = pgObj.putContentHere;
	} 
	
	addJSText(pgObj.jsText, divName);
}

function setupViews(pgObj) {
	if (pgObj.views != null && pgObj.views.length > 0) {
		doSetupViews(pgObj.views);
	} else {
		clearViews();
	}
}

function setupSelector(pgObj) {
	if (pgObj.selections != null) {
		doSetupSelections(pgObj.selections);
	} else {
		clearSelections();
	}
}

function setupIcons(pgObj) {
	if (pgObj.icons != null && pgObj.icons.length > 0) {
		doSetupIcons(pgObj.icons);
	} else {
		clearIcons();
	}
}

function setupRecordNavigator(pgObj) {
	if (pgObj.recordNavigator != null && pgObj.recordNavigator.length > 0) {
		doSetupRecordNavigator(pgObj.recordNavigator);
	} else {
		clearRecordNavigator();
	}
}

function setupButtons(pgObj) {
	if (pgObj.btns != null) {
		doSetupButtons(pgObj.btns);
	} else {
		clearButtons();
	}
}


function clearButtons() {
	var buttonsElem = document.getElementById("buttons");
	if (buttonsElem != null) {
		buttonsElem.innerHTML = "";	
	}
}

function doSetupButtons(btnsArray) {
	clearButtons(); // clear this before adding any

	// get the btns div
	var buttonsElem = document.getElementById("buttons");
	
	// for each item in btnsArray, 
	// create a new img obj with the src from the btnsArray
	// and the onclick set to the js in the btnsArray
	var numOfBtns = btnsArray.length;
	
	var imgStr = "";
	
	for (var n=0; n<numOfBtns; n++) {
		var btn = btnsArray[n];
		
		if (btn) {
			var tokens = btn.split("|");
			
			if (tokens.length >= 3) {
				var srcStr = tokens[0];
				var jsStr = tokens[1];
				var idStr = tokens[2];
				
				// using the string seems to make it work....
				imgStr = imgStr + '<img class="footer_button"' +
					'" onclick="' +
					jsStr +
					'" id="' +
					idStr +
					'" src="' +
					srcStr +
					'">';
			}
		}
	} // end of looping over the btns
	buttonsElem.innerHTML = imgStr;
	
} // end of doSetupButtons function

function clearSelections() {
	var selectorElem = document.getElementById("selectorSelect");
	selectorElem.options.length = 0;
	selectorElem.disabled = true;
	showHideSelections(false);
}

function showHideSelections(show) {
	var divElem = document.getElementById("selectorDiv");
	var labelElem = document.getElementById("selectorLabelDiv");
	if (show) {
		divElem.style.visibility = "visible";
		labelElem.style.visibility = "visible";
	} else {
		divElem.style.visibility = "hidden";
		labelElem.style.visibility = "hidden";
	}
}


function doSetupSelections(selectionsArray) {

    var numOfVOps = selectionsArray.length;
    
    if (numOfVOps <= 0) {
        showHideSelections(false);
    } else {
	    showHideSelections(true);
    	
	    var selectorElem = document.getElementById("selectorSelect");
	    selectorElem.options.length = 0;
	    selectorElem.disabled = false;
    	
	    for (var n=0; n<numOfVOps; n++) {
		    var opsParts = selectionsArray[n].split("|");
    		
		    if (opsParts.length == 3) {
			    var opsText = opsParts[0];
			    var opsID = opsParts[1];
			    var isSelected = opsParts[2];
    			
			    selectorElem.options[n] = new Option(opsText, opsID);
    			
			    if (isSelected == "true") {
				    selectorElem.options[n].selected = true;
			    }
		    }
	    }	 // end looping over things to stuff into the selector	
	}// end if there are some things to show in the selector	
}

function clearViews() {
	var viewElem = document.getElementById("viewSelect");
	viewElem.options.length = 0;
	viewElem.disabled = true;
	showHideViews(false);
	
}

function showHideViews(show) {
	var divElem = document.getElementById("viewSelectDiv");
	var labelElem = document.getElementById("viewLabelDiv");
	if (show) {
		divElem.style.visibility = "visible";
		labelElem.style.visibility = "visible";
	} else {
		divElem.style.visibility = "hidden";
		labelElem.style.visibility = "hidden";
	}
}

function doSetupViews(viewsArray) {
	showHideViews(true);

	var viewElem = document.getElementById("viewSelect");
	viewElem.options.length = 0;
	viewElem.disabled = false;
	
	var numOfViews = viewsArray.length;
	for (var n=0; n<numOfViews; n++) {
		var viewParts = viewsArray[n].split("|");
		
		if (viewParts.length == 3) {
			var viewText = viewParts[0];
			var viewID = viewParts[1];
			var isSelected = viewParts[2];
			
			viewElem.options[n] = new Option(viewText, viewID);
			
			if (isSelected == "true") {
				viewElem.options[n].selected = true;
			}
		}
	}			
}

function hideShowSelectors() {
	var viewElem = document.getElementById("viewSelect");
	var selectorElem = document.getElementById("selectorSelect");
	
	var selectorsDiv = document.getElementById("selectors");
	var iconsDiv = document.getElementById("icons");
	
	if (viewElem.options.length == 0 &&
			selectorElem.options.length == 0) {
		selectorsDiv.style.visibility = "hidden";
		iconsDiv.style.position = "absolute";
		iconsDiv.style.right = "0";
	} else {
		selectorsDiv.style.visibility = "visible";
		iconsDiv.style.position = "relative";
	}
}

function doSetupIcons(iconsArray) {
	// first clear out any existing icons
	clearIcons();
	
	// then add in the new ones
	var numOfIcons = iconsArray.length;
	var iconDiv = document.getElementById("icons");
	
	//get the help icon and remove it so it can be added at the end
	var helpIcon = document.getElementById("helpIcon");
	iconDiv.removeChild(helpIcon);	
	
	for (var n=0; n<numOfIcons; n++) {
		var iconParts = iconsArray[n].split("|");
		
		if (iconParts.length >= 4) {
			var img = iconParts[0];
			var imgOver = iconParts[1];
			var altTxt = iconParts[2];
			var jsOnClick = iconParts[3];
			var imgElem = document.createElement("img");
			
			// use this as the default id
			var idStr = "iconID" + n;
			
			// see if an id was passed in with the json
			// and if so, use that instead of the default
			if (iconParts.length >= 5) {
				idStr = iconParts[4];
			}
			
			imgElem.setAttribute("id", idStr);
			imgElem.setAttribute("src", img);
			imgElem.setAttribute("alt", altTxt);
			imgElem.setAttribute("title", altTxt);
			imgElem.setAttribute("height", 32);
			imgElem.setAttribute("width", 30);
			changeOnClick(imgElem, jsOnClick);
			setMouseOverImg(imgElem, imgOver);
			setMouseOutImg(imgElem, img);
			iconDiv.appendChild(imgElem);
			
			iconsToClear.push(imgElem);
		}
	}	
	
	//add back in the help icon so it will be on the left
	iconDiv.appendChild(helpIcon);
}

function doSetupRecordNavigator(recordNavigatorArray) {
	// first clear out any existing index selections
	clearRecordNavigator();
	
	var recordNavigatorElem = document.getElementById("recordNavigator");
	var indexSrchElem = document.getElementById("indexSearch");
	if (recordNavigatorArray != null) {
	    for (var n=0; n<recordNavigatorArray.length; n++) {
	        if (n==0) {
	            if (recordNavigatorArray[n] == "true") {
	                recordNavigatorElem.style.visibility = "visible";
	                
	                var bcDiv = document.getElementById("breadCrumb");
	                var navSpan = document.getElementById("recordNavigator");
                    bcDiv.appendChild(navSpan);
	                
	            } else {
	                recordNavigatorElem.style.visibility = "hidden";
	                break; // if first value is not "true" then don't show the widget at all 
	            }
	        } else {
	            var opsParts = recordNavigatorArray[n].split("|");
		        if (opsParts.length == 3) {
			        var opsText = opsParts[0];
			        var opsID = opsParts[1];
			        var isSelected = opsParts[2];
        			
			        indexSrchElem.options[n-1] = new Option(opsText, opsID);
        			
			        if (isSelected == "true") {
				        indexSrchElem.options[n-1].selected = true;
			        }
		        }
	        } // end of creating the index search options
	    } // end of looping over recordNavigatorArray
	} // end if recordNavigatorArray is not null
}

function clearRecordNavigator() {
    // remove all options from the "index" drop down, as these options
    // may be different for each view
    var indexSrchElem = document.getElementById("indexSearch");
    if (indexSrchElem) {
	    indexSrchElem.options.length = 0;
    }
    // hide the whole widget
    var recordNavigatorElem = document.getElementById("recordNavigator");
    if (recordNavigatorElem) {
        recordNavigatorElem.style.visibility = "hidden";
    }
    // clear out any previous selections
    var selection = document.getElementById("recordNavigatorSelection");
    if (selection && selection.value) {
        selection.value = ""; 
    }
}

function setMouseOverImg(imgElem, imgOver) {
	imgElem.onmouseover = function () {
		this.src = "" + imgOver;
	}
}

function setMouseOutImg(imgElem, imgOut) {
	imgElem.onmouseout = function () {
		this.src = "" + imgOut;
	}
}

// the string passed in as the callMe param
// should be formatted as a full call to a js
// function, parens and all, ex: 'helloWorld()'
function changeOnClick(elem, callMe) {
	elem.onclick = function() {
		eval(callMe);
	}
}

function clearIcons() {
	var iconsElem = document.getElementById("icons");
	for (var n=0; n<iconsToClear.length; n++) {
		try {
			iconsElem.removeChild(iconsToClear[n]);			
		} catch (ex) {
			// ignore this - the icon may be 'hidden'
			// so not actually in the iconsElem right now
		}
	} // end of looping over icons to remove
	
	iconsToClear = new Array();
}

// use this to temporarily remove an icon from the icons div
function hideIcon(idOfIconToHide) {
	var iconDiv = document.getElementById("icons");
	var iconToRemove = document.getElementById(idOfIconToHide);
	if (iconToRemove) {
		iconDiv.removeChild(iconToRemove);			
	} 
}

// use this to show all icons in the icons div as they first
// appeared the last time the content area was updated
// this might be useful after having used hideIcon() above
// when you want to show it again
function showAllIcons() {
    var iconDiv = document.getElementById("icons");
	
	//get the help icon and remove it so it can be added at the end
	var helpIcon = document.getElementById("helpIcon");
	iconDiv.removeChild(helpIcon);
	
	// remove all the icons that are currently showing
	iconDiv.innerHTML = "";
	
	// add them all back in in the order they first appeared
	for (var n=0; n<iconsToClear.length; n++) {
		iconDiv.appendChild(iconsToClear[n]);			
	} // end of looping over icons to add back in
	
	//add back in the help icon so it will be on the left
	iconDiv.appendChild(helpIcon);
}
function addJSText(jsText, divName) {
	var headElem = document.getElementById("head");
	var newScriptElem = document.createElement("script");
	//newScriptElem.setAttribute('id', 'jsText');
	newScriptElem.setAttribute('type', 'text/javascript');
	headElem.appendChild(newScriptElem);
	newScriptElem.text = jsText;
	
	addDynamicNode(newScriptElem ,divName);
	
	return newScriptElem;
}

function addJSRef(jsRef, divName) {
	var headElem = document.getElementById("head");
	var newScriptElem = document.createElement("script");
	newScriptElem.setAttribute('type', 'text/javascript');
	newScriptElem.setAttribute('src', jsRef);
	headElem.appendChild(newScriptElem);
	
	addDynamicNode(newScriptElem ,divName);
}

	
function addCSSRef(cssRef, divName) {
	var headElem = document.getElementById("head");
	var newCssElem = document.createElement("link");
	newCssElem.setAttribute('href', cssRef);
	newCssElem.setAttribute('type', 'text/css');
	newCssElem.setAttribute('rel', 'stylesheet');
	headElem.appendChild(newCssElem);
	
	addDynamicNode(newCssElem ,divName);
}

//This function checks for changes with
//continueSelectorChange as the callback function.
function selectorChange() {
			
	checkChanges("continueSelectorChange();");
}

//This function populates the selectorForm with the
//new selection chosen by the user. The form is then posted 
//to continue navigation.
function continueSelectorChange()
{
	// find the selectorForm to post
	// and set its id to the current page id
	var selectorForm = document.getElementById("selectorForm");
	selectorForm.id.value = currentPgID;
	
	// get the new selection from the selector widget
	var selectorElem = document.getElementById("selectorSelect");
	var selectedIndex = selectorElem.selectedIndex;
	selectorForm.newSelection.value = selectorElem.options[selectedIndex].value;

	// post the selectorForm
	postForm(selectorForm);
}


function viewChange() {
	// get the id of the selected item
	// and pass it to the navigate function
	var viewElem = document.getElementById("viewSelect");
	var selectedIndex = viewElem.selectedIndex;
	var value = viewElem.options[selectedIndex].value;
	
	//Check changes is not needed here to validate the navigation
	//because it goes through the standard navigate function which 
	//performs the checks.
	navigate(value);			
}

function goToSearch() {
    checkChanges("continueGoToSearch();");
}


function goToLast() {
    checkChanges("continueGoToLast();");
}

function continueGoToLast() {
    var formElem = document.getElementById("recordNavigatorForm");
    formElem.id.value = currentPgID;
    formElem.cmd.value = "last";
    var selectorElem = document.getElementById("indexSearch");
	var selectedIndex = selectorElem.selectedIndex;
	formElem.indexToUse.value = selectorElem.options[selectedIndex].value;
    
    postForm(formElem);
}

function goToPrev() {
    checkChanges("continueGoToPrev();");
}

function continueGoToPrev() {
    var formElem = document.getElementById("recordNavigatorForm");
    formElem.id.value = currentPgID;
    formElem.cmd.value = "prev";
    var selectorElem = document.getElementById("indexSearch");
	var selectedIndex = selectorElem.selectedIndex;
	formElem.indexToUse.value = selectorElem.options[selectedIndex].value;
    
    postForm(formElem);
}

function goToNext() {
    checkChanges("continueGoToNext();");
}

function continueGoToNext() {
    var formElem = document.getElementById("recordNavigatorForm");
    formElem.id.value = currentPgID;
    formElem.cmd.value = "next";
    var selectorElem = document.getElementById("indexSearch");
	var selectedIndex = selectorElem.selectedIndex;
	formElem.indexToUse.value = selectorElem.options[selectedIndex].value;
    
    postForm(formElem);
}

function goToFirst() {
    checkChanges("continueGoToFirst();");
}

function continueGoToFirst() {
    var formElem = document.getElementById("recordNavigatorForm");
    formElem.id.value = currentPgID;
    formElem.cmd.value = "first";
    var selectorElem = document.getElementById("indexSearch");
	var selectedIndex = selectorElem.selectedIndex;
	formElem.indexToUse.value = selectorElem.options[selectedIndex].value;
    
    postForm(formElem);
}