// Vovici Client Side Survey API
// Copyright 1997-2010 Vovici Corporation. All rights reserved.
// Version: 5.3.0

// Implement swapNode for older browsers
try {
	if (!Node.prototype.swapNode) {
		Node.prototype.swapNode = function(node) {
			var nextSibling = this.nextSibling;
			if (nextSibling == node) nextSibling = nextSibling.nextSibling;
			var parentNode = this.parentNode;
			node.parentNode.replaceChild(this, node);
			parentNode.insertBefore(node, nextSibling);
		}
	}
} catch (e) { }

/// <summary>
/// Creates a new instance of the Client Side Survey API.
/// </summary>
function VcSurvey() {
	this.Culture = 'en-US';
	// Number Formatting Defaults
	this.NumberDecimalSeparator = '.';
	this.NumberGroupSeparator = ',';
	this.NumberGroupSizes = 3;
	// Date Picker Defaults
	this.PrevText = 'Back';
	this.NextText = 'Next';
	this.MonthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
	this.MonthNamesShort = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
	this.DayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
	this.DayNamesShort = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
	this.DayNamesMin = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
	this.DateFormat = 'mm/dd/yyyy';
	this.DateSeparator = '/'
	this.FirstDay = 0;
	this.IsRTL = false;	
	this.firstValidationMessage = null;
	this.validationMessages = new Object();
	this.AddEvent(window, "load", this.DisableEnterKey);
}

/// <summary>
/// Returns the form element containing the survey.
/// </summary>
VcSurvey.prototype.SurveyForm = function() {
	var form = document.getElementById("PdcSurvey");
	if (!form) form = document.forms["PdcSurvey"];
	return form;
};

/// <summary>
/// Gets a value from the query string and returns it or blank if not found.
/// </summary>
// <param name="parameterName">A valid url parameter</param>
VcSurvey.prototype.GetUrlParameter = function(parameterName) {
	// Get the query string minus the ?
	var queryString = location.search.substring(1);

	// Convert plus to space
	queryString = queryString.replace(/\+/g, " ");
	// Split the args by & and the look at each named pair.
	var params = queryString.split('&');
	for (var x = 0; x < params.length; x++) {
		var pair = params[x].split('=');
		if ((pair.length == 2) && (pair[0] == parameterName)) {
			return decodeURIComponent(pair[1]);
		}
	}

	return '';
};

/// <summary>
/// Gets a value from the query string and sets it to the
/// specified fill in the blank, essay or hidden question.
/// </summary>
// <param name="heading">A valid dbHeading</param>
// <param name="parameterName">A valid url parameter</param>
VcSurvey.prototype.SetUrlParameter = function(heading, parameterName) {
	this.SetTextValue(heading, this.GetUrlParameter(parameterName));
};

/// <summary>
/// Auto Advances the survey to the next page,
/// or submits if on the last page.
/// </summary>
VcSurvey.prototype.AutoAdvance = function() {
	if (document.PdcSurvey.next) {
		document.PdcSurvey.next.click();
	} else if (document.PdcSurvey.submit) {
		document.PdcSurvey.submit.click();
	} else {
		document.PdcSurvey.submit();
	}
};

/// <param>
/// Sets html to an element.
/// </param>
/// <param name="id">Element ID</param>
/// <param name="html">HTML to assign</param>
VcSurvey.prototype.SetElementHtml = function(id, html) {
	var element = document.getElementById(id);
	if (element) element.innerHTML = html;
};

/// <summary>
/// Returns the value for a fill in the blank or essay question as a string.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
VcSurvey.prototype.GetTextValue = function(heading) {
	var value = '';
	var inputField = document.getElementById(heading);
	if (inputField) value = inputField.value;
	return value.toString();
};

/// <summary>
/// Sets the value for a fill in the blank, essay or hidden question.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
/// <param name="newValue">Value to assign to field</param>
VcSurvey.prototype.SetTextValue = function(heading, newValue) {
	var inputField = document.getElementById(heading);
	if (inputField) inputField.value = newValue;
};

/// <summary>
/// Returns the value for a fill in the blank as number.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
VcSurvey.prototype.GetNumericValue = function(heading) {
	var textValue = this.GetTextValue(heading);
	var numValue = this.ToEnglishNumber(textValue);
	return Number(numValue);
};

/// <summary>
/// Returns the selected value of a Choose One
/// (Radio Button List or Select List) or 0 for Not Answered.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
VcSurvey.prototype.GetChooseOneValue = function(heading) {
	var elements = document.getElementsByName(heading);
	for (var x = 0; x < elements.length; x++) {
		element = elements[x];
		if (element.tagName == "SELECT") {
			return Number(element.options[element.selectedIndex].value);
		} else if (element.type == "radio" && element.checked) {
			return Number(element.value);
		}
	}
	return 0;
};

/// <summary>
/// Sets the value for a Choose One
/// (Radio Button List or Select List)
/// </summary>
/// <param name="heading">A valid dbHeading</param>
/// <param name="newValue">Value to assign to field</param>
VcSurvey.prototype.SetChooseOneValue = function(heading, newValue) {
	var elements = document.getElementsByName(heading);
	for (var x = 0; x < elements.length; x++) {
		element = elements[x];
		if (element.tagName == "SELECT") {
			var selectedIndex = 0;
			var optionCount = element.options.length - 1;
			for (var i = 1; i < optionCount; i++) {
				if (element.options[i].value == newValue) {
					selectedIndex = i;
					break;
				}
			}
			element.selectedIndex = selectedIndex;
			return;
		} else if (element.type == "radio") {
			element.checked = (element.value == newValue);
			$(element).change();
		}
	}
};

/// <summary>
/// Returns the selected value of a Choose Many choice
/// 0 = unchecked, 1 = checked.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
VcSurvey.prototype.GetChooseManyValue = function(heading) {
	var element = document.getElementById(heading);
	if (element && element.checked) return 1;
	return 0;
};

/// <summary>
/// Sets the value for a Choose Many choice.
/// </summary>
/// <param name="newValue">Value to assign to field 0 = unchecked, 1 = checked</param>
VcSurvey.prototype.SetChooseManyValue = function(heading, newValue) {
	var element = document.getElementById(heading);
	if (element) element.checked = (newValue == 1);
	$(element).change();
};

/// <summary>
/// Given a list of choose many choices, sets them to not checked.
/// </summary>
/// <param>List of dbHeadings e.g. 'Q1_1', 'Q1_2', 'Q1_3'</param>
VcSurvey.prototype.ClearCheckboxes = function() {
	for (var i = 0; i < arguments.length; i++) {
		var element = document.getElementById(arguments[i]);
		if (element) element.checked = false;
	}
};

/// <summary>
/// Indicates if the specified essay question, fill in the blank topic
/// or choose one list/dropdown has been answered. Or if the specified choose one
/// radio or choose many checkbox have been selected.
/// Does not indicate whether its a valid answer.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
VcSurvey.prototype.IsAnswered = function(heading) {
	var inputField = document.getElementById(heading);
	if (inputField) {
		switch (inputField.tagName) {
			// Fill In
			case "INPUT":
				switch(inputField.type) {
					case "text":
					case "password":
					case "hidden":
						var ghostText = inputField.getAttribute("ghostText");
						if (ghostText && ghostText == inputField.value) return false;
						return (inputField.value != '');
					case "radio":
					case "checkbox":
						return inputField.checked;
				}
				break;
			// Essay
			case "TEXTAREA":
				return (inputField.value != '');
			// Choose One List/Dropdown
			case "SELECT":
				var value = inputField.options[inputField.selectedIndex].value;
				return (value != '0' && value != '');
		}
	} else {
		// Date Dropdown Boxes
		if (document.getElementById(heading + "_DD")) {
			var monthElement = document.getElementById(heading + "_MM");
			var month = Number(monthElement.options[monthElement.selectedIndex].value);
			var day = Number(document.getElementById(heading + "_DD").value);
			var year = Number(document.getElementById(heading + "_YYYY").value);
			if (month != 0 || day != 0 || year != 0) return true;
		// Radio Group
		} else {
			var elements = document.getElementsByName(heading);
			if (elements) {
				for (var x = 0; x < elements.length; x++) {
					if (elements[x].type == "radio" && elements[x].checked) {
						return true;
					}
				}
			}
		}		
	}
	return false;
};

/// <summary>
/// Given a list of field headings, returns the number
/// of them that have been answered.
/// </summary>
/// <param>List of dbHeadings e.g. 'Q1_1', 'Q1_2', 'Q1_3' or Array</param>
VcSurvey.prototype.AnsweredCount = function() {
	var answerCount = 0;
	var args = this.getArguments(arguments);
	for (var x = 0; x < args.length; x++) {
		if (this.IsAnswered(args[x])) answerCount++;
	}
	return answerCount;
};

/// <summary>
/// Given a list of field headings, returns true
/// if any of them have been answered.
/// </summary>
/// <param>List of dbHeadings e.g. 'Q1_1', 'Q1_2', 'Q1_3' or Array</param>
VcSurvey.prototype.AnyAnswered = function() {
	var args = this.getArguments(arguments);
	for (var x = 0; x < args.length; x++) {
		if (this.IsAnswered(args[x])) return true;
	}
	return false;
};

/// <summary>
/// Given a list of field headings, returns true
/// if any of them have not been answered.
/// </summary>
/// <param>List of dbHeadings e.g. 'Q1_1', 'Q1_2', 'Q1_3' or Array</param>
VcSurvey.prototype.AnyNotAnswered = function() {
	var args = this.getArguments(arguments);
	for (var x = 0; x < args.length; x++) {
		if (!this.IsAnswered(args[x])) return true;
	}
	return false;
};

/// <summary>
/// Private - Returns an Array of items given an argument object or array object.
/// </summary>
/// <param name="args">Array Object or Arguments</param>
VcSurvey.prototype.getArguments = function(args) {
	if (args[0].constructor.toString().indexOf("function Array()") != -1) {
		return args[0];
	} else {
		return Array.prototype.slice.call(args);
	}
}

/// <summary>
/// Given a fill in the blank heading, returns true if the length
/// of the respondents answer is less than the specified length.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
/// <param name="length">Minimum Length</param>
VcSurvey.prototype.IsMinLength = function(heading, length) {
	return (this.GetTextValue(heading).length < length);
};

/// <summary>
/// Given a fill in the blank heading, returns true if the length
/// of the respondents answer is greater than the specified length.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
/// <param name="length">Maximum Length</param>
VcSurvey.prototype.IsMaxLength = function(heading, length) {
	return (this.GetTextValue(heading).length > length);
};

/// <summary>
/// Given a fill in the blank heading, returns true if the value
/// of the respondents answer is within than the specified range.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
/// <param name="minValue">Minimum Value</param>
/// <param name="maxValue">Maximum Value</param>
VcSurvey.prototype.IsInRange = function(heading, minValue, maxValue) {
	var numValue = this.GetNumericValue(heading);
	if (minValue != null && numValue < minValue) return false;
	if (maxValue != null && numValue > maxValue) return false;
	return true;
};

/// <summary>
/// Given a list of field headings, returns true
/// if they all have unique values.
/// </summary>
/// <param name="headings">An array object of dbHeadings e.g. new Array('Q1_1', 'Q1_2', 'Q1_3')</param>
VcSurvey.prototype.IsRankedOrder = function(headings) {
	var choiceValues = new Array();
	for (var x = 0; x < headings.length; x++) {
		var value = this.GetChooseOneValue(headings[x]);
		// Exclude Not Answered and Coded Values
		if (value > 0) {
			// If value already selected
			if (choiceValues[value] == 1) {
				return false;
			} else {
				choiceValues[value] = 1;
			}
		}
	}
	return true;
};

/// <summary>
/// Given a list of field headings and a number of topics to rank,
/// returns true if that number of topics have been ranked.
/// </summary>
/// <param name="headings">An array object of dbHeadings e.g. new Array('Q1_1', 'Q1_2', 'Q1_3')</param>
/// <param name="numrank">Number of topics that need to be ranked</param>
VcSurvey.prototype.IsRankedTopX = function(headings, numrank) {
	var count = 0;
	var choiceValues = new Array();
	for (var x = 0; x < headings.length; x++) {
		var value = this.GetChooseOneValue(headings[x]);
		// Exclude Not Answered and Coded Values
		if (value > 0) count++;
	}
	return (numrank == count);
};

/// <summary>
/// Indicates if the specified fill in topic contains a whole number.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
VcSurvey.prototype.IsInteger = function(heading) {
	var inputField = document.getElementById(heading);
	if (inputField) return this.IsTextInteger(inputField.value);
	return false;
};

/// <summary>
/// Indicates if the specified text is a whole number.
/// </summary>
/// <param name="text">Text being tested</param>
VcSurvey.prototype.IsTextInteger = function(text) {
	// If number contains both a group seperator and a decimal seperator
	// We can determine if they entered the number for the wrong region.
	var groupSep = text.indexOf(this.NumberGroupSeparator);
	// If seperator is ascii 160 space, and was not found, also search for ascii 32 space
	if (groupSep == -1 && this.NumberGroupSeparator == "\u00A0") {
		groupSep = text.indexOf("\ ");
	}
	var decimalSep = text.indexOf(this.NumberDecimalSeparator);
	if (groupSep != -1 && decimalSep != -1 && (groupSep > decimalSep)) return false;
	// Test Concurrent Separators
	var reGroup = new RegExp("\\" + this.NumberGroupSeparator + "{2,}");
	var reDecimal = new RegExp("\\" + this.NumberDecimalSeparator + "{2,}");
	if(reGroup.exec(text) != null || reDecimal.exec(text) != null) return false;
	var number = this.ToEnglishNumber(text);
	if (number.match(/^-?\d+$/)) return true;
	return false;
};


/// <summary>
/// Indicates if the specified fill in topic contains a real number.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
VcSurvey.prototype.IsFloat = function(heading) {
	var inputField = document.getElementById(heading);
	if (inputField) return this.IsTextFloat(inputField.value);
	return false;
};

/// <summary>
/// Indicates if the specified text is a real number.
/// </summary>
/// <param name="text">Text being tested</param>
VcSurvey.prototype.IsTextFloat = function(text) {
	// If number contains both a group seperator and a decimal seperator
	// We can determine if they entered the number for the wrong region.
	var groupSep = text.indexOf(this.NumberGroupSeparator);
	// If seperator is ascii 160 space, and was not found, also search for ascii 32 space
	if (groupSep == -1 && this.NumberGroupSeparator == "\u00A0") {
		groupSep = text.indexOf("\ ");
	}
	var decimalSep = text.indexOf(this.NumberDecimalSeparator);
	if (groupSep != -1 && decimalSep != -1 && (groupSep > decimalSep)) return false;
	// Test Concurrent Separators
	var reGroup = new RegExp("\\" + this.NumberGroupSeparator + "{2,}");
	var reDecimal = new RegExp("\\" + this.NumberDecimalSeparator + "{2,}");
	if(reGroup.exec(text) != null || reDecimal.exec(text) != null) return false;
	var number = this.ToEnglishNumber(text);
	if (number.match(/^-?\d*(\.\d+)?$/)) return true;
	return false;
};

/// <summary>
/// Indicates if the specified fill in topic contains a valid e-mail address.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
VcSurvey.prototype.IsEmail = function(heading) {
	var inputField = document.getElementById(heading);
	if (inputField) {
		var email = inputField.value;
		if (email.match(/^[\w_\-\.\']+[\%\+]?[\w_\-\']*\@[0-9a-zA-Z\-]+\.[0-9a-zA-Z\-\.]+$/)) return true;
	}
	return false;
};

/// <summary>
/// Indicates if the specified fill in topic contains a valid date.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
VcSurvey.prototype.IsDate = function(heading) {
	// Get Month/Day/Year Values
	var month, day, strYear;
	var dateElement = document.getElementById(heading);
	// Calendar Picker
	if (dateElement) {
		var dateValue = dateElement.value;
		var dateFormat = this.DateFormat;
		// Croatian, Hungarian, Latvian end with trailing period
		if(dateValue.lastIndexOf('.') == dateValue.length - 1) {
			dateValue = dateValue.substr(0, dateValue.length - 1);
		}
		if(dateFormat.lastIndexOf('.') == dateFormat.length - 1) {
			dateFormat = dateFormat.substr(0, dateFormat.length - 1);
		}
		var reGroup = new RegExp("\\" + this.DateSeparator);
		// Uzbekistan uses different separators
		if (this.Culture == "uz-Latn-UZ") {
			reGroup = new RegExp("\\/| ");
		}
		var dateParts = dateFormat.split(reGroup);
		var valueParts = dateValue.split(reGroup);
		if (valueParts.length < 3) return false;
		for (var i = 0; i < 3; i++) {
			if (dateParts[i] == "mm") month = Number(valueParts[i]);
			if (dateParts[i] == "dd") day = Number(valueParts[i]);
			if (dateParts[i] == "yyyy") strYear = valueParts[i];
		}
	// Multiple Controls
	} else {
		var monthElement = document.getElementById(heading + "_MM");
		month = Number(monthElement.options[monthElement.selectedIndex].value);
		day = Number(document.getElementById(heading + "_DD").value);
		strYear = document.getElementById(heading + "_YYYY").value;
	}
	var year = Number(strYear);
	// Not a number
	if (isNaN(month) || isNaN(day) || isNaN(year)) return false;
	// Month out of range
	if (month < 1 || month > 12) return false;
	// Day out of range
	if (day < 1 || day > 31) return false;
	// 30 Day Months
	if ((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) return false;
	// Leap Year Check
	if (month == 2) {
		var isleap = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
		if (day > 29 || (day == 29 && !isleap)) return false;
	}
	// Years must be a positive 4 digit integer.
	if (year <= 0 || strYear.length != 4 || !this.IsTextInteger(strYear)) return false;
	return true;
};

/// <summary>
/// Private - Given an array of field headings, returns their total as a number.
/// </summary>
/// <param name="heading">Array of dbHeadings</param>
VcSurvey.prototype.calculateTotal = function(headings) {
	var total = 0;
	var decimalPlaces = 0;

	for (var i = 0; i < headings.length; i++) {
		var heading = headings[i];
		var inputField = document.getElementById(heading);
		if (inputField) {
			var number = this.ToEnglishNumber(inputField.value);
			// Add leading 0 if missing
			if (number.indexOf(".") == 0) number = "0" + number;
			// Get decimal precision
			var decimalIndex = number.indexOf(".");
			if (decimalIndex != -1) {
				var decimalPlacesCount = number.length - (decimalIndex + 1);
				if (decimalPlacesCount > decimalPlaces) decimalPlaces = decimalPlacesCount;
			}
			if (number.match(/^-?\d+(\.\d+)?$/)) {
				total += parseFloat(number);
			}
		}
	}

	if (decimalPlaces > 0) total = total.toFixed(decimalPlaces);

	return total;
};

/// <summary>
/// Given a list of field headings, returns their total as a number.
/// </summary>
/// <param>List of dbHeadings e.g. 'Q1_1', 'Q1_2', 'Q1_3'</param>
VcSurvey.prototype.NumericTotal = function() {
	return this.calculateTotal(arguments);
};

/// <summary>
/// Given a list of field headings, returns their total as a string
/// formatted for the surveys culture.
/// </summary>
/// <param>List of dbHeadings e.g. 'Q1_1', 'Q1_2', 'Q1_3'</param>
VcSurvey.prototype.StringTotal = function() {
	var total = this.calculateTotal(arguments);
	return this.ToRegionNumber(total);
};


/// <summary>
/// Displays the running total for a list of topics.
/// </summary>
/// <param>
/// First arguement is dbheading of the question where to display the total.
/// Second arguement is list of fields to add.
/// e.g. 'Q1', 'Q1_1', 'Q1_2', 'Q2_3', 'Q2_4'
/// </param>
/// <param>List of dbHeadings e.g. 'Q1_1', 'Q1_2', 'Q1_3'</param>
VcSurvey.prototype.ShowRunningTotal = function() {
	var heading = arguments.pop() + "TOTAL";
	var element = document.getElementById(heading);
	if (element) element.innerHTML = this.StringTotal(arguments);
};

/// <summary>
/// Converts a number to a string with regional formatting.
/// </summary>
/// <param name="number">Number</param>
VcSurvey.prototype.ToRegionNumber = function(number) {
	var negative = (number < 0);

	// Convert to string
	number = number.toString();

	// Insert group seperators
	var parts = number.split('.');
	var base = Math.abs(parts[0]).toString();
	var groups = [];
	while(base.length > this.NumberGroupSizes) {
		var temp = base.substr(base.length - this.NumberGroupSizes);
		groups.unshift(temp);
		base = base.substr(0, base.length - this.NumberGroupSizes);
	}
	if(base.length > 0) { groups.unshift(base); }
	base = groups.join(this.NumberGroupSeparator);

	// Add decimal places if any with decimal symbol
	if (parts.length > 1) {
		number = base + this.NumberDecimalSeparator + parts[1];
	} else {
		number = base;
	}

	// Add minus sign if negative value
	if (negative) number = "-" + number;

	return number;
};

/// <summary>
/// Converts a region based number to US English Format.
/// </summary>
/// <param name="number">Number string for survey region</param>
VcSurvey.prototype.ToEnglishNumber = function(number) {
	while (number.indexOf(this.NumberGroupSeparator) != -1) {
		number = number.replace(this.NumberGroupSeparator, "");
	}
	// If seperator is ascii 160 space, also strip out ascii 32 space
	if (this.NumberGroupSeparator == "\u00A0") {
		while (number.indexOf("\ ") != -1) {
			number = number.replace("\ ", "");
		}
	}
	number = number.replace(this.NumberDecimalSeparator, ".");
	return number;
};

/// <summary>
/// Apply Odd/Even row style to a Matrix Question.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
VcSurvey.prototype.DisplayOddEvenRows = function(heading) {
	var table = document.getElementById("T" + heading);
	if (table) {	
		var tbody = table.getElementsByTagName("TBODY");
		if (tbody) {
			var viscount = 0;
			var rows = tbody[0].getElementsByTagName("TR");			
			for(var i = 0; i < rows.length; i++) {
				var row = rows[i];
				if (row.style.display != "none") {
					viscount++;
					row.className = (viscount % 2 == 1) ? "odd-row" : "even-row";
				}
			}
		}
	}
};

/// <summary>
/// Hides columns (choices) in a table question based on a previous choose many's answers.
/// </summary>
/// <param>
/// First arguement is value to test 1 for selected, 0 for not selected
/// Remaining arguements are the dependent value (Usually a placeholder e.g. %Q1_1%) and the column id.
/// e.g. 1, '1|Q2_A_C1', '0|Q2_A_C2', '0|Q2_A_C3', '1|Q2T4', '0|Q2_A_C4'
/// </param>
VcSurvey.prototype.DisplayDynamicColumns = function() {
	var value = arguments[0];
	for (var i = 1; i < arguments.length; i++) {
		var pair = arguments[i].split('|');
		if (pair[0] != value) this.HideTableColumn(pair[1]);	
	}
};

/// <summary>
/// Hides a column (of choices) in a table question for the given column id.
/// </summary>
/// <param name="columnId">Id of table column to hide</param>
VcSurvey.prototype.HideTableColumn = function(columnId) {
	var cells = document.getElementsByName(columnId);
	for(j = 0; j < cells.length; j++) {
		cells[j].style.display = "none";
	}
	// Fix column group span for FireFox
	var index = columnId.lastIndexOf('_');
	var value = Number(columnId.substr(index + 2));
	var colId = columnId.substr(0, index) + ((value > 0) ? "_COLNORM" : "_COLCODED");
	var colGroup = document.getElementById(colId);
	if (colGroup) {
		var newSpan = Number(colGroup.span) - 1;
		if (newSpan == 0) {
			colGroup.style.display = "none";
		} else {
			colGroup.span = Number(colGroup.span) - 1;
		}
	}
}

/// <summary>
/// Gets whether the specified table question topic row is visible.
/// </summary>
/// <param name="elementId">Id of table row element</param>
VcSurvey.prototype.IsTopicVisible = function(elementId) {
	var element = document.getElementById(elementId);
	return (element && element.style.display=="");
};

/// <summary>
/// Hides choices in a table question dropdown based on a previous choose many's answers
/// </summary>
/// <param>
/// First arguement is value to test 1 for selected, 0 for not selected
/// Second arguement is the dropdown prefix
/// Third arguement is number of topics
/// Remaining arguements are the dependent values (Usually a placeholder e.g. %Q1_1%).
/// e.g. 1, 'Q3_A', 5, '1', '0', '0', '1', '0'
/// </param>
VcSurvey.prototype.DisplayDynamicList = function() {
	var value = arguments[0];
	var tableSide = arguments[1];
	var topicCount = arguments[2];
	for (var i = 1; i <= topicCount; i++) {
		var dbHeading = tableSide + "_" + i;
		for (var j = 3; j < arguments.length; j++) {
			if (arguments[j] != value) {
				var choice = j - 2;
				this.RemoveListChoice(dbHeading, choice);
			}
		}
	}
};

/// <summary>
/// Removes all choices with the specified value from a dropdown or list box.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
/// <param name="choiceValue">Value of choice to remove</param>
VcSurvey.prototype.RemoveListChoice = function(heading, choiceValue) {
	var choiceList = document.getElementById(heading);
	var optionCount = choiceList.options.length - 1;

	for (var i = optionCount; i > 0; i--) {
		if (choiceList.options[i].value == choiceValue) choiceList.options[i] = null;
	}
};

/// <summary>
/// Randomizes the Choices in a Choose One List Box or Dropdown Question.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
VcSurvey.prototype.RandomizeListChoices = function(heading) {
	var selectedValue = this.GetChooseOneValue(heading);	
	var choiceList = document.getElementById(heading);
	var optionCount = choiceList.options.length - 1;
	var randomizedChoices = new Array();

	for (var i = 1; i <= optionCount; i++) {
		var option = choiceList.options[i];
		var fixed = option.getAttribute("fixed");
		if (!(fixed && fixed == "fixed")) {
			choiceList.options[i] = new Option(i, i);
			randomizedChoices.push(option);
		} 
	}

	randomizedChoices = this.randomizeArray(randomizedChoices);

	for (var i = 1; i <= optionCount; i++) {
		var option = choiceList.options[i];
		var fixed = option.getAttribute("fixed");
		if (!(fixed && fixed == "fixed")) {
			if (randomizedChoices.length == 0) break;
			choiceList.options[i] = randomizedChoices.pop();
		}
	}

	this.SetChooseOneValue(heading, selectedValue);
};

/// <summary>
/// Randomizes the Choices in a Choose One Radio Buttons or Choose Many Check Boxes.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
/// <param name="numChoices">Total number of choices in the question</param>
VcSurvey.prototype.RandomizeListButtons = function(heading, numChoices) {
	var randomizedChoices = new Array();

	for (var i = 1; i <= numChoices; i++) {
		var spanChoice = document.getElementById(heading + "C" + i);
		if (spanChoice) {
			var fixed = spanChoice.getAttribute("fixed");
			if (!(fixed && fixed == "fixed")) {
				randomizedChoices.push(spanChoice);
			}
		}
	}

	randomizedChoices = this.randomizeArray(randomizedChoices);

	for (var i = 1; i <= numChoices; i++) {
		if (randomizedChoices.length == 0) break;
		var spanChoice = document.getElementById(heading + "C" + i);
		if (spanChoice) {
			var fixed = spanChoice.getAttribute("fixed");
			if (!(fixed && fixed == "fixed")) {
				spanChoice.swapNode(randomizedChoices.pop());
			}
		}
	}
};

/// <summary>
/// Randomizes the rows in a Matrix Question.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
VcSurvey.prototype.RandomizeTableRows = function(heading, numChoices) {
	var table = document.getElementById("T" + heading);
	var tbodyElements = table.getElementsByTagName("tbody");
	var tbody = tbodyElements.item(0);
	var trElements = tbody.getElementsByTagName("tr");
	var randomizedRows = new Array();

	for (var i = 0; i < trElements.length; i++) {
		var tr = trElements.item(i);
		var fixed = tr.getAttribute("fixed");
		if (!(fixed && fixed == "fixed")) {
			randomizedRows.push(tr);
		}
	}

	randomizedRows = this.randomizeArray(randomizedRows);

	for (var i = 0; i < trElements.length; i++) {
		if (randomizedRows.length == 0) break;
		var tr = trElements.item(i);
		var fixed = tr.getAttribute("fixed");
		if (!(fixed && fixed == "fixed")) {
			if (tr.swapNode) {
				tr.swapNode(randomizedRows.pop());
			} else {
				tr.innerHTML = randomizedRows.pop().innerHTML;
			}
		}
	}
};

/// <summary>
/// Randomizes the choices in a Drag and Drop Rank Order Question.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
VcSurvey.prototype.RandomizeDragDropItems = function(heading, numChoices) {
	var ddroUl = document.getElementById("DDRO_" + heading);
	var liElements = ddroUl.getElementsByTagName("li");
	var randomizedItems = new Array();

	for (var i = 0; i < liElements.length; i++) {
		var li = liElements.item(i);
		var fixed = li.getAttribute("fixed");
		if (!(fixed && fixed == "fixed")) {
			randomizedItems.push(li);
		}
	}

	randomizedItems = this.randomizeArray(randomizedItems);

	for (var i = 0; i < liElements.length; i++) {
		if (randomizedItems.length == 0) break;
		var li = liElements.item(i);
		var fixed = li.getAttribute("fixed");
		if (!(fixed && fixed == "fixed")) {
			if (li.swapNode) {
				li.swapNode(randomizedItems.pop());
			} else {
				li.innerHTML = randomizedItems.pop().innerHTML;
			}
		}
	}
};

/// <summary>
/// Private - Randomizes an array of items.
/// </summary>
/// <param name="heading">Array of items to randomize</param>
VcSurvey.prototype.randomizeArray = function(array) {
	for (var i = 0; i < array.length; i++) {
		var j = Math.floor(Math.random() * array.length);
		var item1 = array[i];
		var item2 = array[j];
		array[i] = item2;
		array[j] = item1;
	}
	return array;
};

/// <summary>
/// Jumps to the specified question on the current page and displays an optional alert message.
/// </summary>
/// <obsolete>
/// Used for pre Vovici v5 client-side validation. Maintained for backwards compatibility.
/// <obsolete>
/// <param name="heading">Anchor Heading to jump to e.g. A1 for Question Q1</param>
/// <param name="message">Alert message to display</param>
VcSurvey.prototype.GotoQuestion = function(heading, message) {
	window.location = "#" + heading;
	if (message) {
		alert(message);
	}
};

/// <summary>
/// Jumps to the first validation error on the page.
/// Returns true if success.
/// </summary>
VcSurvey.prototype.GotoFirstError = function() {
	if (this.firstValidationMessage) {
		var messageElement = document.getElementById(this.firstValidationMessage);
		var selectedPosX = 0;
		var selectedPosY = 0;
		while(messageElement != null){
			selectedPosX += messageElement.offsetLeft;
			selectedPosY += messageElement.offsetTop;
			messageElement = messageElement.offsetParent;
		}
		window.scrollTo(selectedPosX,selectedPosY);
		return true;
	}
	return false;
};

/// <summary>
/// Given a Choose One Dropdown or List Box question
/// Jumps to the anchor specified in the destination attribute for the selected choice.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
VcSurvey.prototype.SelectJump = function(heading) {
	// Get Selected Choice
	var choiceList = document.getElementById(heading);
	var selectedOption = choiceList.options[choiceList.selectedIndex];
	// Jump to destination if set
	var destination = selectedOption.getAttribute("destination");
	if (destination && destination != '') {
		window.location = "#" + destination;
	}
}

/// <summary>
/// Configure's a Rank Order Question displayed as Radio Buttons
/// To only allow each rank to only be selected once.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
/// <param name="topics">Number of topics in question</param>
/// <param name="choices">Number of choices(ranks) in question</param>
VcSurvey.prototype.ConfigureRankOrder = function(heading, topics, choices) {
	this.HideTableColumn(heading + "_C0");
	for (var topic = 1; topic <= topics; topic++) {
		for (var choice = 1; choice <= choices; choice++) {
			var id = heading + "_" + topic + "_" + choice;
			var element = document.getElementById(id);
			if (element) {
				survey.AddEvent(element, "click", function(e) {
					var targ;
					if (!e) var e = window.event;
					if (e.target) targ = e.target;
					else if (e.srcElement) targ = e.srcElement;
					for (var topic = 1; topic <= topics; topic++) {
						for (var choice = 1; choice <= choices; choice++) {
							var id = heading + "_" + topic + "_" + choice;
							var element = document.getElementById(id);
							if (element.value == targ.value && element.id != targ.id) {
								element.checked = false;
							}
						}
					}
				});
			}
		}
	}
}

/// <summary>
/// Update sliders vs text boxes.
/// </summary>
VcSurvey.prototype.UpdateSliders = function() {
	$('input.slidertb').each(function() {
		var fieldName = $(this).attr('id');
		var sliderID = "#" + fieldName + "S";
		var minVal = $(sliderID).slider('option', 'min');
		var val = (!isNaN(parseFloat($(this).val()))) ? $(this).val() : minVal;
		$("#" + fieldName + "S").slider('option', 'value', survey.CheckSliderValue(fieldName,
				$(sliderID).slider('option', 'step'),
				val,
				minVal,
				$(sliderID).slider('option', 'max'))
				);
	});
}

/// <summary>
/// Set appropriate boundary values for slider.
/// </summary>
VcSurvey.prototype.CheckSliderValue = function(fieldName, stepVal, val, minVal, maxVal) {
	var smin = $("#" + fieldName + "S").slider('option', 'min') + stepVal;
	var smax = $("#" + fieldName + "S").slider('option', 'max') - stepVal;
	if (val <= minVal) return smin - stepVal;
	if (val >= maxVal) return smax + stepVal;
	var v = val;
	if (val < smin) v = stepVal * ((val - minVal) / (smin - minVal)) + (smin - stepVal);
	else if (val > smax) v = stepVal * ((val - smax) / (maxVal - smax)) + smax;
	return v;
}

/// <summary>
/// Private function for slider support.
/// Update slider value for both:UI text box and hidden value.
/// </summary>
VcSurvey.prototype.UpdateSliderValue = function(fieldName, currentvalue, minVal, maxVal, stepVal) {
	var defaultVal = $("#" + fieldName + "S").slider('option', 'value');
	var v = currentvalue;
	if ((v != minVal) && (v != maxVal)) v = survey.RoundToGrid(currentvalue, defaultVal, minVal, maxVal, stepVal);
	if ($("#" + fieldName).val() != v) $("#" + fieldName).val(v);
	v = survey.CheckSliderValue(fieldName, stepVal, v, minVal, maxVal);
	if (defaultVal != v) {
		$("#" + fieldName + "S").slider('option', 'value', v);
	}
}

/// <summary>
/// Private function for slider support.
/// Provide appropriate round for real numbers.
/// </summary>
VcSurvey.prototype.RoundToGrid = function(val, defaultVal, minVal, maxVal, valueInterval) {
	val = parseFloat(val);
	if (isNaN(val)) {
		if (isNaN(parseFloat(defaultVal))) return minVal;
		return defaultVal;
	}
	val = Math.round(val / valueInterval) * valueInterval;
	val = Math.round(val * 10000) / 10000;
	if (val < minVal) val = minVal;
	if (val > maxVal) val = maxVal;
	return val;
}

/// <summary>
/// Private function for slider support.
/// In case of enable JavaScript show variant with JS.
/// </summary>
VcSurvey.prototype.checkJavascript = function(fieldName) {
	$(".slider-cell").show();
	$(".marksTbl").show();
	$(".slider :text").addClass("slidertb");
	$(".sliderdivJS").addClass("sliderdiv");
	$(".sliderJS").addClass("slider");
}

/// <summary>
/// Adds a slider control for the specified fill in the blank topic to the page.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
/// <param name="minVal">Minimum Range of Slider</param>
/// <param name="maxVal">Maximum Range of Slider</param>
/// <param name="stepVal">Step between values</param>
/// <param name="totalFunction">Function to call after slider changed (e.g. Show Running Total)</param>
VcSurvey.prototype.CreateSlider = function(fieldName, minVal, maxVal, stepVal, size, totalFunction) {
	survey.checkJavascript(fieldName);
	var sliderID = "#" + fieldName + "S";
	var slidervalueID = "#" + fieldName;
	var slidermaxval = maxVal;
	var sliderminval = minVal;
	if (stepVal > 0) {
		sliderminval = survey.RoundToGrid(minVal + stepVal, minVal + stepVal, minVal, maxVal, stepVal) - stepVal;
		if (sliderminval > minVal) sliderminval -= stepVal;
		slidermaxval = Math.ceil((maxVal - sliderminval) / stepVal) * stepVal + sliderminval;
	}
	$(sliderID).slider({
		range: "min",
		min: sliderminval,
		max: slidermaxval,
		step: stepVal,
		slide: function(event, ui) {
			survey.UpdateSliderValue(fieldName, ui.value, minVal, maxVal, stepVal);
		}
	});
	// Set value from form (Preselected, Piped or Infused)
	// If not valid, set to blank, Not Answered
	var formValue = this.GetTextValue(fieldName);
	try {
		$(sliderID).slider('option', 'value', parseFloat(formValue));
	} catch (e) { }

	$(slidervalueID).attr('size', size);
	if (totalFunction) {
		$(sliderID).bind('slidechange', function(event, ui) { totalFunction(); });
	}
	survey.UpdateSliderValue(fieldName, $(sliderID).slider("value"), minVal, maxVal, stepVal);
	if (isNaN(parseFloat(formValue))) {
		$(slidervalueID).val('');
	}

	$(slidervalueID).change(function(e) {
		survey.UpdateSliderValue(fieldName, $(this).val(), minVal, maxVal, stepVal);
		if (totalFunction) totalFunction();
	});
	$(slidervalueID).keyup(function(e) {
		if (!isNaN(parseFloat($(this).val()))) {
			$(sliderID).slider('option', 'value', survey.CheckSliderValue(fieldName, stepVal, $(this).val(), minVal, maxVal));
		}

	});

	$('input[type = "reset"]').unbind('click.resetSliders').bind('click.resetSliders', function() {
		$('input.slidertb').each(function() {
		$(this).val($(this)[0].defaultValue);
		});
		survey.UpdateSliders();
	})
}


/// <summary>
/// Resets client-side validation.
/// </summary>
VcSurvey.prototype.ResetValidation = function(messageId) {
	this.firstValidationMessage = null;
	for (messageId in this.validationMessages) {
		var messageElement = document.getElementById(messageId);
		messageElement.style.display = "none";
	}
};

/// <summary>
/// Sets ghost text for the spcified fill in the blank question.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
/// <param name="text">Text to display when field is empty.</param>
VcSurvey.prototype.SetGhostText = function(heading, text) {
	var element = document.getElementById(heading);
	if (element) {
		element.setAttribute("ghostText", text);
		element.setAttribute("originalStyle", element.className);
		if (element.value == '') {
			element.value = text;
			element.className += " ghost-text";
			this.AddEvent(element, "focus", function(e){
			if (element.className.match("ghost-text")) {
					element.className = element.getAttribute("originalStyle");
					element.value = '';
				}
			});
			this.AddEvent(element, "blur", function(e){
				if (element.value == '') {
					element.className += " ghost-text";
					element.value = element.getAttribute("ghostText");
				}
			});
		}
	}
};

/// <summary>
/// Clear ghost text on all text boxes for submission.
/// </summary>
VcSurvey.prototype.ClearGhostText = function() {
	var form = survey.SurveyForm();
	var inputElements = form.getElementsByTagName("input");
	for (var i = 0; i < inputElements.length; i++) {
		var inputElement = inputElements.item(i);
		if (inputElement.type == "text") {
			var ghostText = inputElement.getAttribute("ghostText");
			if (ghostText && ghostText == inputElement.value) {
				inputElement.value = '';
			}
		}
	}
};

/// <summary>
/// Displays the specified validation message.
/// </summary>
/// <param name="messageId">Id of validation message to display</param>
/// <param name="placeHolder1">Optional value to replace %1 in validation message</param>
/// <param name="placeHolder2">Optional value to replace %2 in validation message</param>
VcSurvey.prototype.ShowValidationMessage = function(messageId, placeHolder1, placeHolder2) {
	var messageElement = document.getElementById(messageId);
	if (messageElement) {
		// We need to store the validation message to preserve placeholders
		if (!this.validationMessages[messageId]) {
			this.validationMessages[messageId] = messageElement.innerHTML;
		}
		// Get message text and replace place holders
		var messageText = this.validationMessages[messageId];
		if (placeHolder1) messageText = messageText.replace("%1", placeHolder1);
		if (placeHolder2) messageText = messageText.replace("%2", placeHolder2);
		messageElement.innerHTML = messageText;
		// Make Visible
		messageElement.style.display = "";
		if (!this.firstValidationMessage) this.firstValidationMessage = messageId;
	}
};

/// <summary>
/// Shows a Tool Tip for the specified glossary id relative to the calling word.
/// </summary>
/// <param name="heading">The element triggering the tool tip</param>
/// <param name="glossaryId">A valid glossary id</param>
VcSurvey.prototype.ShowToolTip = function(element, glossaryId) {
	var glossaryElement = document.getElementById(glossaryId);
	if (glossaryElement) {
		glossaryElement.style.visibility = "visible";
		// Set Top
		var top = 0;
		var topElement = element;
		while(topElement.offsetParent) {
			top += topElement.offsetTop;
			topElement = topElement.offsetParent;
		}
		top -= glossaryElement.offsetHeight
		if (top < 0) top = element.offsetTop + element.offsetHeight;
		glossaryElement.style.top = top + "px";
		// Set Left
		var width = document.body.offsetWidth;
		var left = 0;
		var leftElement = element;
		while(leftElement.offsetParent) {
			left += leftElement.offsetLeft;
			leftElement = leftElement.offsetParent;
		}
		if ((left + glossaryElement.offsetWidth) > width) {
			left = Math.max(0, width - glossaryElement.offsetWidth);
		}
		glossaryElement.style.left = left + "px";
	}
};

/// <summary>
/// Hides the Tool Tip with the specified glossary id for the calling word.
/// </summary>
/// <param name="heading">The element triggering the tool tip</param>
/// <param name="glossaryId">A valid glossary id</param>
VcSurvey.prototype.HideToolTip = function(element, glossaryId) {
	var glossaryElement = document.getElementById(glossaryId);
	if (glossaryElement) {
		glossaryElement.style.visibility = "hidden";
	}
};

/// <summary>
/// Displays the survey Jump Page.
/// </summary>
VcSurvey.prototype.ShowJumpPage = function() {
	var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
	var url = document.PdcSurvey.action + "?s=" + document.PdcSurvey.PdcSessionId.value + "&jump=1";
	if (!is_chrome && window.showModalDialog) {
		window.showModalDialog(url, document.PdcSurvey, "status:no;resizable:yes;center:yes;help:no;minimize:no;maximize:yes;scroll:yes;statusbar:no;");
	} else {
		window.open(url, document.PdcSurvey.PdcSessionId.value + "JUMP", "modal=yes, location=no, menubar=no, resizable=yes, scrollbars=yes, status=no, toolbar=no, dialog=yes");
	}
};

/// <summary>
/// Emails the current result page to the participants e-mail address on file.
/// </summary>
/// <param name="confirmation">Optional confirmation text to display after sending Ajax request.</param>
VcSurvey.prototype.EmailResults = function(confirmText) {
	var currentPage = document.getElementById("PdcCurrentPage");
	if (currentPage) {
		var args = "EMAILRESULTS;" + currentPage.value;
		this.AjaxRequest(args);
		if (confirmText) alert(confirmText);
	}
};

/// <summary>
/// Emails the current result page to the participant prompting for an e-mail address.
/// </summary>
/// <param name="promptText">Text to prompt for e-mail address.</param>
/// <param name="confirmText">Optional confirmation text to display after sending Ajax request.</param>
/// <param name="incorrectEmailText">Optional text to display if entered email address is incorrect.</param>
VcSurvey.prototype.EmailResultsPrompt = function(promptText, confirmText, incorrectEmailText) {
	var currentPage = document.getElementById("PdcCurrentPage");
	if (currentPage) {
		var email = prompt(promptText, '');
		if (email) {
			if (email.match(/^[\w_\-\.\']+[\%\+]?[\w_\-\']*\@[0-9a-zA-Z\-]+\.[0-9a-zA-Z\-\.]+$/)) {
				var args = "EMAILRESULTS;" + currentPage.value + ";" + email;
				this.AjaxRequest(args);
				if (confirmText) alert(confirmText);
			} else if (incorrectEmailText && incorrectEmailText != '') {
				alert(incorrectEmailText);
			}
		}
	}
};

/// <summary>
/// Populates the following list based on the
/// item selected in the specified list.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
/// <param name="index">Index of list who's value has changed</param>
VcSurvey.prototype.GetNextList = function(heading, index) {
	this.ClearSubsequentLists(heading, index);
	var listElement = document.getElementById(heading + "_" + index);
	var selectedItem = listElement.options[listElement.selectedIndex];
	var listId = selectedItem.getAttribute("listid");
	if (listId && listId != 0) {
		var args = "GETLIST;" + heading + ";" + index + ";" + listId;
		this.AjaxRequest(args);
	}
};

/// <summary>
/// Populates the first list based on the listid.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
/// <param name="index">Index of list who's value has changed</param>
VcSurvey.prototype.GetFirstList = function(heading, listId) {
	var args = "GETLIST;" + heading + ";" + 0 + ";" + listId;
	this.AjaxRequest(args);
};

/// <summary>
/// Populates the following list using a web service call.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
/// <param name="index">Index of list who's value has changed</param>
VcSurvey.prototype.GetNextListWS = function(heading, index) {
	// Get selected values of list items up to and including this list
	var listValues;
	for(var i = 1; i <= index; i++) {
		var nextListElement = document.getElementById(heading + "_" + i);
		if (nextListElement && nextListElement.tagName == "SELECT") {
			var selectedIndex = nextListElement.selectedIndex;
			if (selectedIndex >= 0) {
				var selectedValue = nextListElement.options[selectedIndex].value;
				listValues += ";" + heading + "_" + i + "=" + selectedValue;
			}
		}
	}
	this.ClearSubsequentLists(heading, index);
	var args = "GETLISTWS;" + heading + ";" + index + listValues;
	this.AjaxRequest(args);
};

/// <summary>
/// Removes all the choices in the list following the
/// specified index except for the list caption.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
/// <param name="index">Index of list after which choices should be removed</param>
VcSurvey.prototype.ClearSubsequentLists = function(heading, index) {
	var nextListIndex = parseInt(index) + 1;
	var nextListElement = document.getElementById(heading + "_" + nextListIndex);
	while (nextListElement && nextListElement.tagName == "SELECT") {
		var optionCount = nextListElement.options.length;
		for(var i = 0; i < optionCount; i++) {
			nextListElement.options[1] = null;
		}
		nextListElement.disabled = true;
		nextListIndex++;
		nextListElement = document.getElementById(heading + "_" + nextListIndex);
	}
};

/// <summary>
/// Populates the specified list from an XML collection of ListItems.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
/// <param name="index">Index of list after to populate</param>
VcSurvey.prototype.PopulateList = function(heading, index, xml) {
	var listElement = document.getElementById(heading + "_" + index);
	var listItems = xml.documentElement;
	var optionCount = 1;
	for (i = 0; i < listItems.childNodes.length; i++) {
		var listItem = listItems.childNodes[i];
		if (listItem.nodeType == 1) {
			listElement.options[optionCount] = new Option(listItem.firstChild.firstChild.nodeValue, listItem.getAttribute('value'));
			listElement.options[optionCount].setAttribute("listid", listItem.getAttribute('targetlistid'));
			if (listItem.getAttribute("selected") == "true") {
				listElement.options[optionCount].setAttribute("selected", "selected");
				if(listElement.onchange) {
					listElement.onchange();
				}
			}
			optionCount++;
		}
	}
	listElement.disabled = false;
};

/// <summary>
/// Creates an instance of the XML HTTP Request object
/// Used for subsequent Ajax Requests.
/// </summary>
VcSurvey.prototype.GetXmlHTTP = function() {
	if (window.XMLHttpRequest) {
		return new XMLHttpRequest();
	} else if (window.ActiveXObject) {
		return new ActiveXObject("Microsoft.XMLHTTP");
	}
};

/// <summary>
/// Submits an Ajax Request to the Survey Engine.
/// </summary>
/// <param name="parameters">Arguments to submit with Ajax Request</param>
VcSurvey.prototype.AjaxRequest = function(parameters) {
	var xmlhttp = this.GetXmlHTTP();
	if (xmlhttp != null) {
		xmlhttp.onreadystatechange = function() {
			if (xmlhttp.readyState == 4) {
				// Safari may return undefined
				if (xmlhttp.status == 200 || typeof(xmlhttp.status) == 'undefined') {
					var parts = parameters.split(';');
					var xml = null;
					if (window.ActiveXObject) {
						xml = new ActiveXObject("Microsoft.XMLDOM");
						xml.loadXML(xmlhttp.responseText);
					} else {
						xml = xmlhttp.responseXML;
					}
					switch(parts[0]) {
						case "GETLIST":
						case "GETLISTWS":
							survey.PopulateList(parts[1], parseInt(parts[2]) + 1, xml);
							break;
					}
				} else {
					alert("Ajax Request Failed: " + xmlhttp.status);
				}
			}
		}
		// Strip server path
		var url = this.SurveyForm().action;
		if(url.indexOf("/") != 0) {
			var pos = url.indexOf("//");
			pos = url.indexOf("/", pos + 2);
			url = url.substr(pos);
		}
		url = url.replace("se.ashx", "list.ashx");
		xmlhttp.open("GET", url, true);
		// Safari Caching Bug
		xmlhttp.setRequestHeader('If-Modified-Since','Wed, 15 Nov 1995 00:00:00 GMT');
		xmlhttp.setRequestHeader("isajaxrequest", "1");
		xmlhttp.setRequestHeader("ajaxargs", parameters);
		xmlhttp.setRequestHeader("PdcSessionId", this.GetTextValue("PdcSessionId"));
		xmlhttp.send('');
	}
};

/// <summary>
/// Registers an event for an element.
/// </summary>
/// <param name="element">Element on which to fire an event</param>
/// <param name="eventName">Name of event to fire</param>
/// <param name="eventFunction">Function to run on element event</param>
VcSurvey.prototype.AddEvent = function(element, eventName, eventFunction) {
	if (element.addEventListener) {
		element.addEventListener(eventName, eventFunction, false);
	} else if (element.attachEvent) {
		element.attachEvent("on" + eventName, eventFunction);
	} else {
		element["on" + eventName] = eventFunction;
	}
};

/// <summary>
/// Prevents form from submitting by pressing Enter key in a Fill In Question.
/// </summary>
VcSurvey.prototype.DisableEnterKey = function() {
	var form = survey.SurveyForm();
	if (form) {
		var inputElements = form.getElementsByTagName("input");
		for (var i = 0; i < inputElements.length; i++) {
			var inputElement = inputElements.item(i);
			// Attach OnKeyPress event to fill in's
			if (inputElement.type == "text" || inputElement.type == "password") {
				survey.AddEvent(inputElement, "keypress", function(e){
					// If use hits Enter
					if(e.keyCode==13) {
						// Cancel Form Submission that bypasses onsubmit event
						e.returnValue = false;
						e.cancel = true;
						// Required For FireFox
						if(e.preventDefault)e.preventDefault();
						// Submit the form, calling validation
						survey.AutoAdvance();
					}
				});
			}
		}
	}
};

/// <summary>
/// Update Rank numbers on right pane
/// </summary>
VcSurvey.prototype.UpdateRankNumberList = function(rank_area_id) {
	var j = 0;
	var lastLiElement = null;
	var rank = null;

	$("ul.sortable_destination[rank_area_id='" + rank_area_id + "'] li.choice_item").each(function(i, liElement) {
		lastLiElement = liElement;

		$(liElement).find("img").css("width", "40px"); // Hack for IE 6
		$(liElement).find("div.img").css("width", "40px"); // Hack for IE 6
		$(liElement).find("div.left_margin").css("width", "8px"); // Hack for IE 6
		
		if (rank == null) {
			rank = $(liElement).attr("rank");
		}
	});

	if (lastLiElement != null) {
		$("ul.sortable_destination[rank_area_id='" + rank_area_id + "'] li.drag_here").insertAfter(lastLiElement);
	}

	$("ul.sortable_destination[rank_area_id='" + rank_area_id + "'] li div.rank_number").each(function(i, divNumber) {
		j++;
		$(divNumber).html(j.toString() + '.');
	});

	$("div.response-set[rank_area_id='" + rank_area_id + "'] input[type='radio']").each(function(i, radioButton) {
		$(radioButton).attr("checked", false);
	});

	j = 0;
	$("ul.sortable_destination[rank_area_id='" + rank_area_id + "'] li.choice_item").each(function(i, liElement) {
		j++;
		$("#" + $(liElement).attr("choice_id") + j.toString()).attr("checked", "checked");
		$(liElement).css("border", "none 0px");

		// Fix the height of choice in right panel
		var textCellDiv = $(liElement).find("p.text_cell");
		var lineHeight = $(textCellDiv).css("line-height");
		var fontSize = $(textCellDiv).css("font-size");
		var twoLineHeight = 2 * parseFloat(lineHeight);
		var maxHeight = 40;

		if (twoLineHeight <= maxHeight) {
			$(liElement).find("div.choice_text").css("height", twoLineHeight.toString() + "px");
		} else if (twoLineHeight / 2 <= maxHeight) {
			twoLineHeight /= 2;
			$(liElement).find("div.choice_text").css("height", twoLineHeight.toString() + "px");
		}
	});

	$("ul.sortable_source[rank_area_id='" + rank_area_id + "'] div.choice_text").each(function(i, divElement) {
		$(divElement).css("height", "auto");
	});

	$("ul.sortable_source[rank_area_id='" + rank_area_id + "'] div.rank_number").each(function(i, divElement) {
		$(divElement).html('');
	});

	$("ul.sortable_source[rank_area_id='" + rank_area_id + "'] li.choice_item").each(function(i, liElement) {
		$(liElement).css("border", "none 0px");
		$(liElement).css("border-bottom", "solid 1px #eeeeee");

		$(liElement).find("img").css("width", "90px"); // Hack for IE 6
		$(liElement).find("div.img").css("width", "90px"); // Hack for IE 6
		$(liElement).find("div.left_margin").css("width", "8px"); // Hack for IE 6
	});

	if (rank != null) {
		rank = parseInt(rank);

		if (j >= rank) {
			var disabledDragging = "ul.sortable_source[rank_area_id='" + rank_area_id + "'], ul.sortable_destination[rank_area_id='-1']";
			$("ul.sortable_source[rank_area_id='" + rank_area_id + "']").sortable("option", "connectWith", disabledDragging);
			$("ul.sortable_destination[rank_area_id='" + rank_area_id + "'] li.drag_here").hide();
		} else {
			var enabledDragging = "ul.sortable_source[rank_area_id='" + rank_area_id + "'], ul.sortable_destination[rank_area_id='" + rank_area_id + "']";
			$("ul.sortable_source[rank_area_id='" + rank_area_id + "']").sortable("option", "connectWith", enabledDragging);
			$("ul.sortable_destination[rank_area_id='" + rank_area_id + "'] li.drag_here").show();
		}
	} else {
		var enabledDragging = "ul.sortable_source[rank_area_id='" + rank_area_id + "'], ul.sortable_destination[rank_area_id='" + rank_area_id + "']";
		$("ul.sortable_source[rank_area_id='" + rank_area_id + "']").sortable("option", "connectWith", enabledDragging);
		$("ul.sortable_destination[rank_area_id='" + rank_area_id + "'] li.drag_here").show();
	}
}

/// <summary>
/// Copy saved choices to setup Drag&Drop question on start
/// </summary>
VcSurvey.prototype.CopySavedChoicesToDragDrop = function() {
	$("div.response-set[rank_order='1']").each(function(i, wrapDivElement) {
		var rankAreaId = $(wrapDivElement).attr("rank_area_id");
		var j = 0;
		var selectedChoices = new Array();
		var rank = parseInt($("ul.sortable_source[rank_area_id='" + rankAreaId + "'] li.choice_item").attr("rank"));

		for (var k = 1; k <= rank; k++) {
			$("ul.sortable_source[rank_area_id='" + rankAreaId + "'] li.choice_item").each(function(i, liElement) {
				j++;
				var radioSelector = "#" + $(liElement).attr("choice_id") + (k).toString();
				var isChecked = $(radioSelector).attr("checked");

				if (isChecked) {
					selectedChoices.push(liElement);
				}
			});
		}

		for (var i = 0; i < selectedChoices.length; i++) {
			$(selectedChoices[i]).appendTo("ul.sortable_destination[rank_area_id='" + rankAreaId + "']");
		}

		survey.UpdateRankNumberList(rankAreaId);
	});
}

/// <summary>
/// Main function, OnLoadPage
/// </summary>
$(function() {
	survey.CopySavedChoicesToDragDrop();
	$("li.choice_item").addClass("pointer");

	$("ul.sortable_source").each(function(i, ulElement) {
		var rankOrderId = $(ulElement).attr("rank_area_id");

		$(ulElement).sortable({
			connectWith: "ul.sortable_source[rank_area_id='" + rankOrderId + "'], ul.sortable_destination[rank_area_id='" + rankOrderId + "']",
			tolerance: 'intersect',
			dropOnEmpty: true,
			opacity: 0.6,
			placeholder: "choice_destination",
			items: "li.choice_item[rank_area_id='" + rankOrderId + "']",
			start: function(event, ui) {
				ui.helper.css("border", "solid 1px #cccccc");
			},
			beforeStop: function(event, ui) {
				survey.UpdateRankNumberList($(ulElement).attr("rank_area_id"));
			}
		});
	});

	$("ul.sortable_destination").each(function(i, ulElement) {
		var rankOrderId = $(ulElement).attr("rank_area_id");

		$(ulElement).sortable({
			connectWith: "ul.sortable_source[rank_area_id='" + rankOrderId + "'], ul.sortable_destination[rank_area_id='" + rankOrderId + "']",
			tolerance: 'intersect',
			dropOnEmpty: true,
			opacity: 0.6,
			placeholder: "choice_destination",
			items: "li.choice_item[rank_area_id='" + rankOrderId + "']",
			beforeStop: function(event, ui) {
				survey.UpdateRankNumberList(rankOrderId);
			}
		});
	});

	$("ul.sortable_source, ul.sortable_destination").disableSelection();

	$(".choice_item").click(function(event) {
		$("ul.sortable_source li").each(function(i, liElement) {
			$(liElement).removeClass("selected_rank_choice");
			$(liElement).find("div.arrow_button").hide();
		});

		$("ul.sortable_destination li").each(function(i, liElement) {
			$(liElement).removeClass("selected_rank_choice");
			$(liElement).find("div.arrow_button").hide();
		});

		if ($(event.currentTarget).parents("ul.sortable_destination")[0] != undefined) {
			$(event.currentTarget).addClass("selected_rank_choice");
			$(event.currentTarget).find("div.arrow_button").show();
		}

		survey.UpdateRankNumberList($(event.currentTarget).parents("ul.sortable_destination").attr("rank_area_id"));
	});

	$("div.remove").click(function(event) {
		var rankOrderId = $(event.currentTarget).parents("ul.sortable_destination").attr("rank_area_id");
		var liElement = $(event.currentTarget).parents("li");
		liElement.removeClass("selected_rank_choice");
		$("ul.sortable_source[rank_area_id='" + rankOrderId + "']").append($(liElement));
		survey.UpdateRankNumberList(rankOrderId);
		$(liElement).click(); // Hack for IE 6
	});

	$("div.arrow_button").click(function(event) {
		var rankOrderId = $(event.currentTarget).parents("ul.sortable_destination").attr("rank_area_id");

		if ($(event.currentTarget).hasClass("rank_up_item")) {
			var prevItem = $("ul.sortable_destination[rank_area_id='" + rankOrderId + "'] li.selected_rank_choice").prev("li");
			$(prevItem).before($("ul.sortable_destination[rank_area_id='" + rankOrderId + "'] li.selected_rank_choice"));
		}
		else if ($(event.currentTarget).hasClass("rank_down_item")) {
			var nextItem = $("ul.sortable_destination[rank_area_id='" + rankOrderId + "'] li.selected_rank_choice").next("li");

			if (!$(nextItem).hasClass("drag_here")) {
				$(nextItem).after($("ul.sortable_destination[rank_area_id='" + rankOrderId + "'] li.selected_rank_choice"));
			}
		}

		survey.UpdateRankNumberList(rankOrderId);
		$(event.currentTarget).parents("li").click(); // Hack for IE6, 7, 8
	});
});

/// <summary>
/// Image Button click event handler
/// </summary>
VcSurvey.prototype.ImageButtonClick = function(heading, event) {
if ($(event.target).hasClass('specify') || $(event.srcElement).hasClass('specify')) return;
	var inputElement = document.getElementById(heading);
	if (inputElement.type == 'radio')
		inputElement.checked = true;
	else
		inputElement.checked = !inputElement.checked;
	survey.UpdateChoicesAppearance();
}

/// <summary>
/// Check box click
/// </summary>
VcSurvey.prototype.CheckBoxClick = function(heading, event) {
	survey.UpdateChoicesAppearance();
	event.cancelBubble = true;
}

/// <summary>
/// Update appearance of choices
/// </summary>
VcSurvey.prototype.UpdateChoicesAppearance = function() {
	var sfEls = document.getElementsByTagName("DIV");

	for (var i = 0; i < sfEls.length; i++) {
		if ($(sfEls[i]).hasClass("choice-box")) {
			inputElement = sfEls[i].getElementsByTagName("INPUT")[0];

			if (inputElement.checked) {
				if (!$(sfEls[i]).hasClass("selected")) {
					$(sfEls[i]).addClass("selected");
				}
			}
			else {
				if ($(sfEls[i]).hasClass("selected")) {
					$(sfEls[i]).removeClass("selected");
				}
			}
		}
	}
}

/// <summary>
/// Implementation of hover logic (only for IE6)
/// </summary>
SFHover = function() {
 	var sfEls = document.getElementsByTagName("DIV");
	for (var i = 0; i < sfEls.length; i++) {
		if ($(sfEls[i]).hasClass("choice-box")) {
			sfEls[i].onmouseover = function() {
				this.className += " hover";
			}
			sfEls[i].onmouseout = function() {
				this.className = this.className.replace(new RegExp(" hover"), "");
			}
		}
	}
}

if (window.attachEvent) window.attachEvent("onload", SFHover);
