// variable to track if changes made to current form when switching forms
var formChanged = false;

// variables used for validation
// confirms integer >= 0
var regex_int = /^(\d)+$/;
// confirms integer >= 1
var regex_posInt = /^[1-9](\d)*$/;
// comma-separated list of email addresses, can include aliases with no '@blah.com' component
var regex_emailList = /^[\w_-]+(\.[\w_-]+)*(@[\w_-]+(\.[\w_-]+)*\.\w{2,3})?(,[ ]*[\w_-]+(\.[\w_-]+)*(@[\w_-]+(\.[\w_-]+)*\.\w{2,3})?)*$/;
// single email address, alias with no '@blah.com' component OK
var regex_email = /^[\w_-]+(\.[\w_-]+)*(@[\w_-]+(\.[\w_-]+)*\.\w{2,3})?$/;
// string containing function call
var regex_function = /^.*\(.*\);$/;
// comma-separated list of values
var regex_values = /^[^,]+(,[^,]+)*$/;
// form name regular expressionvar regex_form_name = /[\/:[\]*\\]/;
var regex_form_name = /[`~!@#\$%\^&\*\(\)=\+\?,\.<>]/;//ssaha    
// goes to ESI employee home page
function goToEmployeePage()
{
	if (formChanged)
	{
		if (confirm("Are you sure you want to leave this page?\n" + 
				"You will lose any unsaved modifications to the current form."))
		{
			location.href = "../home.jsp";
		}
	}
	else
	{
		location.href = "../home.jsp";
	}
}

// goes to DynamicFormEdit servlet and loads FormBean data for selected form
function loadForm()
{
	var selectedForm = document.formEdit.selectedForm.value;
	var formName = document.formEdit.name.value;
	var loadForm = true;
	if (formChanged)
	{
		if (!confirm("Are you sure you want to change forms?\n" + 
				"You will lose any unsaved modifications to the current form."))
		{
			loadForm = false;
		}
	}
	if (loadForm)
	{
		if (selectedForm == "")
			location.href = "/employee/admin/DynamicFormEdit?requestType=blankForm";
		else
			location.href = "/employee/admin/DynamicFormEdit?requestType=loadForm&formName=" + selectedForm;
	}
	else
	{
		// reset selected element to form we were editing
		var formList = document.formEdit.selectedForm;
		for (var i=0; i<formList.options.length; i++)
		{
			if (formList.options[i].text == formName)
				formList.options[i].selected = true;
		}
	}
}


function isFormLogonRequired()
{
    var logonRequired = false;
    var logonReqRadio = document.formEdit.logonRequired;
    for (i=0; i<logonReqRadio.length; i++)
    {
        if (logonReqRadio[i].checked) logonRequired = logonReqRadio[i].value;
    }
    
    return logonRequired;
}


// checks status of logonRequired and confirmationEmail and shows or hides senderEmail and
// userEmailQuestion divs accordingly. Also handles show/hide of submittedByDatabaseColumnId field since this
// is only used if the form requires logon.
function toggleEmailDivs()
{
	var logonRequired = isFormLogonRequired();

	var confirmationEmail = false;
	var confEmailRadio = document.formEdit.confirmationEmail;
	for (i=0; i<confEmailRadio.length; i++)
	{
		if (confEmailRadio[i].checked) confirmationEmail = confEmailRadio[i].value;
	}

	if (logonRequired == "true") {
		document.getElementById("userEmailQuestionDiv").style.display="none";
		document.getElementById("senderEmailDiv").style.display="none";
		document.getElementById("submittedByDatabaseColumnIdDiv").style.display="block";
	}
	else if (confirmationEmail == "true") {
		document.getElementById("userEmailQuestionDiv").style.display="block";
		document.getElementById("senderEmailDiv").style.display="block";
		document.getElementById("submittedByDatabaseColumnIdDiv").style.display="none";
	}
	else {
		document.getElementById("userEmailQuestionDiv").style.display="none";
		document.getElementById("senderEmailDiv").style.display="block";
		document.getElementById("submittedByDatabaseColumnIdDiv").style.display="none";
	}
	
	// Call this to update (in this case) the "Unique Record" (advanced) question. This question
	// is used to ID the question that contains the unique value we should use to check the DB
	// for existing entries. If login required or we're not "Importing to DB", don't show this question.
	updateSubmissionURL(logonRequired);
}


// toggles the specified advanced options div between show and hide
function toggleAdvancedOpts(divId) {
	var advOptsDiv = document.getElementById(divId);
	if (advOptsDiv.style.display == "none") {
		advOptsDiv.style.display = "block";
		document.forms[0].advOptsButton.value = "Hide ...";
	}
	else {
		advOptsDiv.style.display = "none";
		document.forms[0].advOptsButton.value = "Edit ...";
	}
}

// checks what type of question we are editing and shows/hides various divs accordingly
function toggleTypeDivs() {
	var questType = document.questEdit.questType.value;
	// get each div and decide if it should be hidden based on questType
	var currentDiv = document.getElementById("allTypes");
	if (questType == "") currentDiv.style.display="none";
	else currentDiv.style.display="block";
	currentDiv = document.getElementById("allButInfoAndSep");
	if (questType == "info" || questType == "separator" || questType == "") currentDiv.style.display="none";
	else currentDiv.style.display="block";
	currentDiv = document.getElementById("defaultAnsBlockText");
	if (questType == "text" || questType == "textarea") currentDiv.style.display="block";
	else currentDiv.style.display="none";
	currentDiv = document.getElementById("separator");
	if (questType == "separator") currentDiv.style.display="block";
	else currentDiv.style.display="none";
	currentDiv = document.getElementById("textAndTextarea");
	if (questType == "text" || questType == "textarea") currentDiv.style.display="block";
	else currentDiv.style.display="none";
	currentDiv = document.getElementById("textarea");
	if (questType == "textarea") currentDiv.style.display="block";
	else currentDiv.style.display="none";
	currentDiv = document.getElementById("multiValue");
	if (questType == "radio" || questType == "checkbox" || questType == "select") currentDiv.style.display="block";
	else currentDiv.style.display="none";
	currentDiv = document.getElementById("radioAndCheckbox");
	if (questType == "radio" || questType == "checkbox") currentDiv.style.display="block";
	else currentDiv.style.display="none";
	currentDiv = document.getElementById("advAllTypes");
	if (questType == "") currentDiv.style.display="none";
	else currentDiv.style.display="block";
	currentDiv = document.getElementById("advAllButInfoAndSep");
	if (questType == "info" || questType == "separator" || questType == "") currentDiv.style.display="none";
	else currentDiv.style.display="block";
	currentDiv = document.getElementById("advMultiValue");
	if (questType == "radio" || questType == "checkbox" || questType == "select") currentDiv.style.display="block";
	else currentDiv.style.display="none";
	currentDiv = document.getElementById("advTextAndTextarea");
	if (questType == "text" || questType == "textarea") currentDiv.style.display="block";
	else currentDiv.style.display="none";
}

// definition of SubmitAction object type - 'new' will create a new instance. 'submitAction' is the type
// of action processed when form is submitted, 'submitURL' is the URL of the java servlet which will
// process the action specified.
function SubmitAction(submitAction, submitURL) {
	this.submitAction = submitAction;
    this.submitURL = submitURL;
}

// definition of ValidExp object type - 'new' will create a new instance. 'regexpr' is the regular
// expression, 'label' is the text to display to user, and 'warning' is the text to display when
// warning the user if an entry is invalid.
function ValidExp(regexpr, label, warning) {
	this.regexpr = regexpr;
	this.label = label;
	this.warning = warning;
}

// Makes input for a custom regular expression readonly or not based on whether user has selected 'Other'.
// Also loads correct regular expression into the validationExpOther textarea
function updateValidationExpOther() {
	var validExpOther = document.questEdit.validationExpOther;
	var validExpOtherEdit = document.questEdit.editValidExpOther;
	var selectedIndex = document.questEdit.validationExp.selectedIndex;
	if (selectedIndex == 0) {
		validExpOther.value = "";
		validExpOther.readOnly = true;
		validExpOtherEdit.disabled = true;
	}
	else if ((selectedIndex > 0) && (selectedIndex <= validExps.length)) {
		validExpOther.value = validExps[selectedIndex-1].regexpr;
		// if last item in list is selected, this is 'Other', so do not disable field
		if (selectedIndex == validExps.length) {
			validExpOther.readOnly = false;
			validExpOtherEdit.disabled = false;
		}
		else {
			validExpOther.readOnly = true;
			validExpOtherEdit.disabled = true;
		}
	}
}

// changes the validation warning if the user selects a new standard validation expression type from list
function changeValidWarning() {
	var validWarning = document.questEdit.validationWarning;
	validWarning.value = "";
	// subtract one to selected index to account for "Please select ..." at top - no corresponding entry in array
	var selectedIndex = document.questEdit.validationExp.selectedIndex - 1;
	if ((selectedIndex >= 0) && (selectedIndex < validExps.length)) {
		validWarning.value = validExps[selectedIndex].warning;
	}
}

function tableNameDefault()
{
	var frmname = document.getElementById("name").value;
	
	//parse the form name so that it meets the MySql naming convention
	/* Max length 64
	 - No ., /, \, or the backtic (`) characters
     - At least one non numeric char.
	 - Allow user to enter upper/lower case, but we will do a tolower() before saving the name
	 - Possibility: take form name and 
	 1) make all lowercase, 
	 2) replace any illegal chars with the underscore char. 
	 3) remove any spaces (even though allowed) and use this string as the default table name.
	*/
	//to lowercase
	frmname = frmname.toLowerCase();
	
	//remove all illegal characters[., /, \, '`']
	var patt1=/[.\/\\\`]/g;
	frmname = frmname.replace(patt1,"_");
	
	//remove spaces
	frmname = frmname.replace(/\s/g, "");
	
	return frmname;
}

// JLW - changes the hibernate Mapping XML if the user selects 'Yes' for Auto Generation
// of the mapping text
function updateAutoGen()
{
	var hibernateMapping = document.getElementById("hibernateMappingXML");
	var autoMapping = document.forms[0].autoGenMapping[0].checked;
	var hibernatetablename = document.forms[0].hibernateTableName.value;
	
	if (document.forms[0].autoGenMapping[0].checked == true)
	{
		//disable the hibernateMappingXML textarea
		hibernateMapping.readOnly = true;
		hibernateMapping.disabled = true;
		
		//Show the table name textbox with the default form name
		document.getElementById("mappingTableName").style.display = "block";
		
		// Allow only a "view" of the data - not allowed to edit autogen mapping
		document.getElementById("hibernateMappingXMLView").style.display = "inline";
		document.getElementById("hibernateMappingXMLEdit").style.display = "none";
	}
	
	if (document.forms[0].autoGenMapping[1].checked == true)
	{
		//enable the hibernateMappingXML textarea
		hibernateMapping.readOnly = false;
		hibernateMapping.disabled = false;
		
		//Hide the table name textbox
		document.getElementById("mappingTableName").style.display = "none";
		
		// Allow full "edit" of the data - user wants to "manually" enter mapping XML
		document.getElementById("hibernateMappingXMLView").style.display = "none";
		document.getElementById("hibernateMappingXMLEdit").style.display = "inline";
	}
}

//JLW - when user selects question data type of String display
//text box to enter the length of the string
function toggleDatabaseColLength()
{
	var selectedIndex = document.getElementById("databaseDataType").selectedIndex;
	
	if ( (selectedIndex >= 0) && (document.getElementById("databaseDataType")[selectedIndex].value == "java.lang.String") )
		document.getElementById("typeLength").style.display = "block";
	else
		document.getElementById("typeLength").style.display = "none";
}

// JAF changes the submission URL if the user selects a new submission action from list
function updateSubmissionURL(logonRequired) {
	var submitURL = document.getElementById("submissionURL");
	
	var needFormLogon;
	if ( logonRequired == null)
	{
	     needFormLogon= isFormLogonRequired();
	}
	else
	{
	    needFormLogon = logonRequired;
	}
	
	// subtract one to selected index to account for "Please select ..." at top - no corresponding entry in array
	var selectedIndex = document.getElementById("submitAction").selectedIndex - 1;
	
	if ((selectedIndex >= 0) && (selectedIndex < submitActions.length)) {
		// if last item in list is selected, this is 'Other', so do not disable URL field, allow user to enter data
	 	if (selectedIndex == submitActions.length - 1) {
			submitURL.readOnly = false;
			submitURL.disabled = false;
		}
		else {  
		// other submit actions have pre-defined URLs so user is prevented from updating these values
			submitURL.value = submitActions[selectedIndex].submitURL;
			submitURL.readOnly = true;
			submitURL.disabled = true;
		}
	}
	if ( (selectedIndex >= 0) && ( (submitActions[selectedIndex].submitAction == "Import to Database") ||
		(submitActions[selectedIndex].submitAction == "Other"))) {
			document.getElementById("hibernateMappingXMLDiv").style.display = "block";
			document.getElementById("autogenhibernateMappingDiv").style.display = "block";
			document.getElementById("mappingTableName").style.display = "none";
			document.getElementById("duplicateRecordsStrategyDiv").style.display = "block";
			
			if ( needFormLogon == "true" )
	        {
	            // If logon Required, then we'll use userID from Session - so this Q doesn't apply
	            document.getElementById("duplicateRecordsUniqueDiv").style.display = "none";
	        }
	        else
	        {
	            // We're importing to DB or other and logon not required - so we need to know which question
	            // is the "uniquifier" for each form response (record)
	            document.getElementById("duplicateRecordsUniqueDiv").style.display = "block";
	        }
	        
	}
	else {
		document.getElementById("hibernateMappingXMLDiv").style.display = "none";
		document.getElementById("autogenhibernateMappingDiv").style.display = "none";
		document.getElementById("duplicateRecordsStrategyDiv").style.display = "none";

        // If we're not importing to DB or Other - this Q doesn't apply
		document.getElementById("duplicateRecordsUniqueDiv").style.display = "none";
	}
}

// Uses data in the questValues array to build the HTML for the values div, for multi-value question types
function buildValuesList() {
	var questType = document.questEdit.questType.value;
	if (questType == "radio" || questType == "select" || questType == "checkbox") {
		var values = document.getElementById("valuesDiv");
		var valuesHtml = "";
		for (var i=0; i<questValues.length; i++) {
			var val = questValues[i];
			if (val != null && val.display != null) {
				valuesHtml += '<div class="topBtmMarginSmall">';
				valuesHtml += 'Display Text: <input type="text" name="display' + i + '" size="24" value="' 
					+ val.display + '" onchange="changeDisplay(' + i + ');" />';
				valuesHtml += ' Value (optional): <input type="text" name="value' + i + '" size="24" value="' 
					+ val.value + '" onchange="changeValue(' + i + ');" />';
				if (questType == "checkbox") {
					if (val.isDefault) {
						valuesHtml += ' <input type="checkbox" name="isDefault' + i + 
							'" checked="checked" onclick="changeDefault(' + i + ');" /> Default';
					}
					else {
						valuesHtml += ' <input type="checkbox" name="isDefault' + i + '" onclick="changeDefault(' + i + ');" /> Default';
					}
				}
				else {
					if (val.isDefault) {
						valuesHtml += ' <input type="radio" name="isDefault" checked="checked" onclick="changeDefault(' + i + ');" /> Default';
					}
					else {
						valuesHtml += ' <input type="radio" name="isDefault" onclick="changeDefault(' + i + ');" /> Default';
					}
				}
				valuesHtml += ' <input type="button" name="delete' + i + '" value="Delete" onclick="deleteValue(' + i + ');" /><br />';
				valuesHtml += '</div>';
			}
		}
		if (valuesHtml.length > 0) {
			valuesHtml += '<div class="clear note">The \'Value\' field is used to return a different value';
			valuesHtml += ' in the user\'s response from the choices displayed. For example, you might want to';
			valuesHtml += ' display \'Early bird registration - price $150\' but only return \'150\'';
			valuesHtml += ' in the response.</div>';
		}
		values.innerHTML = valuesHtml;
	}
}

// updates value stored in questValues array for specified index
function changeValue(index) {
	var input = eval("document.questEdit.value" + index);
	questValues[index].value = input.value;
}

// updates display text stored in questValues array for specified index. Also updates linked questions
// div to reflect change.
function changeDisplay(index) {
	var input = eval("document.questEdit.display" + index);
	questValues[index].display = input.value;
	buildLinkedQuestsList();
}

// updates isDefault stored in questValues array for specified index
function changeDefault(index) {
	var input;
	questType = document.questEdit.questType.value;
	// if question type is checkbox, the isDefault inputs will be checkboxes
	if (questType == "checkbox") {
		input = eval("document.questEdit.isDefault" + index);
		questValues[index].isDefault = input.checked;
	}
	// otherwise the isDefault inputs are radio buttons
	else {
		// if only one radio button in group
		if (document.questEdit.isDefault.length == null) {
			questValues[index].isDefault = document.questEdit.isDefault.checked;
		}
		// if more than one radio button in group, turn off all others except selected one
		else {
			input = eval("document.questEdit.isDefault[" + index + "]");
			for (var i=0; i<questValues.length; i++) {
				if (questValues[i] != null) {
					if (i == index)	questValues[i].isDefault = true;
					else questValues[i].isDefault = false;
				}
			}
		}
	}
}

// sets the object in questValues array at specified index to null so it won't be used to build values
// list. Also rebuilds html for linked questions div to reflect change.
function deleteValue(index) {
	questValues[index] = null;
	buildValuesList();
	buildLinkedQuestsList();
}

// adds a new QuestionValue object to questValues array at next available index. Does not rebuild the
// html for linked questions div - this build is triggered when the user enters display text for the
// new option. Otherwise there is no text to display in div, might be confusing.
function addValue() {
	questValues[numValues] = new QuestionValue("","",false);
	// If this is not the first QuestionValue created, loop through questValues and find a non-null item.
	// Copy linkedQuests data (if any) to new QuestionValue but set display to 'hide' initially.
	var linksFound = false;
	if (numValues > 0) {
		var newLinks = questValues[numValues].linkedQuests;
		for (var i=0; !linksFound && i<numValues; i++) {
			if (questValues[i] != null && questValues[i].linkedQuests != null) {
				var links = questValues[i].linkedQuests;
				linksFound = true;
				for (var j=0; j<links.length; j++) {
					if (links[j] != null) {
						var questName = links[j].name;
						newLinks[j] = new LinkedQuestion(questName,"hide", "do not reset");
					}
				}
			}
		}
	}
	buildValuesList();
	var input = eval("document.questEdit.display" + numValues);
	input.focus();
	numValues += 1;
}

// Sets the value of the hidden input 'values', builds string using data in questValues array.
// This function is called from validateQuestion() so the input is set prior to form submission.
function setValues() {
	var vals = "";
	var firstEntry = true;
	if (questValues != null) {
		for (var i=0; i<questValues.length; i++) {
			if (questValues[i] != null) {
				// if value field has been set, use this value. If not, set value to same as display text
				if (questValues[i].value != null && questValues[i].value.length > 0) {
					if (firstEntry) vals += addEscapes(questValues[i].value) + "|";
					else vals += "," + addEscapes(questValues[i].value) + "|";
				}
				else {
					if (firstEntry) vals += addEscapes(questValues[i].display) + "|";
					else vals += "," + addEscapes(questValues[i].display) + "|";
				}
				vals += addEscapes(questValues[i].display);
				firstEntry = false;
			}
		}
	}
	document.questEdit.values.value = vals;
}

// adds escapes ('\') in front of comma and pipe characters that should not be separators 
// when building values string
function addEscapes(input) {
	var newString = "";
	if (input != null) {
		for (var i=0; i<input.length; i++) {
			var c = input.charAt(i);
            if (c == ',' || c == '|') newString += "\\" + c;
			else newString += c;
		}
	}
	return newString;
}

// sets the value of the hidden input 'defaultAnswer'. For multi-value types, the value is built using
// data in the questValues array. For text types, the value is taken from the defaultAnswerText form
// input. This function is called from validateQuestion() so the input is set prior to form submission.
function setDefaultAnswer() {
	var defAnswer = "";
	var questType = document.questEdit.questType.value;
	if (questType == "radio" || questType == "select" || questType == "checkbox") {
		var firstEntry = true;
		if (questValues != null) {
			for (var i=0; i<questValues.length; i++) {
				if (questValues[i] != null && questValues[i].isDefault) {
					// if value field has been set, use this value. If not, use display text
					if (questValues[i].value != null && questValues[i].value.length > 0) {
						if (firstEntry) defAnswer += questValues[i].value;
						else defAnswer += "," + questValues[i].value;
					}
					else {
						if (firstEntry) defAnswer += questValues[i].display;
						else defAnswer += "," + questValues[i].display;
					}
					firstEntry = false;
				}
			}
		}
	}
	else if (questType == "text" || questType == "textarea") {
		defAnswer = document.questEdit.defaultAnswerText.value;
	}
	document.questEdit.defaultAnswer.value = defAnswer;
}

/*
 Definition of LinkedQuestion object type - 'new' will create a new instance. 'name' is the question name. 
 The 'display' field is a string with a value of either 'show' or 'hide' depending on whether the question 
 should be visible for the current question value ('ignore' option is valid for checkboxes. 
 The 'fieldSetting' field defines the value to be displayed when the question is shown -- 'None Set', 'Default',
 'Do Not Reset'(leaves the current contents of the field alone). 
*/
function LinkedQuestion(name,display, fieldSetting) {
	this.name = name;
	this.display = display;
	this.fieldSetting = fieldSetting;
}

// parses XML that represents linked questions data, creates LinkedQuestion objects and puts in array
function parseLinkedQuestsXml() {
	var doc;
	// parse XML into DOM document object - IE has different method from other browsers
	if (linkedQuestsXml != null && linkedQuestsXml.length > 0) {
		if (typeof DOMParser != 'undefined') {
			var parser = new DOMParser();
			doc = parser.parseFromString(linkedQuestsXml, "text/xml");
		}
		else if (typeof ActiveXObject != 'undefined') {
			doc=new ActiveXObject("Microsoft.XMLDOM");
			doc.async="false";
			doc.loadXML(linkedQuestsXml);
	    }
	}
	if (doc != null) {
		//parse through document and create LinkedQuestion objects
		var options = doc.getElementsByTagName("option");
		if (options != null && questValues != null) {
			// cycle through values defined for this question and find matching options - then
			// set linked question data in QuestionValue objects
			for (var i=0; i<questValues.length; i++)
			{
				var displayText = questValues[i].display;	//optional value not there; use display
				var found = false;
				for (var j=0; !found && j<options.length; j++)
				{
					var option = options.item(j);
					var temp = option.getElementsByTagName("text").item(0).firstChild;
					if (temp != null)
					{
					   var optionText = temp.nodeValue;
					}
					else 
					{
					   var optionText = "";  // no display text for choice
					}
					if (optionText == displayText)
					{
						found = true;
						var questions = option.getElementsByTagName("question");
						if (questions != null)
						{
							// reset numLinks for next value - links arrays are parallel, so need to
							// start from 0 again
							numLinks = 0;
							
							// get data for each question, create new LinkedQuestion objects and add to
							// this QuestionValue object's array of linkedQuests
							for (var k=0; k<questions.length; k++)
							{
								var question  = questions.item(k);
								var questName = question.getElementsByTagName("name").item(0).firstChild.nodeValue;
								var display   = question.getElementsByTagName("display").item(0).firstChild.nodeValue;
								var fieldSettings = question.getElementsByTagName("fieldSetting");
								var fieldSetting = "do not reset";  // do not change field value
								if (fieldSettings.length != 0)
								{
									fieldSetting = fieldSettings.item(0).firstChild.nodeValue;
								}

								questValues[i].linkedQuests[numLinks] = new LinkedQuestion(questName, display, fieldSetting);
								numLinks += 1;
							}
						}
					}
				}
			}
		}
	}
	//build linked questions div html
	buildLinkedQuestsList();
}

// builds the HTML for the linked questions div using the array of QuestionValue objects
function buildLinkedQuestsList() {
	var qList     = document.getElementById ("questLink");
	var qTypeList = document.getElementById ("questTypeLink");
	var qType     = document.getElementById ("questType");

	if (questValues != null && questValues.length > 0)
	{
		var divHtml = "";
				   
	    if (qType[qType.selectedIndex].value == "checkbox")
	    {
    		divHtml += '<div id="linkedQuests" class="topBtmMarginSmall clear"><span>';
    		
			divHtml += 'For each linked form element, indicate whether it should be shown, hidden or ignored when ' +
			           'each CHOICE is checked.  When a CHOICE is unchecked, the opposite effect is implied: elements that are marked to be shown when ' +
			           'checked are to be hidden when that CHOICE is unchecked and elements marked to be hidden when checked are to '+
			           'be shown when unchecked.<p />' +
			           'The state of all CHOICES in this question is used to determine whether each linked element should be shown or hidden.  '+
			           'If at least one of the checkboxes has the linked element marked as show, the element is shown.' +
			           '</p>';
	                   
	        divHtml += '<br /></span></div>';
	        
	        // LOOP: display each CHOICE with associated link element setting (SHOW or HIDE or IGNORE)
			for (var i=0; i<questValues.length; i++)
			{
				var questValue = questValues[i];
				var displayText = escapeSpecialChars(questValue.display);
	            if (displayText==null || displayText=="") displayText="&lt;empty string&gt;";
				if (questValue != null)
				{
				    divHtml += '<div id=option"' + i + '" class="separatorBlock" style="display:block; margin-bottom:4px; background-color:#121F48; color:white;">' +
						       '<span class="boldTxt">If Choice </span><span class="boldTxt" style="color:yellow;">'+ displayText +
						       '</span><span class="boldTxt"> selected: </span></div>';
						       
					var numLinkedQuests = 0;
					for (var j=0; j<questValue.linkedQuests.length; j++)
					{
						var linkedQuest = questValue.linkedQuests[j];
						if (linkedQuest != null)
						{
							numLinkedQuests += 1;
							
							var questName    = linkedQuest.name;
							var display      = linkedQuest.display;
							
							if (j!=0)
							    divHtml += '<hr size="5" width="90%">';  // divider between links
	
	                        var questIndex = findQuestIndex(qList, questName);
							
	                        if (questIndex<0)
	                        {
	                            alert("questName " + escapeSpecialChars(questName) + " not found");
	                            divHtml += '</span><br /></div><div style="clear:both;"></div>';
	                        }
	                        else
	                        {
	                        	questText = qList.options[questIndex].text;
	                            divHtml += '<span class="editQuestLink" style="font-weight:bold;">' + escapeSpecialChars(questText) + '</span>';
						  	    divHtml += '<span class="indent"><input type="radio" name="disp' + i + j + '" value="show" ';
							
						        if (display == "show")      divHtml += 'checked="checked" ';
						        divHtml += 'onclick="changeLink(' + i + ', ' + j + ', this)" />Show';
						        divHtml += '<input class="indentSmall" type="radio" name="disp' + i + j + '" value="hide" ';
						
						        if (display == "hide")  	divHtml += 'checked="checked" ';
						        divHtml += 'onclick="changeLink(' + i + ', ' + j + ', this)" />Hide';
						        divHtml += '<input class="indentSmall" type="radio" name="disp' + i + j + '" value="ignore" ';
						
						        if (display == "ignore")  	divHtml += 'checked="checked" ';
						        divHtml += 'onclick="changeLink(' + i + ', ' + j + ', this)" />Ignore';
						        divHtml += '</span><br /></div><div style="clear:both;"></div>';
	                        }
					    }
					}
				}
				divHtml += '<hr size="5" width="90%">';  // divider between links
			}   
			
			divHtml += '<br /><hr><p class="boldTxt centerTxt">Form elements field settings:</p>' +
			           '<div  class="topBtmMarginSmall clear"><span>' + 
		               'When a linked form element transitions from the hidden to the shown state, indicate whether it\'s value(s) should be ' +
		               'NONE SET (empty/no value), set to it\'s DEFAULT or DO NOT RESET (not modified).<p>' +
		               '<p>Linked form elements that are of type SEPARATOR or INFORMATION do not have a value to manipulate and therefore are not shown below.';
                       '</span><br /><br /></div>';

			if ( questValues.length > 0)
			{
			    // For CHECKBOXES, the field settings are stored under the FIRST CHOICE only.
			    // Even if the first choice does not make the linked element visible.
				var questValue = questValues[0];
				if (questValue != null)
				{
					var numLinkedQuests = 0;
					for (var j=0; j<questValue.linkedQuests.length; j++)
					{
						var linkedQuest = questValue.linkedQuests[j];
						if (linkedQuest != null)
						{
							numLinkedQuests += 1;
							
							var questName    = linkedQuest.name;
							var display      = linkedQuest.display;
							var fieldSetting = linkedQuest.fieldSetting;		
							
							if (fieldSetting == "")
							    fieldSetting = "do not reset";
							
							divHtml += '<hr size="5" width="90%">';  // divider between links

							var questIndex = findQuestIndex(qList, questName);
							
	                        if (questIndex<0)
	                        {
	                            alert("questName " + escapeSpecialChars(questName) + " not found");
	                            divHtml += '</span><br /></div><div style="clear:both;"></div>';
	                        }
	                        else
	                        {
                        		questText = qList.options[questIndex].text;
							    divHtml += '<div id="field' + j + 'Div" style="display:block;">';
						 
						        if (qTypeList.options[questIndex].value=="Separator" ||
						            qTypeList.options[questIndex].value=="Information")
						        {
						            divHtml += '<span style="visibility:hidden;">';
					                divHtml += '<input type="radio" name="fieldSetting' + j + '" value="do not reset" ';
								    divHtml += 'checked="checked" ';
							        divHtml += '/>Do Not Reset';
							        divHtml += '</span></div><div style="clear:both;"></div>';
				                }
						        else
						        {
                                    divHtml += '<span class="editQuestLink" style="font-weight:bold;">' + escapeSpecialChars(questText) + '</span>';
						  	        divHtml += '<span style="float:right;padding-right:5%;">';
							        divHtml += escapeSpecialChars(qTypeList.options[questIndex].value);
							        divHtml += ' Value: ';
							        divHtml += '<input class="indentSmall" type="radio" name="fieldSetting' + j + '" value="none set" ';
							        
							        if (fieldSetting == "none set")
							        {
								        divHtml += 'checked="checked" ';
							        }

							        divHtml += 'onclick="changeFieldSetting(' + 0 + ', ' + j + 	', this)"';
							        divHtml += '/>None Set';
							        divHtml += '<input class="indentSmall" type="radio" name="fieldSetting' + j + '" value="default" ';
							        if (fieldSetting == "default")
							        {
							    	    divHtml += 'checked="checked" ';
							        }
							        divHtml += 'onclick="changeFieldSetting(' + 0 + ', ' + j + 	', this)"';
							        divHtml += '/>Default';
							        divHtml += '<input class="indentSmall" type="radio" name="fieldSetting' + j + '" value="do not reset" ';
							        if (fieldSetting == "do not reset")
							        {
							    	    divHtml += 'checked="checked" ';
							        }
							        divHtml += 'onclick="changeFieldSetting(' + 0 + ', ' + j + 	', this)"';
							        divHtml += '/>Do Not Reset';
							        divHtml += '</span><br /></div><div style="clear:both;"></div>';
						        } 
	                        }
					    }
					}
					
					if (numLinkedQuests == 0) 
						divHtml += '<span class="indent blueItalic">There are no linked elements</span>';
					else  					
						divHtml += '<hr size="5" width="90%">';  // divider between links
						
					divHtml += '</div>';
				}
			}   
	    }
	    else
	    {
    		divHtml += '<div id=linkedQuests class="topBtmMarginSmall clear">' + 
			           '<span>For linked form elements, indicate whether the ' +
			           'element(s) should be shown.  When a linked form element transitions from the hidden to the shown state, indicate whether it\'s value(s) should be ' +
		               'NONE SET (empty/no value), set to it\'s DEFAULT or DO NOT RESET (not modified).<p>' +
		               '<p>Linked form elements that are of type SEPARATOR or INFORMATION do not have a value to manipulate and therefore are not shown below.';
		               '</span><br /></div>';
		               
			for (var i=0; i<questValues.length; i++)
			{
				var questValue = questValues[i];
				if (questValue != null)
				{
				    divHtml += '<div id=option"' + i + '" class="separatorBlock" style="display:block; margin-bottom:4px; background-color:#121F48; color:white;">' +
						       '<span class="boldTxt">If Choice </span><span class="boldTxt" style="color:yellow;">'+ escapeSpecialChars(questValue.display) +
						       '</span><span class="boldTxt"> selected: </span></div>';
					var numLinkedQuests = 0;
					for (var j=0; j<questValue.linkedQuests.length; j++)
					{
						var linkedQuest = questValue.linkedQuests[j];
						if (linkedQuest != null)
						{
							numLinkedQuests += 1;
							
							var questName  = linkedQuest.name;
							var display      = linkedQuest.display;
							var fieldSetting = linkedQuest.fieldSetting;
							
							if (fieldSetting == "")
							    fieldSetting = "do not reset";
							
							if (j!=0)
							    divHtml += '<hr size="5" width="90%">';  // divider between links
	
							//findQuestIndex
							var questIndex = findQuestIndex(qList, questName);
	                        if (questIndex<0)
	                        {
	                            alert("questName " + escapeSpecialChars(questName) + " not found");
	                            divHtml += '</span><br /></div><div style="clear:both;"></div>';
	                        }
	                        else
	                        {
	                        	questText = qList.options[questIndex].text;
	                            divHtml += '<span class="editQuestLink" style="font-weight:bold;">' + escapeSpecialChars(questText) + '</span>';
						  	    divHtml += '<span class="indent">' + '<input type="radio" name="disp' + i + j + '" value="show" ';
							
						        if (display == "show")      divHtml += 'checked="checked" ';
						        divHtml += 'onclick="changeLink(' + i + ', ' + j + ', this)" />Show';
						        divHtml += '<input class="indentSmall" type="radio" name="disp' + i + j + '" value="hide" ';
						
						        if (display == "hide")  	divHtml += 'checked="checked" ';
						
						        divHtml += 'onclick="changeLink(' + i + ', ' + j + ', this)" />Hide';
                                divHtml += '<br />'; 
                        
						        divHtml += '<div id="field' + i + j + 'Div" style="display:';
						        if (display == "show") 
							        divHtml += 'block';
						        else
							        divHtml += 'none';
					            divHtml += ';">';
						 
						        if (qTypeList.options[questIndex].value=="Separator" ||
						            qTypeList.options[questIndex].value=="Information")
						        {
						            divHtml += '<span style="visibility:hidden;">';
					                divHtml += '<input type="radio" name="fieldSetting' + i + j + '" value="do not reset" ';
								    divHtml += 'checked="checked" ';
							        divHtml += '/>Do Not Reset';
							        divHtml += '</span></div><div style="clear:both;"></div>';
				                }
						        else
						        {
						  	        divHtml += '<span style="float:right;padding-right:5%;">';
						  	        
							        divHtml += escapeSpecialChars(qTypeList.options[questIndex].value);
							        divHtml += ' Value: ';
							        divHtml += '<input class="indentSmall" type="radio" name="fieldSetting' + i + j + '" value="none set" ';
							        
							        if (fieldSetting == "none set")
							        {
								        divHtml += 'checked="checked" ';
							        }
							        divHtml += 'onclick="changeFieldSetting(' + i + ', ' + j + 	', this)"';
							        divHtml += '/>None Set';
							        divHtml += '<input class="indentSmall" type="radio" name="fieldSetting' + i + j + '" value="default" ';
							        if (fieldSetting == "default")
							        {
							    	    divHtml += 'checked="checked" ';
							        }
							        divHtml += 'onclick="changeFieldSetting(' + i + ', ' + j + 	', this)"';
							        divHtml += '/>Default';
							        divHtml += '<input class="indentSmall" type="radio" name="fieldSetting' + i + j + '" value="do not reset" ';
							        if (fieldSetting == "do not reset")
							        {
							    	    divHtml += 'checked="checked" ';
							        }
							        divHtml += 'onclick="changeFieldSetting(' + i + ', ' + j + 	', this)"';
							        divHtml += '/>Do Not Reset';
							        divHtml += '</span><br /></div><div style="clear:both;"></div>';
						        } 
	                        }
					    }
					}
					
					if (numLinkedQuests == 0) 
						divHtml += '<span class="indent blueItalic">There are no linked elements</span>';
					else  					
						divHtml += '<hr size="5" width="90%">';  // divider between links
						
					divHtml += '</div>';
				}
			}
		}
		document.getElementById("questLinksDiv").innerHTML = divHtml;
	}
}

// changes label & enables/disables button below linked questions list
function updateModLinkButton() {
	var selectedIndex = document.forms[0].questLink.selectedIndex;
	var selectedQuestName = document.forms[0].questLink[selectedIndex].value;
	var modLinkButton = document.forms[0].modifyLinks;
	if (selectedIndex == 0) {
		modLinkButton.value = "Add Link";
		modLinkButton.disabled = true;
		return;
	}
	var match = false;
	// check if values for this question have been defined and if a link to the selected question
	// already exists. Since the linkedQuests arrays for each QuestionValue should contain the same
	// questions, find the first non-null QuestionValue object and loop through its linkedQuests array
	// looking for a match
	var nonNullValueFound = false;
	if (questValues != null) {
		for (var i=0; !nonNullValueFound && i<questValues.length; i++) {
			if (questValues[i] != null) {
				nonNullValueFound = true;
				var linkedQuests = questValues[i].linkedQuests;
				if (linkedQuests != null) {
					for (var j=0; !match && j<linkedQuests.length; j++) {
						if (linkedQuests[j] != null) {
							if (linkedQuests[j].name == selectedQuestName) {
								match = true;
							}
						}
					}
				}
			}
		}
	}
	// if no user choices defined yet, disable button
	if (!nonNullValueFound) {
		modLinkButton.value = "Add Link";
		modLinkButton.disabled = true;
	}
	// if user choices defined and a match was found, set button to 'Remove Link' and enable
	else if (match) {
		modLinkButton.value = "Remove Link";
		modLinkButton.disabled = false;
	}
	// if user choices defined and a match was not found, set button to 'Add Link' and enable
	else if (!match) {
		modLinkButton.value = "Add Link";
		modLinkButton.disabled = false;
	}
}

// checks the value of the modifyLinks button and calls add or remove link as appropriate
function modLink() {
	var buttonLabel = document.forms[0].modifyLinks.value;
	if (buttonLabel == "Add Link") {
		addLink();
	}
	else if (buttonLabel == "Remove Link") {
		removeLink();
	}
}

// adds link to selected question to all QuestionValue objects in the questValues array
function addLink() {
	var selectedIndex = document.forms[0].questLink.selectedIndex;
	var questName = document.forms[0].questLink.value;
	// add link
	if (questValues != null) {
		for (var i=0; i<questValues.length; i++) {
			if (questValues[i] != null) {
				questValues[i].linkedQuests[numLinks] = new LinkedQuestion(questName, "hide", "do not reset");				
			}
		}
		// do not increment counter until out of loop, all linkedQuests arrays should be parallel
		numLinks += 1;
	}
	// rebuild div
	buildLinkedQuestsList();
	// change button to read 'Remove Link'
	document.forms[0].modifyLinks.value = "Remove Link";
}

// removes link to specified question from all QuestionValue objects in the questValues array
function removeLink() {
	var selectedQuestName = document.forms[0].questLink.value;
	var questIndex = -1;
	// Find index in linkedQuests arrays of this entry. Since the linkedQuests arrays for each
	// QuestionValue should contain the same questions, find the first non-null linkedQuests array
	// and loop through looking for match
	if (questValues != null) {
		for (var i=0; i<questValues.length; i++) {
			if (questValues[i] != null) {
				var linkedQuests = questValues[i].linkedQuests;
				if (linkedQuests != null) {
					for (var j=0; questIndex<0 && j<linkedQuests.length; j++) {
						if (linkedQuests[j] != null) {
							if (linkedQuests[j].name == selectedQuestName) {
								questIndex = j;
							}
						}
					}
				}
			}
		}
		if (questIndex >= 0) {
			// remove link - set array entry at questIndex to null
			for (var i=0; i<questValues.length; i++) {
				if (questValues[i] != null) {
					questValues[i].linkedQuests[questIndex] = null;
				}
			}
		}
	}
	// rebuild div
	buildLinkedQuestsList();
	// change button to read 'Add Link'
	document.forms[0].modifyLinks.value = "Add Link";
}

// changes link to specified question
function changeLink(valueIndex, questionIndex, radio) {
	// change data for LinkedQuestion at questionIndex for the QuestionValue at valueIndex
	questValues[valueIndex].linkedQuests[questionIndex].display = radio.value;
	
	var field = document.getElementById( "field" + valueIndex + questionIndex + "Div" );
	if (field!=null)
	{
		if (radio.value == "show")
			field.style.display = "block";
		else
			field.style.display = "none";
    }
}

// changes field setting to specified question
function changeFieldSetting(valueIndex, questionIndex, fieldSetting) {
	// change field setting for LinkedQuestion at questionIndex for the QuestionValue at valueIndex
	questValues[valueIndex].linkedQuests[questionIndex].fieldSetting = fieldSetting.value;
}

// IE does not allow accessing of parts of strings by index, have to use substring
//
function escapeSpecialChars( inputString)
{
    var outputString = "";
    for (ii=0; ii<inputString.length; ii++)
    {
    	if (inputString.substring(ii,ii+1)=='&')
    	{
    		outputString += "&amp;";
    	}
    	else if (inputString.substring(ii,ii+1)=='<')
    	{
    	    outputString += "&lt;";
    	}
    	else if (inputString.substring(ii,ii+1)=='>')
    	{
    	    outputString += "&gt;";
    	}
    	else if (inputString.substring(ii,ii+1)=='"')
    	{
    	    outputString += "&quot;";
    	}
    	else if (inputString.substring(ii,ii+1)=='\'')
    	{
    	   	outputString += "&apos;";
    	}
    	else
    	{
    		outputString += inputString.substring(ii,ii+1);
    	}
    }
    
	return outputString;
}

// Sets the value of the hidden input 'linkedQuests', builds string using data in questValues array.
// This function is called from validateQuestion() so the input is set prior to form submission.
function setLinkedQuests() {
	var linkXml = "";
	if (questValues != null) {
		var linksFound = false;
		linkXml += "<linkedQuestions>";
		for (var i=0; i<questValues.length; i++) {
			if (questValues[i] != null && questValues[i].linkedQuests != null) {
				// if value field has been set, use this value. If not, use display text
				linkXml += "<option><text>" + escapeSpecialChars(questValues[i].display) + "</text>";

				var links = questValues[i].linkedQuests;
				for (var j=0; j<links.length; j++) {
					if (links[j] != null) {
						linksFound = true;
						linkXml += "<question><name>" + links[j].name + "</name>";
						linkXml += "<display>" + links[j].display + "</display>";
						linkXml += "<fieldSetting>" + links[j].fieldSetting + "</fieldSetting></question>";
					}
				}
				linkXml += "</option>";
			}
		}
		linkXml += "</linkedQuestions>";
		// if no links were actually found, set back to empty string
		if (!linksFound) linkXml = "";
	}
	document.questEdit.linkedQuests.value = linkXml;
}

// submits form so that changes will be saved to CMS
function saveForm() {
	if (validateForm()) {
		var selectedForm = document.formEdit.selectedForm.value;
		var formName = document.formEdit.name.value;
		if (selectedForm == "" && formName == "") {
			alert("Unable to save form, 'name' field is empty.");
		}
		else if (selectedForm == "" && formName != "") {
			if (confirm("Saving new form '" + formName + "'.")) {
				document.formEdit.requestType.value="newForm";
				document.formEdit.submit();
			}
		}
		else if (selectedForm == formName) {
			if (confirm("Are you sure you want to overwrite form '" + selectedForm + "'?")) {
				document.formEdit.requestType.value="modifyForm";
				document.formEdit.submit();
			}
		}
		else {
			if (confirm("Saving new form '" + formName + "'.")) {
				document.formEdit.requestType.value="newForm";
				document.formEdit.submit();
			}
		}
	}
}

// sets requestType input to 'updateForm' and submits form so changes will be saved.
function updateForm() {
	if (validateForm()) {
		document.formEdit.requestType.value="updateForm";
		document.formEdit.submit();
	}
}

// validates that all required fields for a dynamic form have a reasonable value
function validateForm() { 
	var requiredFields = "";
	var formEdit = document.getElementById("formEdit");
	var number;
	if (formEdit.name.value.length == 0) { requiredFields += "\n * Form name must be supplied."; }
	
	if (regex_form_name.test(formEdit.name.value))
	{ requiredFields += "\n * Form name can not include following \"`~!@#$%^&*()=+?,\.<>\" special characters."; }
	
	if (formEdit.title.value.length == 0) { requiredFields += "\n * Form title must be supplied."; }
	if (formEdit.colorScheme.value.length == 0) { requiredFields += "\n * A color scheme must be selected."; }
	if (formEdit.questionPercent.value.length == 0) { requiredFields += "\n * Width of question text must be supplied."; }
	else if (!regex_posInt.test(formEdit.questionPercent.value)) { requiredFields += "\n * Width of question text must be an integer between 20 and 80."; }
	else {
		number = parseInt(formEdit.questionPercent.value);
		if (number < 20 || number > 80)	{ requiredFields += "\n * Width of question text must be an integer between 20 and 80."; }
	}
	if (formEdit.questionSpacing.value.length == 0) { requiredFields += "\n * Spacing between questions must be supplied."; }
	else if (!regex_posInt.test(formEdit.questionSpacing.value)) { requiredFields += "\n * Spacing between questions must be an integer between 1 and 100."; }
	else {
		number = parseInt(formEdit.questionSpacing.value);
		if (number < 1 || number > 100)	{ requiredFields += "\n * Spacing between questions must be an integer between 1 and 100."; }
	}
	var dispBackground = "";
	var dispBackRadio = formEdit.displayQuestionBackground;
	for (i=0; i<dispBackRadio.length; i++) {
		if (dispBackRadio[i].checked) dispBackground = dispBackRadio[i].value;
	}
	if (dispBackground.length == 0) { requiredFields += "\n * Must indicate whether to show colored background."; }
	if (formEdit.submitText.value.length == 0) { requiredFields += "\n * Submit button text must be supplied."; }
	var logonReq = "";
	var logonReqRadio = formEdit.logonRequired;
	for (i=0; i<logonReqRadio.length; i++) {
		if (logonReqRadio[i].checked) logonReq = logonReqRadio[i].value;
	}
	if (logonReq.length == 0) { requiredFields += "\n * Must indicate whether logon is required."; }
	if (formEdit.submissionURL.value.length == 0) { requiredFields += "\n * URL for form submission must be supplied."; }

	var autoGenerate = false;
	var autoGenMap = formEdit.autoGenMapping;
	for (i=0; i<autoGenMap.length; i++)
	{
		if (autoGenMap[i].checked)
			autoGenerate = autoGenMap[i].value;
	}

	if (formEdit.submitAction.value == "Import to Database" && formEdit.hibernateMappingXML.value.length == 0 && autoGenerate == "false")  
		{ requiredFields += "\n * If Import to Database option is set, \"Automatic Generation of database mapping\" " +
							" needs to be set to \"Yes\" Or Database Mapping XML must be supplied ."; }
	if (formEdit.emailList.value.length > 0 && !regex_emailList.test(formEdit.emailList.value))
		{ requiredFields += "\n * Form recipients list should be a comma-separated list of email addresses."; }
	if (formEdit.senderEmail.value.length > 0 && !regex_email.test(formEdit.senderEmail.value))
		{ requiredFields += "\n * 'ReplyTo' address must be a valid email address."; }
	if (formEdit.responseEmail.value.length == 0) { requiredFields += "\n * Response recipients text must be supplied."; }
	if (formEdit.responseEmail.value.length > 0 && !regex_emailList.test(formEdit.responseEmail.value))
		{ requiredFields += "\n * Response recipients list should be a comma-separated list of email addresses."; }
	if (formEdit.onsubmitJavascript.value.length > 0 && !regex_function.test(formEdit.onsubmitJavascript.value))
		{ requiredFields += "\n * Javascript function call on form submission should be a complete function call including semicolon."; }
	if (formEdit.validAfter.value.length > 0 && !DateUtils.isValidDatetimeSyntax(formEdit.validAfter.value))
		{ requiredFields += "\n * Form validAfter date must be in the format MM/DD/YYYY HH:MM:SS."; }
	if (formEdit.validUntil.value.length > 0 && !DateUtils.isValidDatetimeSyntax(formEdit.validUntil.value))
		{ requiredFields += "\n * Form validUntil date must be in the format MM/DD/YYYY HH:MM:SS."; }
	if (formEdit.expirationDate.value.length > 0 && !DateUtils.isValidDatetimeSyntax(formEdit.expirationDate.value))
		{ requiredFields += "\n * Form expiration date must be in the format MM/DD/YYYY HH:MM:SS."; }

	if (requiredFields != "") {
		requiredFields = "Please correct the following to save this form:" + requiredFields;
		alert(requiredFields);
		return false;
	}
    else { return true; }
}

// submits questEdit form so that changes will be saved to QuestionBean in session
function saveQuestion() {
	if (validateQuestion()) {
		document.questEdit.submit();
	}
}

// validates that all required fields for a dynamic form question have a reasonable value
function validateQuestion() {
	var requiredFields = "";
	var questEdit = document.getElementById("questEdit");
	var questType = questEdit.questType.value;
	if (questType == "") { requiredFields += "\n * Question type must be selected."; }
	else {
		var dispInitially = "";
		var dispInitRadio = questEdit.displayInitially;
		for (i=0; i<dispInitRadio.length; i++) {
			if (dispInitRadio[i].checked) dispInitially = dispInitRadio[i].value;
		}
		if (dispInitially.length == 0) { requiredFields += "\n * Must indicate whether to display question initially."; }
		if (questEdit.introHeight.value.length > 0 && !regex_int.test(questEdit.introHeight.value))
			{ requiredFields += "\n * Height of introduction must be an integer greater than or equal to 0."; }
		if (questEdit.introWidth.value.length > 0 && !regex_int.test(questEdit.introWidth.value))
			{ requiredFields += "\n * Width of introduction must be an integer greater than or equal to 0."; }
		if (questType != "separator" && questType != "info") {
			setDefaultAnswer();
			var ansReq = "";
			var ansReqRadio = questEdit.required;
			for (i=0; i<ansReqRadio.length; i++) {
				if (ansReqRadio[i].checked) ansReq = ansReqRadio[i].value;
			}
			if (ansReq.length == 0) { requiredFields += "\n * Must indicate whether an answer is required."; }
			var lineBreak = "";
			var lineBreakRadio = questEdit.lineBreakUsed;
			for (i=0; i<lineBreakRadio.length; i++) {
				if (lineBreakRadio[i].checked) lineBreak = lineBreakRadio[i].value;
			}
			if (lineBreak.length == 0) { requiredFields += "\n * Must indicate whether to use a line break between question and answer."; }
		}
		if (questType == "text" || questType =="textarea") {
			if (questEdit.width.value.length > 0 && !regex_posInt.test(questEdit.width.value))
				{ requiredFields += "\n * Width must be an integer greater than 0."; }
			if (questType == "textarea") {
				if (questEdit.height.value.length > 0 && !regex_posInt.test(questEdit.height.value))
					{ requiredFields += "\n * Height must be an integer greater than 0."; }
			}
		}
		if (questType == "radio" || questType =="checkbox" || questType == "select")
		{
			setValues();
	    	setLinkedQuests();
			if (questEdit.values.value.length == 0)
			{ 
				requiredFields += "\n * User choices must be supplied.";
			}
			else if (!regex_values.test(questEdit.values.value))
			{ 
				requiredFields += "\n * User choices must be a comma-separated list.";
			}
			if (questType != "select")
			{
				if (questEdit.numColumns.value.length == 0)
				{
					requiredFields += "\n * Number of columns to display choices must be supplied.";
				}
				else if (!regex_posInt.test(questEdit.numColumns.value))
				{ 
					requiredFields += "\n * Number of columns must be an integer greater than 0.";
				}
			}
			
			// Verify all option "display text" are unique
			//
			if (questValues != null)
			{
				for (var i=0; i<questValues.length; i++)
				{
					if (questValues[i] != null)
					{
						// Compare against all other option "display text" for question
						// (0 thru i have already been checked)
						for (var j=i+1; j<questValues.length; j++)
						{
							if (questValues[j] != null)
							{
								if (questValues[i].display == questValues[j].display)
								{
									requiredFields += "\n * Duplicate choices \"" + questValues[j].display + "\". Display Text for list of choices MUST be unique.";
								}
							}
						}
					}
				}
			}
		}
		if (questType == "separator") {
			if (questEdit.separatorType.value == "") { requiredFields += "\n * Separator display type must be selected."; }
		}
	}

	if (requiredFields != "") {
		requiredFields = "Please correct the following to save this question:" + requiredFields;
		alert(requiredFields);
		return false;
	}

    else {
    	return true;
    }
}

// submits form with requestType of 'updateForm' so that servlet will update FormBean with changes. Servlet
// will set attribute indicating OK to open preview page if update has no errors. dynFormEdit JSP
// page checks for that attribute and calls openPreviewForm() if it is there.
function previewForm() {
	if (validateForm()) {
		document.formEdit.requestType.value="updateForm";
		document.formEdit.preview.value="form";
		if (formChanged) document.formEdit.formModified.value="true";
		document.formEdit.submit();
	}
}

function previewMapping(content) 
{
	var newwinContent = "";
	var name="Hibernate Mapping";
	
    newwinContent += "<html>\n<head>\n";
    newwinContent += "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n";
    newwinContent += "<title> View " + name + "</title>\n<script type=\"text/javascript\" src=\"/js/radeox.js\"></script>\n</head>\n";
	newwinContent += "<body>";
	newwinContent += "\n<div style=\"text-align:center;\"><h2>" + name + "</h2></div>\n";
	newwinContent += "<form id=\"form\">";
	newwinContent += "\n<table style=\"width:100%;\"><tr>\n";
	newwinContent += "<td style=\"text-align:center;\"><textarea name=\"box\" readonly=\"readonly\" cols=\"75\" rows=\"25\">" + content + "</textarea></td></tr>";
	newwinContent += "<tr><td style=\"text-align:center;\"><input type='button' name='closeBtn' value='Close Window' onclick='window.close();' />\n</td></tr>\n";
	newwinContent += "</table></form></body></html>";
	
	openHTMLWindow(newwinContent, 565, 700);
}

// opens new window with dynamic forms help page
function openHelp() {
	window.open("/employee/dynFormsHelp.html", "FormsHelp", "height=800,width=700,resizable,scrollbars");
}

// opens new window with form preview page
function openPreviewForm() {
	window.open("/employee/admin/DynamicFormEdit?requestType=previewForm", "FormPreview", "");
}

// opens new window with email preview page
function openPreviewEmail() {
	window.open("/employee/admin/DynamicFormEdit?requestType=previewEmail", "EmailPreview",
		 "height=600,width=600,resizable,scrollbars");
}

// goes to DynamicFormEdit servlet and deletes the selected form
function deleteForm() {
	var selectedForm = document.formEdit.selectedForm.value;
	if (selectedForm == "") {
		alert("Unable to delete form from database, form data not saved.");
	}
	else {
		if (confirm("Are you sure you want to delete form '" + selectedForm + "'?"))
			location.href = "/employee/admin/DynamicFormEdit?requestType=deleteForm&formName=" + selectedForm;
	}
}

// submits form with requestType of 'updateForm' so that servlet will update FormBean with changes. Servlet
// will set attribute indicating OK to open preview email page if update has no errors. dynFormEdit JSP
// page checks for that attribute and calls openPreviewEmail() if it is there.
function previewEmail() {
	if (validateForm()) {
		document.formEdit.requestType.value="updateForm";
		document.formEdit.preview.value="email";
		if (formChanged) document.formEdit.formModified.value="true";
		document.formEdit.submit();
	}
}

// goes to DynamicFormEdit servlet and emails form link to users
function emailForm() {
	var selectedForm = document.formEdit.selectedForm.value;
	if (selectedForm == "") {
		alert("Unable to email form, form data not saved.");
	}
	else {
		if (confirm("Are you sure you want to email form '" + selectedForm + "'?\nPlease be sure all form modifications have been saved."))
			location.href = "/employee/admin/DynamicFormEdit?requestType=emailForm&formName=" + selectedForm;
	}
}

// submits form to DynamicFormEdit servlet, loads QuestionBean, and forwards to dynFormQuestion JSP to edit
function editQuestion() {
	if (validateForm()) {
		// set formModified input - servlet will check for this and set flag when sending to question edit page
		if (formChanged) document.formEdit.formModified.value="true";
		var selectedQuest = document.formEdit.questionList.value;
		if (selectedQuest == "") {
			document.formEdit.requestType.value="blankQuestion";
			document.formEdit.submit();
		}
		else {
			document.formEdit.requestType.value="loadQuestion";
			document.formEdit.questName.value=selectedQuest;
			document.formEdit.submit();
		}
	}
}

// definition of QuestionValue object type - 'new' will create a new instance. 'value' is the value
// to be returned when this option is selected, 'display' is the text to display to user for this option,
// 'isDefault' is a boolean indicating whether this option is selected by default, and 'linkedQuests'
// is an array of LinkedQuestion objects containing data indicating which questions are linked to this
// value and whether they should be showed or hidden
function QuestionValue(value, display, isDefault) {
	this.value = value;
	this.display = display;
	this.isDefault = isDefault;
	this.linkedQuests = new Array();
}

// goes to DynamicFormEdit servlet and forwards to form editing page. Question data not saved.
function cancelEditQuest() {
	var modified = document.questEdit.formModified.value;
	if (modified == "true")
		location.href = "/employee/admin/DynamicFormEdit?requestType=cancelEditQuestion&formModified=true";
	else
		location.href = "/employee/admin/DynamicFormEdit?requestType=cancelEditQuestion";
}

// removes question from question lists
function deleteQuest() {
	var questList = document.formEdit.questionList;
	var selectedQuest = questList.value;
	var url = "/employee/admin/DynamicFormEdit?requestType=deleteQuestion&questName=" + selectedQuest;
	// check if OK to proceed with request
	if (selectedQuest == "") {
		alert("Unable to complete request, no question selected.");
	}
	else {
		if (!confirm("Are you sure you want to delete the selected question?")) {
			return;
		}
		formChanged = true;
		// create and send XMLHttpRequest
		var req = createXMLHttpRequest();
		if (req != null) {
       		req.open("GET", url, true);
			req.onreadystatechange = function() {
			    if (req.readyState == 4) { // Complete
			    	if (req.status == 200) { // OK response
						var qList = document.formEdit.questionList;
				    	var questIndex = findQuestIndex(qList, selectedQuest);
				    	if (questIndex > 0) {
					    	qList.options[questIndex] = null;
					    	qList.options[questIndex-1].selected = true;
					    	qList = document.formEdit.userEmailQuestion;
					    	// make change to email question selection list, make sure the
					    	// previously selected email question stays selected, unless it was
					    	// the deleted question
					    	var emailQuest = qList.options[qList.selectedIndex].value;
					    	qList.options[questIndex] = null;
					    	var emailIndex = findQuestIndex(qList, emailQuest);
					    	if (emailIndex >= 0) {
					    		qList.options[emailIndex].selected = true;
					    	}
					    	else {
						    	qList.options[questIndex-1].selected = true;
						    }
					    }
					    else {
					    	alert("Unable to delete question, no matching question found.");
					    }
			    	}
			    	else { alert("Unable to delete question: " + req.statusText); }
			    }
			};
	        req.send(null);
	    }
	}
}

// moves question up on all question lists
function moveQuestUp() {
	var questList = document.formEdit.questionList;
	var selectedQuest = questList.value;
	var url = "/employee/admin/DynamicFormEdit?requestType=moveQuestUp&questName=" + selectedQuest;
	// check if OK to proceed with request
	if (selectedQuest == "") {
		alert("Unable to complete request, no question selected.");
	}
	else {
		if (questList.selectedIndex <= 1) {
			alert("Unable to move question up, question is at top of list.");
			return;
		}
		formChanged = true;
		// create and send XMLHttpRequest
		var req = createXMLHttpRequest();
		if (req != null) {
       		req.open("GET", url, true);
			req.onreadystatechange = function() {
			    if (req.readyState == 4) { // Complete
			    	if (req.status == 200) { // OK response
						var qList = document.formEdit.questionList;
				    	var questIndex = findQuestIndex(qList, selectedQuest);
					    if (questIndex < 0) {
					    	alert("Unable to move question, no matching question found.");
					    }
					    else if (questIndex == 0 || questIndex == 1) {
					    	alert("Unable to move question up, question is at top of list.");
					    }
				    	else {
					    	var selectedText = qList.options[questIndex].text;
				    		var selectedValue = selectedQuest;
					    	var otherText = qList.options[questIndex-1].text;
					    	var otherValue = qList.options[questIndex-1].value;
					    	qList.options[questIndex-1] = new Option(selectedText, selectedValue);
					    	qList.options[questIndex] = new Option(otherText, otherValue);
					    	qList.options[questIndex-1].selected = true;
					    	qList = document.formEdit.userEmailQuestion;
					    	// make change to email question selection list, make sure the
					    	// previously selected email question stays selected
					    	var emailQuest = qList.options[qList.selectedIndex].value;
					    	qList.options[questIndex-1] = new Option(selectedText, selectedValue);
					    	qList.options[questIndex] = new Option(otherText, otherValue);
					    	var emailIndex = findQuestIndex(qList, emailQuest);
					    	if (emailIndex >= 0) {
					    		qList.options[emailIndex].selected = true;
					    	}
					    	else {
						    	qList.options[0].selected = true;
						    }
					    }
			    	}
			    	else { alert("Unable to move question: " + req.statusText); }
			    }
			};
	        req.send(null);
	    }
	}
}

// moves question down on all question lists
function moveQuestDown() {
	var questList = document.formEdit.questionList;
	var selectedQuest = questList.value;
	var url = "/employee/admin/DynamicFormEdit?requestType=moveQuestDown&questName=" + selectedQuest;

	// check if OK to proceed with request
	if (selectedQuest == "") {
		alert("Unable to complete request, no question selected.");
	}
	else {
		if (questList.selectedIndex == questList.options.length-1) {
			alert("Unable to move question down, question is at bottom of list.");
			return;
		}
		formChanged = true;
		// create and send XMLHttpRequest
		var req = createXMLHttpRequest();
		if (req != null) {
       		req.open("GET", url, true);
			req.onreadystatechange = function() {
			    if (req.readyState == 4) { // Complete
			    	if (req.status == 200) { // OK response
						var qList = document.formEdit.questionList;
				    	var questIndex = findQuestIndex(qList, selectedQuest);
					    if (questIndex < 0) {
					    	alert("Unable to move question, no matching question found.");
					    }
					    else if (questIndex == qList.options.length-1) {
					    	alert("Unable to move question down, question is at bottom of list.");
					    }
				    	else {
					    	var selectedText = qList.options[questIndex].text;
				    		var selectedValue = selectedQuest;
					    	var otherText = qList.options[questIndex+1].text;
					    	var otherValue = qList.options[questIndex+1].value;
				        	qList.options[questIndex+1] = new Option(selectedText, selectedValue);
				        	qList.options[questIndex] = new Option(otherText, otherValue);
				        	qList.options[questIndex+1].selected = true;
				        	qList = document.formEdit.userEmailQuestion;
					    	// make change to email question selection list, make sure the
					    	// previously selected email question stays selected
					    	var emailQuest = qList.options[qList.selectedIndex].value;
				        	qList.options[questIndex+1] = new Option(selectedText, selectedValue);
				        	qList.options[questIndex] = new Option(otherText, otherValue);
					    	var emailIndex = findQuestIndex(qList, emailQuest);
					    	if (emailIndex >= 0) {
					    		qList.options[emailIndex].selected = true;
					    	}
					    	else {
						    	qList.options[0].selected = true;
						    }
					    }
			    	}
			    	else { alert("Unable to move question: " + req.statusText); }
			    }
			};
	        req.send(null);
	    }
	}
}

// cycles through list and finds question with value matching parameter
function findQuestIndex(questList, value) {
	var index = -1;
	if (questList != null) {
		var found = false;
		for (var i=0; !found && i<questList.options.length; i++) {
			if (questList.options[i].value == value) {
				index = i;
				found = true;
			}
		}
	}
	return index;
}

// Cycle through DynamicQuestionBean list and finds question with display text matching parameter.
// Return -1 if match not found.
//
function findQuestTextIndex(questList, qText) {
	var index = -1;
	if (questList != null) {
		var found = false;
		for (var i=0; !found && i<questList.options.length; i++) {
			if (questList.options[i].text == qText) {
				index = i;
				found = true;
			}
		}
	}
	return index;
}

// opens a small window to display the full text of any context help associated with the form field.
function openContextHelp(text) 
{
    var newWindowContent = "<html><head><title>Question Help</title></head><body style='font-family: arial, verdana, sans-serif;font-size: .75em;padding:6px' ><h1 style='font-size: 1.75em; font-weight: normal;color:#26466D;margin:0;padding:0'>Question Help</h1><p>" + text;
	newWindowContent += "</p><div style='text-align: center;padding-top:20px'><input type='button' value='Close' onclick='window.close();' /></div></body></html>";
		
	openHTMLWindow(newWindowContent);
}

// Validates date/time strings based on format supplied. Returns string representation of date if
// input is valid, otherwise returns null
function toDate(date,format){
	var i, regex, index=new Array;
	var day, month, year, hour, minute, second, ampm;
	// Determine order of datetime tokens
	with(format){
		index[search(/dd?/i)]="day";
		index[search(/mm?/i)]="month";
		index[search(/yyyy/i)]="year";
		index[search(/hh?/i)]="hour";
		index[search(/nn/i)]="minute";
		index[search(/ss/i)]="second";
		index[search(/ap/i)]="ampm";

		// timing of replaces is quite important!
		regex=format.replace(/(\$|\^|\*|\(|\)|\+|\.|\?|\\|\{|\}|\||\[|\])/g,"\\$1");
		// only allow one pass for day and month
		if(search(/dd/i)>-1)
			regex=regex.replace(/dd/i,"(0[1-9]|[1-2]\\d|3[0-1])");
		else
			regex=regex.replace(/d/i,"(0?[1-9]|[1-2]\\d|3[0-1])");
		if(search(/mm/i)>-1)
			regex=regex.replace(/mm/i,"(0[1-9]|1[0-2])");
		else
			regex=regex.replace(/m/i,"(0?[1-9]|1[0-2])");
		regex=regex.replace(/nn/i,"([0-5]\\d)")
			.replace(/ss/i,"([0-5]\\d)")
			.replace(/yyyy/i,"(\\d{4})")
			.replace(/\s+/g,"\\s*");
		if(search(/hh24/i)>-1)
			regex=regex.replace(/hh24/i,"([0-1]\\d|2[0-3])");
		else if(search(/h24/i)>-1)
			regex=regex.replace(/h24/i,"([0-1]?\\d|2[0-3])");
		else if(search(/hh/i)>-1)
			regex=regex.replace(/hh/i,"(0\\d|1[0-2])").replace(/ap/i,"([ap]m?)");
		else
			regex=regex.replace(/h/i,"(0?\\d|1[0-2])").replace(/ap/i,"([ap]m?)");
	}
	// test date against format
	if(!new RegExp("^"+regex+"$","i").test(date))
		return;
	// set values from user input
	year=month=day=hour=minute=second=0,ampm="";
	for(var key=0,i=0;key<index.length;key++)
		if(index[key]) eval(index[key]+"=RegExp.$"+ ++i);
	// set default values
	if(hour<12&&/^pm?$/i.test(ampm))
		hour = parseInt(hour)+12;
	else if(hour==12&&/^am?$/i.test(ampm))
		hour=0;
	if(year==0) year=1;
	if(month==0) month=1;
	if(day==0) day=1;
	// check days in month
	if(month==2 && day>((year%4==0&&year%100!=0||year%400==0)?29:28) || day>((month-1)%7+1)%2+30)
		return;
	// build result value
	return ""+pad(year,4)+pad(month)+pad(day)+pad(hour)+pad(minute)+pad(second);
}

// used by toDate function
function pad(value, width){
	width=choose(width,2);
	var returnValue=value.toString();
	for(var i=width-returnValue.length;i>0;i--)
		returnValue="0"+returnValue;
	return returnValue;
}

// used by pad function (in conjunction with toDate function)
function choose(/* list */){
	var i, value, iArguments=arguments.length;
	for(i=0;i<iArguments;i++){
		value = arguments[i];
		if(typeof value!="undefined" && value!=null && value!="")
			return value;
	}
}

