


//<SCRIPT language=JavaScript>
/***********************************************************
************************************************************
  	XML Tree Scripts
		
	These scripts are specifically designed
	to work with the XML tree and are closely tied to
	its operation.  Most of these functions are called
	from the XSL file used to display the XML tree.
************************************************************
************************************************************/
	//alert('Loading Scripts on ' + document.location.href);

	/**
	* Some global variables that will be useful across
	* program calls.  This first set is just used as
	* constants:
	**/
	var d = document;
	var hidden = "none";
	var visible = "block";
	var OpenerImg='../common/Images/closedFolder_sm.gif';
	var CloserImg='../common/Images/openFolder_sm.gif';
	
	/**
	* These global variables are used with the search
	* function that allows the user to search throug
	* the XML tree
	**/
	var blnSearchForNext=false;
	var intLastSearchPos=0;
		
	/**
	* validateXMLDoc
	* This function forces Validation of this XML File.
	* IE5 does not validate XML by default, so this
	* javascript will force valication and display errors.
	* (Note that this function should only be called
	*  from within an XML file.  That is done by putting
	*  a call to this function in the XSL for the XML.)
	**/
	function validateXMLDoc() {
		xmldoc= new ActiveXObject("Microsoft.XMLDOM");
		xmldoc.validateOnParse = true;
		var url=document.location+"";
		xmldoc.load(url);		
		var err= xmldoc.parseError;
		if (err.line) {				
			var msg = "Error Parsing XML on line " +err.line ;
			msg += ", Position: " + err.linepos + ": ";
			msg += "<ol>";
			msg += err.reason+"<br />Near text '"+err.srcText+"'" 
			msg += "</ol>Attempting to display despite errors...<br />"
		} else {
			var msg=""
		}
		//alert(xmldoc.url);
		return msg
	}	


	/**
	* toggleDisplay(String ItemName, Object Caller)
	* This function will toggle the open/closed state
	* of a branch in the XML tree.  The itemName tells
	* the name of the DIV sectoin to hide or show.  
	* Caller is the icon object that was clicked.
	**/
	function toggleDisplay(strItemName,caller) {
		var obj = getObject(strItemName).style;
		if (obj.display == visible) {
			obj.display = hidden;
			caller.src=OpenerImg;
		} else {
			obj.display = visible;
			caller.src=CloserImg;
		}
		// This may have changed the size of the thing, 
		// so we need to re-prepare the form scrolling
		prepareForScrolling('scrollcontent');
	}
	
	/**
	* showAll() shows all branches of the XML tree
	**/
	function showAll() {toggleAll(1)}

	/**
	* hideAll() hides all branches of the XML tree
	**/
	function hideAll() {toggleAll(0)}
	
	/**
	* toggleAll(Boolean Mode) is the work behind showAll and hideAll.
	* It loops through the entire page and looks for any
	* tags that can be expanded or collapsed, based on
	* the mode that was requested (1 = show, 0 = hide)
	**/
	function toggleAll(bShow) {
		var i, obj;
		var coll;
		//First loop through and change the images
		if ( (d.all && (coll=d.all.tags('IMG')))
		   ||(d.getElementsByTagName && (coll=d.getElementsByTagName('IMG')))
		   ){
			for (i=0;i<=coll.length;i++) {
				obj=coll.item(i);
				if (obj && String(obj.src).match(bShow?OpenerImg:CloserImg)) {
			   	    obj.src=(!bShow?OpenerImg:CloserImg);
					//eval(obj.onclick+";anonymous();");
				}
			}
		}
		//Then loop through and change the actual visibility
		if ( (d.all && (coll=d.all.tags('DIV')))
		   ||(d.getElementsByTagName && (coll=d.getElementsByTagName('DIV')))
		   ){
			for (i=0;i<=coll.length-1;i++) {
				obj=coll.item(i);
				if (obj) {
					if (obj.id!='scrollcontent') {
			   			obj.style.display=(bShow?visible:hidden);
			   		}
				}
			}
		}
		// This may have changed the size of the thing, 
		// so we need to re-prepare the form scrolling
		prepareForScrolling('scrollcontent');
	}
		
	/**
	* searchTree(frmCaller)
	* SearchTree is called from a Form which must contain
	* a text field caled "searchText".  It will look through
	* the XML tree for a link containing the desired text, 
	* and expand to that branch.  SearchTree can be called
	* multiple times to go to subsequent matching branches.
	**/
	var objLastSelected = null;
	function searchTree(frmCaller) {
		var strSearchText;
		var intSearchStartPos;
		var i, obj;
		var coll;
		var bShow;
	
		//Get the search string
		strSearchText = String(frmCaller.elements['searchText'].value).toUpperCase();

		//Determine the starting location
		intSearchStartPos = (blnSearchForNext?intLastSearchPos:0);
		
		//First loop and find the first anchor tag that matches
		if ( (d.all && (coll=d.all.tags('A')))
		   ||(d.getElementsByTagName && (coll=d.getElementsByTagName('A')))
		   ){
			if (coll.length < intSearchStartPos) {intSearchStartPos = 0;}
			if (objLastSelected) objLastSelected.style.backgroundColor='White';

			for (i=intSearchStartPos; i<coll.length; i++) {
				obj=coll.item(i);
				//Make sure it is the right type of link
				if (obj && obj.href!="" && obj.target=="FormFrame") {
					window.status = "Searching for '" + strSearchText + "' in '" + obj.innerHTML + "'...";
				
					//Look for a match
					if (String(obj.innerHTML).toUpperCase().indexOf(strSearchText) >=0) {
			   			
						//Call the anchor's action
						//obj.click();
						obj.style.backgroundColor='Yellow';

						
			   			//Change the button text and remember this search
			   			frmCaller.elements['searchButton'].value="Find Next";
			   			blnSearchForNext = true;
			   			intLastSearchPos = ++i;
			   			
			   			//Expand the tree and update the appropriate images
						//toggleAll(0)
						expandTreeForNode(obj);

						// This may have changed the size of the thing, 
						// so we need to re-prepare the form scrolling
						prepareForScrolling('scrollcontent');
						
						// ScrollTo Node
						getObject('scrollcontent').scrollTo(getRealTop(obj));

						
						//end
						objLastSelected = obj;
			   			window.status="Ready";
			   			return;
			   		}
				}
			}
			alert("'" + frmCaller.elements['searchText'].value + "' not found.");
			blnSearchForNext=false;
			window.status = "Ready";
		}
	}
	
	function getRealTop(el) {
      yPos = el.offsetTop;
      tempEl = el.offsetParent;
      while (tempEl != null) {
        yPos += tempEl.offsetTop;
        tempEl = tempEl.offsetParent;
      }

      return yPos-105;// Fudge factor because it was not quite working for the scroll
    }
    
	/**
	* expandTreeForNode(Object NodeToExpand)
	* This function will expand all the necessary branches of
	* the XML tree in order to make a certain node visible.
	**/
	function expandTreeForNode(obj) {
		var coll;

		//First, find the nearest table tag
		try {
			while (obj.tagName != 'TD') {
				window.status=obj.tagName;
				if (!obj.parentElement) {return;}
				obj = obj.parentElement;
			}
		} catch (e) {
		alert(e);
			return;
		}
		
		//Under the table tag, locate the first IMG and set its source to the Closer
		if ( (obj.children && (coll=obj.children.tags('IMG'))) 
		   ||(obj.getElementsByTagName && (coll=obj.getElementsByTagName('IMG')))
		   )
		{

			if (coll.item(0) && (String(coll.item(0).src).match(OpenerImg) || String(coll.item(0).src).match(CloserImg))) {
				coll.item(0).src=CloserImg;
				//Then locate the first DIV tag and set its display to visible
				if ( (obj.all && (coll=obj.all.tags('DIV'))) 
				   ||(obj.getElementsByTagName && (coll=obj.getElementsByTagName('DIV')))
				   )
				{
					coll.item(0).style.display=visible;
				}
			}
		}
			
		
		expandTreeForNode(obj.parentElement);
				
	}

	/**
	* getObject(String ObjectName)
	* Gets a named tag object independent of browser version
	**/
	function getObject(strItemName) {
		if(d.all && (obj=d.all[strItemName]) 
		   || d.layers && (obj=d.layers[strItemName]) 
		   || d.getElementById && (obj=d.getElementById(strItemName))) {
			return obj;
		}
		return null;
	}

	/*------------------------------------------------------------------------------------
	Function:  getValue
	Purpose:   Used to get the value of items in the form.  Although the value of most 
			form items can be accessed with ELEMENT.value, this does not work for all
			types of items (SELECT, CHECKBOX, RADIO).
	           
			Note that if the value of the element includes more than one item, a list
			will be returned, separated by commas.
	           
	Arguments: ELEM - the form object from which to get a value.
	Returns:   (None)
	------------------------------------------------------------------------------------*/
	function getValue(ELEM) {

		var strValue = '';
			
		if (ELEM) {
		
			// If the element is a select list, then it has OPTIONS
			if (ELEM.options) {
				for (var j=0; j<ELEM.options.length;j++) {
					if (ELEM.options(j).selected) {
						strValue = ELEM.options(j).value + (strValue.length>0?',':'');
					}
				}
			}
			
			//If the element has length then it is a collection - probably checkboxes
			else if (ELEM.length) {					
				for (var j=0;j<ELEM.length;j++) {
					if (ELEM[j].status) {
						strValue = ELEM[j].value + (strValue.length>0?',':'');
					}
				}
			}
			
			//If it is a span or a div
			else if (ELEM.tagName.match(/^(DIV|SPAN|P)$/i)) {
				strValue = ELEM.innerHTML;
			} 
			
			//If it was just a normal
			else {
				strValue = ELEM.value;
			}
		}
		
		return strValue;
		
	}

	isIE=(navigator.appName.indexOf("Microsoft")!=-1);
	isNS=(navigator.appName=="Netscape");
	
	/* ******************************************
	 * PrepareForScrolling
	 * Records the initial object height for future use in scrolling
	 * This height will be used to tell the scoll when to stop.
	 * ******************************************/
	function prepareForScrolling(objID) {
		//Make sure we start with the page scrolled to the top
		scrollTo(0,0);
		try {		
		
			obj = getObject(objID);
			
			fudgeFactor = 1.05; // A little extra space at the bottom

			if (isIE) {
				obj.contentHeight = obj.offsetHeight * fudgeFactor;
				if (!obj.scrollT) obj.scrollT = 0;
			} else {
				obj.contentHeight = obj.style.clip.bottom * fudgeFactor;
				if (!obj.scrollT) obj.scrollT = 0;
			}
			
			// Define the scrolling Images
			obj.scrollUpImg = document.getElementById('scrollup');
			obj.scrollUpImg.src = '../common/Images/scrollUp.gif';
			obj.scrollUpImg.onmouseover = new Function("getObject('"+objID+"').runScroll(-5);status='Click to scroll faster';return true;");
			obj.scrollUpImg.onmousedown = new Function("getObject('"+objID+"').runScroll(-25);");
			obj.scrollUpImg.onmouseout	= new Function("getObject('"+objID+"').runScroll(0);status='Ready';return true;");
			obj.scrollUpImg.onmouseup	= obj.scrollUpImg.onmouseover;
			
			obj.scrollDnImg = document.getElementById('scrolldown');
			obj.scrollDnImg.src = '../common/Images/scrollDown.gif';
			obj.scrollDnImg.onmouseover = new Function("getObject('"+objID+"').runScroll(+5);status='Click to scroll faster';return true;");
			obj.scrollDnImg.onmousedown = new Function("getObject('"+objID+"').runScroll(+25);");
			obj.scrollDnImg.onmouseout	= new Function("getObject('"+objID+"').runScroll(0);status='Ready';return true;");
			obj.scrollDnImg.onmouseup	 = obj.scrollDnImg.onmouseover;
					

			// Define some methods
			obj.scrollTo =	function temp(pos) 
			{		
				// Increment the scroll top the position but with hard stops
				// at zero and maxScroll
				maxScroll = this.contentHeight-this.scrollH+100;
				this.scrollT = min(max(0,pos), maxScroll);

				if (isIE) {
						this.style.clip='rect('+this.scrollT+','+this.scrollW+','+(this.scrollT+this.scrollH)+',0)';	
						this.style.top = this.posTop - this.scrollT ; 
				}
				setSnapSize(this.id)
			}

			obj.scrollBy =	function temp(pos) {
				if (obj.scrollUpImg.style.display=='block')
					this.scrollTo(this.scrollT-pos);
			}

			obj.runScroll =	function temp(speed) 
			{		
				if (this.scrollH >= this.contentHeight) return;
				if (speed|speed==0) this.scrollSpeed=speed;
				this.scrollTo(this.scrollT+this.scrollSpeed);
				if (this.scrollSpeed!=0) setTimeout('getObject("'+this.id+'").runScroll();',10);
			}
			
			obj.scrollToObject =	function temp(obj) 
			{		
				if (this.scrollH > this.contentHeight) return ;
				var target  = obj.parentElement.offsetTop+obj.parentElement.offsetHeight;
				var current = this.posTop-this.offsetTop+this.scrollH;
				//window.status="ScrollToObject Target = "+target+", start at "+current
				if (target > current) {
					this.scrollTo(target-this.scrollH);
				}				
			}


			obj.grabScrollHandle = function temp() {
				top.dragCursorStart = event.clientY;
				top.dragScrollStart = obj.scrollT;
				document.onmousemove = new Function("getObject('"+objID+"').handleScroll(event.clientY);return true;");
				document.onmouseup = new Function("document.onselectstart=null;document.onmousemove='';");
			}
			obj.handleScroll = function temp(pos) {
				// Scroll amount should be calculated based on
				// how much percent of distance the scroll thing was moved.
				document.onselectstart=new Function('return false;');
				var maxScroll = obj.contentHeight - obj.scrollH+100;
				var availHgt = obj.scrollH - 43 ;
				var pctView = obj.scrollH / obj.contentHeight;
				var pctScrl = (availHgt * (1-pctView))/maxScroll;
				//status = "CUR: " + top.dragCursorStart + ", T: " + top.dragScrollStart;
				this.scrollTo((pos - top.dragCursorStart)/pctScrl + top.dragScrollStart);
				//document.onselectstart=null;
			}
			
			// Define the scrolling Images
			obj.scrollHandle = document.getElementById('scrollhandle');
			obj.scrollHandle.onmousedown = obj.grabScrollHandle;

			// See if there is BottomLeftFloater...
			try {
				obj.bottomLeftFloater = document.getElementById('bottomLeftFloater');
			} catch (e) {}
			
			// Set this element to resize whenever the parent element resizes
			obj.parentElement.onresize=new Function("setSnapSize('"+objID+"');");
			
			setTimeout("setSnapSize('"+objID+"');",10) // Call the function in 100ms
		} catch (e) {
			alert('Error in PrepForScrolling: \n'+e.description);
		}
	}
			
	
	function max(a,b) {return a>b?a:b;}
	function min(a,b) {return a<b?a:b;}

	function setSnapSize(objID) {
		try {
			border=10;
			obj = getObject(objID);
			
			if (isIE) {
				winW = obj.parentElement.offsetWidth;
				winH = obj.parentElement.offsetHeight;
			} else {
				winW = window.innerWidth;
				winH = window.innerHeight;
			}
			
			//Store some variables for the object, for future use
			obj.posTop	= obj.parentElement.offsetTop + border ; 
			obj.posRight= winW - border;
			obj.scrollH = winH -2*border;
			obj.scrollW = winW-2*border-15;
			obj.scrollB = border;

			if (isIE) {
				if (obj.scrollW>0 && obj.scrollH>0) {
					obj.style.clip='rect('+obj.scrollT+','+obj.scrollW+','+(obj.scrollT+obj.scrollH)+',0)';	
					obj.style.top = obj.posTop - obj.scrollT; 
					obj.style.left=border;
					obj.style.height=obj.scrollH;
					obj.style.width=obj.scrollW;
				}
			} else {
				if (winW>0 && winH>0) {
					obj.style.clip.top=obj.scrollT;
					obj.style.clip.left=0;
					obj.style.clip.right=winW-border;
					obj.style.clip.height=winH-2*border;
					obj.top=obj.posTop; 
					obj.left=border;
					obj.height=winH-2*border;
					obj.width=winW-2*border;
				}
			}

			
			// Show the scroll buttons if necessary
			if (obj.scrollH < obj.contentHeight) {
			
				obj.scrollUpImg.style.position='absolute'; 
				obj.scrollUpImg.style.top=obj.posTop+3;
				obj.scrollUpImg.style.left=obj.posRight-15;
				obj.scrollUpImg.style.display='block';
				
				obj.scrollDnImg.style.position='absolute'; 
				obj.scrollDnImg.style.top=obj.posTop+obj.scrollH-20;
				obj.scrollDnImg.style.left=obj.posRight-15;
				obj.scrollDnImg.style.display='block';
			
				positionScrollHandle(obj);
				
			} else {
			
				if (obj.scrollT!=0) obj.scrollTo(0);
				obj.scrollUpImg.style.display='none';
				obj.scrollDnImg.style.display='none';
				obj.scrollHandle.style.display='none';
				
			}
	        
			// If there is a Resizer then show that too
			if (obj.bottomLeftFloater) {
				with (obj.bottomLeftFloater) {
					style.display='block';
					style.position='absolute'; 
					style.top= obj.scrollH - style.height-12;
					style.left= 10
				}
			}
		} catch (e) {
			alert('Error in SetSnapSize: \n'+e.description);
		}
	}
	
	function positionScrollHandle (obj) {
		var hnd = obj.scrollHandle;
		var maxScroll = obj.contentHeight - obj.scrollH+100;
		var availHgt = obj.scrollH - 43 ;
		var pctView = obj.scrollH / obj.contentHeight;
		var pctDown = obj.scrollT / maxScroll;
		var barHeight = availHgt * pctView;
		var barTop = (availHgt - barHeight)*pctDown + 22;
		hnd.style.position='absolute'; 
		hnd.style.top=obj.posTop+barTop;
		hnd.style.height = barHeight;
		hnd.style.width = '17px';
		hnd.style.left=obj.posRight-15;
		hnd.style.display='block';
	}
	
	function removeScrollForPrinting(objID) {
		getObject(objID);
		obj.scrollUpImg.style.display='none';
		obj.scrollDnImg.style.display='none';
		if (isIE) {
			winW = 650;
			if (winW>0 && winH>0) {
				obj.style.clip='rect(0,'+winW+','+obj.contentHeight+',0)';	
				obj.style.top = 0; 
				obj.style.left=0;
				obj.style.height=obj.contentHeight;
				obj.style.width=winW;
			}
		} else {
			winW = window.innerWidth;
			winH = window.innerHeight;
			if (winW>0 && winH>0) {
				obj.style.clip.top=0;
				obj.style.clip.left=0;
				obj.style.clip.right=winW;
				obj.style.clip.height=obj.contentHeight;
				obj.top=0; 
				obj.left=0;
				obj.height=obj.contentHeight;
				obj.width=winW;
			}
		}
	}
	

	function min(a,b) {return a<b?a:b;}
	function max(a,b) {return a>b?a:b;}	
	
	/**
	* selectProfile(String ProfileName, String Gender, String Age)
	* This function will set the profile information in the top
	* frame, make the profile information visible, and open the
	* profile overview in the form frame.
	**/
	function selectProfile(strProfileName, strGender, strAge) {
		try {
			window.top.TitleFrame.setVisibility("UserAndProfileInfo",visible);
			window.top.TitleFrame.ProfileInfo.innerHTML=strProfileName+' - '+strGender+', Age '+strAge;
			window.top.FormFrame.document.URL='LifeExpectForm.ASP?ParamID=Overview&ProfileName='+strProfileName;
		} 
		catch (e) {
			alert("Warning - Error Selecting Profile: " + e);
		}
	}


	/**
	* showProfileDetails(String ProfileName)
	* This function will load the details of the profile 
	* into the tree frame while displaying a "please wait"
	* message to the user.
	**/
	function showProfileDetails(strProfileName, strGender, strAge) {
		try {
			//Display the nice message
			window.top.TreeFrame.document.write('<table border=0 height=100% width=100%><tr>')
			window.top.TreeFrame.document.write('<td valign=center align=center><h3>Loading ')
			window.top.TreeFrame.document.write('information for ' + strProfileName + ' ...<')
			window.top.TreeFrame.document.write('/h3></td></tr></table>');
			//Load the tree
			window.top.TreeFrame.document.URL='LifeExpectTree.asp?ProfileName=\'' + strProfileName + '\'';
		} 
		catch (e) {
			alert("Warning - Error Selecting Profile: " + e);
		}
	}
	
	/**
	* BatchUpload() 
	* Uploads a CSV file directly from the USER's pc and performs batch processing on it.
	**/
	function batchUpload() {
		alert('This function is not yet enabled');
		return false;
	}
	
	/**
	* createBatchCSV()
	* This function will pass the list of selected profiles to
	* the ASP program so that a CSV file can be created.
	**/
	function createBatchCSV(val) {
		ProfileIDForm.Action.value='CREATE BATCH CSV';

		//Make sure that the user has selected a few items...
		var aList = new Array();
		var objProfiles = getObject("ProfileList");   // The visible profiles
		for (var i=0; i<objProfiles.length; i++) {
			if (objProfiles[i].selected) {
				var val_array = objProfiles[i].value.split('|');
				aList.push(val_array[3]);
			}
		}
		if (aList.length<2) {
			alert('Please select multiple profiles.');
			return false;
		} else {
			ProfileIDForm.ProfileName.value = aList.join(',')
			//alert('submitting '+aList.length+' profiles, length('+ProfileIDForm.ProfileName.value.length+')...');
			try {
				ProfileIDForm.submit();			
			} catch (e) {
				alert('Too many profiles selected. Please select fewer profiles and try again.\nThe limit is usually around 300-400 profiles.\n'+e.description);
			}
		}
	}


	function deleteProfile(val) {
		ProfileIDForm.Action.value='Delete Profile';
		if (val=='') {
			alert('Please select a profile');
		} else if (confirm('Deleting a profile cannot be undone.  Are you sure?')) {
			var val_array = val.split('|');
			try {
				ProfileIDForm.ProfileName.value=val_array[0];
 			} catch (e) {alert(e.description)}
			ProfileIDForm.submit();			
		}
	}

	function profileSelected(val) {
		if (val=='') {
			alert('Please select a profile');
		} else {
			var val_array = val.split('|');
			try {
				selectProfile(val_array[0],val_array[1],val_array[2]);
				showProfileDetails(val_array[0]);
 			} catch (e) {alert(e.description)}
		}
	}

/***********************************************************
************************************************************
  	Navigation / Header Scripts
		
	The next several scripts are useful in conjunction with
	the navigation buttons or tabs, and other header frame
	related activities
************************************************************
************************************************************/



	/**
	* openHelpWin(strHelpFile)
	* This function open the help window in another window
	**/
	var HelpWin;
	function openHelpWin(strHelpFile) {
		// Opens a help window that is the right size
		// for the user's screen.
		var strHeight = .95 * screen.availHeight;
		var strWidth = .60 * screen.availWidth;
		var strTop = 0; 
		var strLeft = 0;//screen.width - strWidth-10;
		var strWindowSettings = "toolbar=no,location=no,"+
				"directories=no,status=no,menubar=no,"+
				"scrollbars=yes,resizable=yes,copyhistory=no,"+
				"width="+strWidth+",height="+strHeight+","+
				"top="+strTop+",left="+strLeft;
				alert(strHelpFile);
		(HelpWin&&!HelpWin.closed)
				?HelpWin.focus()
				:HelpWin=window.open(
							strHelpFile,
							"HelpWin",strWindowSettings);
				
	}


	/**
	* openAboutWin()
	* This function open the help window in another window
	**/
	var AboutWin;
	function openAboutWin() {
		// Opens a About window that is the right size
		// for the user's screen.
		var strHeight = 400;
		var strWidth = 500;
		var strTop = (screen.availHeight - strHeight) / 2; 
		var strLeft = (screen.availWidth - strWidth) / 2;
		var strWindowSettings = "toolbar=no,location=no,"+
				"directories=no,status=no,menubar=no,"+
				"scrollbars=yes,resizable=no,copyhistory=no,"+
				"width="+strWidth+",height="+strHeight+","+
				"top="+strTop+",left="+strLeft;
		(AboutWin&&!AboutWin.closed)
				?AboutWin.focus()
				:AboutWin=window.open(
							"about.asp",
							"AboutWin",strWindowSettings);
				
	}


	/**
	* selectNewProfile()
	* This function will clear the profile selection and
	* set the form and tree frames back to their default
	* state - which asks the user which profile to select.
	**/
	function selectNewProfile(qstr) {
		try {
			window.top.TitleFrame.setVisibility("UserAndProfileInfo",hidden);
			window.top.TitleFrame.ProfileInfo.innerHTML='No Profile';
			window.top.TreeFrame.document.URL='LifeExpectTree.ASP?Reset=1&'+qstr;
			window.top.FormFrame.document.URL='LifeExpectForm.ASP?Reset=1&'+qstr;
		} 
		catch (e) {
			//Ignore all errors
		}
	}

	/**
	* makeDots()
	* Makes the little progress dots for the life calculation wait screen
	**/
	function makeDots(){
		LTDoc=window.top.TreeFrame.document;
		if (document.all && LTDoc.all.item("dots")) {
			// Wingding n is a black square, 6 is an hourglass (you could also use a standard bullet: •
			LTDoc.all.item("dots").innerHTML=LTDoc.all.item("dots").innerHTML + "|";
			setTimeout("makeDots()",400);
		}
	}



	/**
	* showAccountInfo()
	* This function is called from the navigation buttons.
	* It will cause the TreeFrame to display the account
	* information.  If there is no current account, the
	* ASP program will handle that problem.
	**/
	function showAccountInfo() {
		try {
			window.top.TreeFrame.document.URL='LifeExpectTree.ASP?ACTION=AccountInfo';
		} 
		catch (e) {
			//Ignore all errors
		}
	}

	/**
	* logOut()
	* This function is called from the navigation buttons.
	* It clears the User and Profile information from the 
	* screen, empties the current user information, and sets
	* the treeFrame back to the login scren.
	**/
	function logOut() {
		try {
			window.top.TitleFrame.setVisibility("ActiveProfileLinks",hidden);
			window.top.TitleFrame.setVisibility("UserAndProfileInfo",hidden);
			window.top.TitleFrame.CurrentUser.innerHTML='Logged Out';
			window.top.TitleFrame.document.URL='LifeExpectTree.ASP?ACTION=Log Out';
			parent.MainFrames.cols = "*,0,0";
			window.top.document.location.reload();
			selectNewProfile('<%=request.querystring%>');
		} 
		catch (e) {
			//Ignore all errors
		}

	}

	/**
	* logIn()
	* This puts the username in the title bar.  All the
	* meat of logging in and logging out is handled in 
	* ASP on the server side.
	**/
	function logIn(strUserName) {
		//No Action - just display stuff
        try {
			//window.top.TitleFrame.setVisibility("UserAndProfileInfo",visible);
			window.top.TitleFrame.setVisibility("ActiveProfileLinks",visible);
			window.top.TitleFrame.setVisibility("UserAndProfileInfo",hidden);
			window.top.TitleFrame.CurrentUser.innerHTML=strUserName;
			parent.MainFrames.cols = "*,500,0";
	}
		catch (e) {
			//Ignore all errors
		}
	}
	
	/**
	* calculateProfile()
	* This function is called form the navigation buttons.
	* It checks to see if a profile is selected and then
	* either displays a warning or opens the calculation
	* validation screen.
	**/
	function calculateProfile() {
		try {
			var sProfileInfo = new String(window.top.TitleFrame.ProfileInfo.innerHTML);
			if (sProfileInfo.indexOf('No Profile') != -1) {
				alert("You must select a profile before you can perform calculations");
				selectNewProfile()
			} else {			
				//This function actually just starts up the Calculation Approval screen
				window.top.FormFrame.document.URL='LifeExpectForm.ASP?ACTION=Calculate';
			}
		} 
		catch (e) {
			//Ignore all errors
		}
	}

// END NAVIGATION / HEADER SCRIPTS

/***********************************************************
************************************************************
	Profile Searching Scripts
		
	The next couple scripts enable profile searching
	and filtering.  The user can use search criteria
	to remove items from the profile list.  Only 
	un-selected items will be removed from the list.
************************************************************
************************************************************/
	
	/**
	* enableProfileButtons
	* Enables and disables profile buttons based on the number
	* of items selected in the profile list
	**/
	function enableProfileButtons(objProfiles) {
		// Determine the number of items selected
		var numSelected=0;
		for (var i=0; i<objProfiles.length; i++) {
			if (objProfiles[i].selected) numSelected++;
		}
		try {
			switch (numSelected) {
			case 0:
				break;
			case 1: 
				getObject("OpenButton").style.display  ='block';
				getObject("DeleteButton").style.display='block';
				getObject("BatchDownloadButton").style.display ='none';
				getObject("BatchUploadButton").style.display  ='none';
				getObject("BatchProcessButton").style.display ='none';
				break;
			default: // More than 1 selected
				getObject("OpenButton").style.display  ='none';
				getObject("DeleteButton").style.display='none';
				getObject("BatchDownloadButton").style.display ='block';
				getObject("BatchUploadButton").style.display  ='block';
				getObject("BatchProcessButton").style.display ='block';
				break;
			}
		} catch (e) {
			throw e;
		}
		window.status = numSelected+' Profiles Selected...'
	}

	/**
	* validateBatchProcess(nAvailableCalcs)
	* Determines if the user has sufficient available calcualtions to do the batch
	* processing and gives an alert if not allowed.  Otherwise starts the processing
	* approval window in the form frame.
	**/
	function validateBatchProcess(nAvailableCalcs) {
		var nSelectedProfiles = 0;
		var sProfileIds = "";
		var objActiveProfiles = getObject("ProfileList");   // The visible profiles
		for (var i=0; i<objActiveProfiles.length; i++) {
			var objItem = objActiveProfiles[i]
			if (objItem.selected) {
				nSelectedProfiles++;
				sProfileIds = sProfileIds + '|' + objItem.profileid
			}
		}	
		if (nSelectedProfiles>nAvailableCalcs) {
			alert("You have selected "+nSelectedProfiles+" profiles but your account "+
				"has only "+nAvailableCalcs+" calculations\n remaining.  Please remove " +
				(nSelectedProfiles - nAvailableCalcs) + " profiles from the list.");
		} else {
			window.top.FormFrame.document.URL='LifeExpectForm.ASP?Action=APPROVE BATCH PROCESS&ProfileIds='+sProfileIds;
		}
	}


	/**
	* filterProfiles
	* Searches through the profile list for items matching
	* the search criteria. Removes any non-matching items
	* from the list, unless they are already selected.
	**/
	function filterProfiles() {
		var bShowAll = false;
		if (arguments.length>0) {bShowAll = arguments[0];}
			

		// Determine the number of items selected
		var objItem;

		var objActiveProfiles = getObject("ProfileList");   // The visible profiles
		var objBackupProfiles = getObject("ProfileBackup"); // Backup Parking for all Profiles
		var strNameSearch     = getObject("NameSearch").value;
		var aItemsToRemove    = new Array();
		var aItemsToAdd       = new Array()
		
		// Bail out if there are not at least two characters in the search string 
		// and there are over 500 items in the list
		if (strNameSearch.length<3 && objBackupProfiles.length>500) return;
		
		// Escape any special characters
		var re = /([\\\^\$\*\+\?\.\(\)\|\{\}\[\]])/ig;
		strNameSearch  = strNameSearch.replace(re,"\\$1");

		// Allow "*" to mean wildcards on the Name Search
		strNameSearch = strNameSearch.replace(/\\\*/g,".*");

		// Define the regular expressions
		//var reName = new RegExp(strNameSearch,'i'); // Match anywhere
		var reName = new RegExp('^'+strNameSearch,'i'); // Force match to start of string		

		// Remove any un-selected, non-matching profiles from the active 
		// profiles list. Need to work downwards because the locations 
		// change if i delete from the beginning of the list.
		for (var i=0; i<objActiveProfiles.length; i++) {
			var objItem = objActiveProfiles[i]
			if (!objItem.selected) {
				if (!reName.exec(objItem.profilename)) {
					aItemsToRemove.push(i)
				}
			}
		}
		
		// Loop through the "All Profiles" list and add anything matching
		// to the active profile list
		for (var i=0; i<objBackupProfiles.length; i++) {
			var objItem = objBackupProfiles[i]
			if (reName.exec(objItem.profilename)) {
				aItemsToAdd.push(i)
			}
		}

		
		var nTotalItems = objActiveProfiles.length + objBackupProfiles.length;
		var nFinalSize = objActiveProfiles.length - aItemsToRemove.length + aItemsToAdd.length
		var nTotalMove = aItemsToRemove.length + aItemsToAdd.length;
		
		if (nTotalItems==0) {
			var warning = getObject('ProfileListWarning');
			warning.innerHTML = "The current filter conditions return no records.<br> "  +
								"Please change the dates and try again."		
			getObject('ProfileList').style.width=300;
		} else if (!bShowAll && nFinalSize>500) {
			var warning = getObject('ProfileListWarning');
			warning.innerHTML = "Please add more filter criteria, or <a href='javascript:filterProfiles(true);'>" + 
			                    "click here</a> to see all "+ nFinalSize +" records.<br>" +
			                    "Note that viewing more than 500 profiles will be slow."
			warning.style.display = "block";
			getObject('ProfileList').style.width=300;
		} else {
			getObject('ProfileListWarning').style.display = "none";
			document.body.style.cursor = "wait";
			window.status = "Moving " + nTotalMove + " items to return a list of " + nFinalSize 
			for (i in aItemsToRemove.reverse()) {moveProfileOption(objActiveProfiles,objBackupProfiles,aItemsToRemove[i]);}
			window.status = "Adding " + aItemsToAdd.length + " items to return a list of " + nFinalSize
			for (i in aItemsToAdd.reverse()) {moveProfileOption(objBackupProfiles,objActiveProfiles,aItemsToAdd[i]);}
			document.body.style.cursor = "default";
			getObject('ProfileList').style.width='auto';
			window.status = ""
		}		
		//alert("Finished")
		enableProfileButtons(objActiveProfiles);
	}
	
	// Helper function to move a profile option from one list to another
	function moveProfileOption(objList1, objList2, i) {
		var objItem = objList1[i];
		//alert("Moving " + objItem.text);
		//window.status = "Moving item "+i+" from "+objList1.name+" to "+ objList2.name
		var objNewItem = document.createElement('option');
		try {
			objNewItem.text        = objItem.text ;
			objNewItem.value       = objItem.value ;
			objNewItem.profileid   = objItem.profileid;
			objNewItem.profilename = objItem.profilename;
			objNewItem.calculated  = objItem.calculated;
			objNewItem.created     = objItem.created ;
		} catch (e) {
			window.status = "Error moving item "+i+" from "+objList1.name+" to "+ objList2.name+": "+e.description;
		}
		try {
			objList2.add(objNewItem); // IE only
		} catch(ex) {
			objList2.add(objNewItem, null); // standards compliant; doesn't work in IE
		}
		//objList2[objList2.length-1].selected=1;
		objList1.remove(i);
	}
	
	// Helper function for numerical sort
	function desc(a,b){
		return(b-a)
	}	




	/**
	* showProperties(obj)
	* Displays the properties of the requested object
	**/
	function showProperties(obj) {
		// Determine the number of items selected
		alert('Showing '+obj);
		var p=0;
		var strout='<hr><table><tr>';
		var colnum=0;
		for (p in obj) {
			try {
				strout = strout + "<td>" + p + "</td><td>=</td><td>" + eval("obj."+p+";") + "</td>";
				if (++colnum>2) {
					strout=strout+"</tr><tr>";
					colnum=0;
				}
			} catch (e) {break;}
		}
		strout = strout + "</tr></table>";
		document.write(strout);
	}


/***********************************************************
************************************************************
  	Form Frame Scripts
		
	The next several scripts are useful in conjunction with
	the Form Frame in the LifeExpect Web Program
************************************************************
************************************************************/

	/**
	* isFormChanged
	* This subroutine checks to see if the overview form 
	* in the FormFrame has changed, and returns true if 
	* it has, false if it has not
	**/
	function isFormChanged() {
		var obj1;
		var obj2;
		//alert("Looking for changes");
		if (getObject("oldName").value != getObject("newProfileName").value) {
			return true;
		}
		if (getObject("oldGender").value == "Male" && !getObject("Gender")(0).checked
		 || getObject("oldGender").value != "Male" && getObject("Gender")(0).checked) {
			return true;
		}
		if (getObject("oldBirthday").value != getObject("Birthday").value) {
			return true;
		}
		return false;
	}
	
	/**
	* enableFormActions()
	* This subroutine is used to enable and disable the
	* buttons and links in the form frame - preventing the user
	* from pushing things that they are not supposed to.  It uses 
	* the form's global variable 'document.hasUnsavedChanges' 
	* to determine if the buttons should be enabled
	**/
	function enableFormActions() {
		try {
			var obj;
			var coll;
			var doc = window.top.FormFrame.document;
			
			//First enable/disable all buttons except SAVE and NEW
			if ( (doc.all && (coll=doc.all.tags('INPUT'))) 
			   ||(doc.getElementsByTagName && (coll=doc.getElementsByTagName('INPUT'))))
			{
				for (i=0; i<coll.length; i++) {
					obj=coll.item(i);
					//alert(obj.type);
					if (obj.type == "submit" || obj.type == "button") {
						if (obj.value != "Save" && obj.value != "New Profile") {
							//alert("Disabling " + obj.name + " " + obj.value);
							obj.disabled = document.hasUnsavedChanges;
						}
					}
				}
			}
			
			//Now enable/disable all of the links
			if ( (doc.all && (coll=doc.all.tags('A'))) 
			   ||(doc.getElementsByTagName && (coll=doc.getElementsByTagName('A'))))
			{
				for (i=0; i<coll.length; i++) {
					obj=coll.item(i);
					//alert("Disabling Link " + obj.href + ", " + obj.hrefHolder);
					if (document.hasUnsavedChanges) {
						if (!obj.isAlreadyDisabled) {
							obj.innerHTMLHolder = obj.innerHTML;
							obj.innerHTML="<font color=gray>"+obj.innerHTML+"</font>";
							obj.hrefHolder = obj.href;
							obj.href="javascript: alert('Please save your changes to the profile header before you continue.');";
							obj.onmouseover = "this.style.color='red';";
							obj.isAlreadyDisabled = true;
						}
					} else {
						obj.href = obj.hrefHolder;
						obj.innerHTML = obj.innerHTMLHolder;
						obj.onmouseover="";
						obj.isAlreadyDisabled=false;
					}
				}
			}
		}
		catch (e) {
			//Ignore all errors
			//alert("Error enabling and disabling buttons on the user form: " + e);
		}		
	}
// END FORM FRAME SCRIPTS


/***********************************************************
************************************************************
	Generic Helper Scripts
		
	The next several scripts are useful to more than
	one of the forms and could be easily ported to other
	programs.
************************************************************
************************************************************/

	/**
	* forceFraming()
	* This function forces any file that calls it to
	* appear in the proper frameset for this program
	**/
	function forceFraming() {
		if (window.top.location.href == self.location.href) {
			window.top.location.href = "index.htm"
		}
	}

	//Call this subroutine whenever anyone includes this document... UNLESS
	//the document has had ForceFraming specifically turned off...
	if (window.AllowNoFrames!=1) forceFraming();
	
	/**
	* getObject(String ObjectName)
	* Gets a named tag object independent of browser version
	**/
	function getObject(strItemName) {
		if(d.all && (obj=d.all[strItemName]) 
		   || d.layers && (obj=d.layers[strItemName]) 
		   || d.getElementById && (obj=d.getElementById(strItemName))) {
			return obj;
		}
		return null;
	}
	
	/**
	* setVisibility(strItemName, strMode)
	* This function will toggle visibility
	* of a tag.
	**/
	function setVisibility(strItemName,strMode) {
        //alert(strItemName + ' is ' + getObject(strItemName).style.display);
        getObject(strItemName).style.display = strMode;
        //alert(strItemName + ' set to ' + getObject(strItemName).style.display);
	}

	/**
	* newAlert(prompt,buttons,title)
	* This function will display a nicer alert box 
	* if the user is using Iternet Explorer.  Courtesy
	* of  Peter Belesis and Copyright 1999-2001 
	* INT Media Group, Inc. 
	* http://www.webreference.com/dhtml/column22/js-vbNewjs.html
	* 
	* 	newAlert() takes 3 arguments:
	* 		mess    - a string to be displayed as the message to the user 
	* 		buttons - the button and icon definition, based on the msgbox function
	* 		title   - a string to be displayed in the dialog title bar 
	*
	*   Button Values (sum the following)
	* 	Constant           Value	Description
	*   vbOKOnly	       0	    Display OK button only.
	*   vbOKCancel	       1	    Display OK and Cancel buttons.
	*   vbAbortRetryIgnore 2	    Display Abort, Retry, and Ignore buttons.
	*   vbYesNoCancel      3	    Display Yes, No, and Cancel buttons.
	*   vbYesNo	           4	    Display Yes and No buttons.
	*   vbRetryCancel      5	    Display Retry and Cancel buttons.
	*   vbCritical         16	    Display Critical Message icon.
	*   vbQuestion         32	    Display Warning Query icon.
	*   vbExclamation      48	    Display Warning Message icon.
	*   vbInformation      64	    Display Information Message icon.
	*   vbDefaultButton1   0	    First button is default.
	*   vbDefaultButton2   256	    Second button is default.
	*   vbDefaultButton3   512	    Third button is default.
	*   vbDefaultButton4   768	    Fourth button is default.
	*   vbApplicationModal 0	    Application modal; the user must respond to the message box before continuing work in the current application.
	*   vbSystemModal      4096	    System modal; all applications are suspended until the user responds to the message box.
	**/
	function newAlert(prompt,buttons,title) {
		var IE4 = document.all;
		(IE4) ? makeMsgBox(prompt,buttons,title) : alert(prompt);
	}	
	
	/**
	* newConfirm(prompt, buttons, title)
	* This function will display a nicer confirm box 
	* if the user is using Iternet Explorer.  Courtesy
	* of  Peter Belesis and Copyright 1999-2001 
	* INT Media Group, Inc. 
	* http://www.webreference.com/dhtml/column22/js-vbNewjs.html
	* 
	*	newConfirm() takes 3 arguments:
	* 		mess    - a string to be displayed as the message to the user 
	* 		buttons - the button and icon definition, based on the msgbox function
	* 		title   - a string to be displayed in the dialog title bar 
	*
	*   Button Values (sum the following)
	* 	Constant           Value	Description
	*   vbOKOnly	       0	    Display OK button only.
	*   vbOKCancel	       1	    Display OK and Cancel buttons.
	*   vbAbortRetryIgnore 2	    Display Abort, Retry, and Ignore buttons.
	*   vbYesNoCancel      3	    Display Yes, No, and Cancel buttons.
	*   vbYesNo	           4	    Display Yes and No buttons.
	*   vbRetryCancel      5	    Display Retry and Cancel buttons.
	*   vbCritical         16	    Display Critical Message icon.
	*   vbQuestion         32	    Display Warning Query icon.
	*   vbExclamation      48	    Display Warning Message icon.
	*   vbInformation      64	    Display Information Message icon.
	*   vbDefaultButton1   0	    First button is default.
	*   vbDefaultButton2   256	    Second button is default.
	*   vbDefaultButton3   512	    Third button is default.
	*   vbDefaultButton4   768	    Fourth button is default.
	*   vbApplicationModal 0	    Application modal; the user must respond to the message box before continuing work in the current application.
	*   vbSystemModal      4096	    System modal; all applications are suspended until the user responds to the message box.
	**/
	function newConfirm(prompt,buttons,title) {
		var IE4 = document.all;
		if (IE4) {
			retVal = makeMsgBox(prompt,buttons,title);
			retVal = (retVal==6 || retVal==1 || retVal==5); // Yes, Ok or Ignore
		}
		else {
			retVal = confirm(mess);
		}
		return retVal;
	}

	/**
	* newInput(prompt, title, default)
	* This function will display a nicer input box 
	* if the user is using Iternet Explorer.  Courtesy
	* of  Peter Belesis and Copyright 1999-2001 
	* INT Media Group, Inc. 
	* http://www.webreference.com/dhtml/column22/js-vbNewjs.html
	* 
	*	newInput() takes 3 arguments:
	* 		prompt  - a string to be displayed as the message to the user 
	* 		title   - a string to be displayed in the dialog title bar 
	* 		default - the default value for the box
	**/
	function newInput(prompt,title,def) {
		var IE4 = document.all;
		(IE4) ? retVal=makeInputbox(prompt,title,def) : retVal =input(prompt,def);
		return retVal;
	}	
	
	//--------------------------------------------------
	// compute_age(strBirthday)
	//
	// Convert a date string in the format MM/DD/YYYY
	// into a fractional age (YY.pct) that accounts for
	// leap years, etc.  The fractional age can then 
	// be converted back to a birthday using the the date
	// that the age was stored.  This is a little klugey
	// but it allows users to enter dates without having
	// to change the database at all.
	//--------------------------------------------------
	function compute_age(strBirthday) {
		var val=strBirthday.split(/\//g);
		//alert(val)
		var bd_month = parseInt(val[0]-1);
		var bd_day   = parseInt(val[1]);
		var bd_year  = parseInt(val[2]);
		if (bd_year<100) bd_year = 1900+(bd_year);

		var birthdate = new Date(bd_year, bd_month, bd_day);
		//alert(birthdate.toLocaleDateString())
		
		var now = new Date();
		var now_month = now.getMonth();
		var now_day   = now.getDate();
		var now_year  = now.getYear();

		var a = new Date(bd_year, now_month, now_day);
		var b = new Date(bd_year, 0, 1);
		var c = new Date(bd_year, 11, 31);
		
		var FractionalAge = (a-birthdate) / (c-b);
		var Age = (now_year - bd_year) + FractionalAge;
		Age = Math.round(Age*100)/100;
		return Age
	}
	

	/*------------------------------------------------------------------------------------
	Function:  getValue
	Purpose:   Used to get the value of items in the form.  Although the value of most 
			form items can be accessed with ELEMENT.value, this does not work for all
			types of items (SELECT, CHECKBOX, RADIO).
	           
			Note that if the value of the element includes more than one item, a list
			will be returned, separated by commas.
	           
	Arguments: ELEM - the form object from which to get a value.
	Returns:   (None)
	------------------------------------------------------------------------------------*/
	function getValue(ELEM) {

		var strValue = '';
			
		if (ELEM) {
		
			// If the element is a select list, then it has OPTIONS
			if (ELEM.options) {
				for (var j=0; j<ELEM.options.length;j++) {
					if (ELEM.options(j).selected) {
						strValue = ELEM.options(j).value + (strValue.length>0?',':'');
					}
				}
			}
			
			//If the element has length then it is a collection - probably checkboxes
			else if (ELEM.length) {					
				for (var j=0;j<ELEM.length;j++) {
					if (ELEM[j].status) {
						strValue = ELEM[j].value + (strValue.length>0?',':'');
					}
				}
			}
			
			//If it is a span or a div
			else if (ELEM.tagName.match(/^(DIV|SPAN|P)$/i)) {
				strValue = ELEM.innerHTML;
			} 
			
			//If it was just a normal
			else {
				strValue = ELEM.value;
			}
		}
		
		return strValue;
		
	}


	document.hasUnsavedChanges=false;
	function saveChangesIfNeeded() {
		try {
			if (document.hasUnsavedChanges) {
				event.returnValue = 
				       "You made changes to the current profile but did not save them.\n"+
					   "Choose Cancel in this dialogbox then click Save to save changes."
				return;
			} else {
				return;
			} 
		} catch (e) {
			alert('Warning - Error in saveChangesIfNeeded:\n\n'+e.description);
			return;
		}
	}
	
	function showLifeTable(strProfileName) {
		//LifeTableWindow=window.open('','LifeTableWindow','toolbar=no,status=yes,scrollbars=yes,resizable=yes,width=400,height=600');	
		//window.top.FormFrame.document.URL='LifeExpectForm.ASP?ParamID=Overview';
		window.top.TreeFrame.document.write(
			'<table border=0 height=100% width=100%>'+
			'<tr><td valign=center align=center>'+
			'<h3>Calculating Life Table for '+strProfileName+' ...</h3>'+
			'<table bgcolor=#dddddd cellpadding=3 border=1 width=350>'+
			'<tr><td width=350><font size=5 face="Arial Narrow" color=navy>'+
			'<b><div id=dots></div></b></font></td></tr></table></td></tr>'+
			'</table>');			
			//'<'+'script'+'>top.FormFrame.makeDots();<'+'/script'+'>'
		window.top.TitleFrame.makeDots();
	}
		

//END XML TREE SCRIPTS	
//</SCRIPT>


