// SurveySolutions/EFM Client Side Survey API
// (c) 2006 Perseus Development Corp.
// Version: 1.0.0

function PerseusSurvey() {	
	this.Form = document.PdcSurvey;
	this.NumberDecimalSeparator = ".";	
	this.NumberGroupSeparator = ",";	
	this.NumberGroupSizes = 3;	
}


/// <summary>
/// Auto Advances the survey to the next page, 
/// or submits if on the last page.
/// </summary>
PerseusSurvey.prototype.AutoAdvance = function() {
	if (document.PdcSurvey.next) {
		document.PdcSurvey.next.click();
	} else if (document.PdcSurvey.submit) {
		document.PdcSurvey.submit.click();
	} else {
		document.PdcSurvey.submit();
	}
}
	
/// <summary>
/// Returns the value for a fill in the blank or essay question as a string.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
PerseusSurvey.prototype.GetTextValue = function(heading) {
	var value = '';
	var inputField = document.getElementById(heading);	
	if (inputField) value = inputField.value;
	return value.toString();
}

/// <summary>
/// Returns the value for a fill in the blank  as number.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
PerseusSurvey.prototype.GetNumericValue = function(heading) {
	var textValue = this.GetTextValue(heading);
	var numValue = this.ToEnglishNumber(textValue);
	return Number(numValue);
}

/// <summary>
/// Indicates if the specified essay question, fill in the blank topic
/// or choose one list/dropdown has been answered.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
PerseusSurvey.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 value = inputField.value;
						return (value != '');				
				}
				break;
			// Essay
			case "TEXTAREA":
				var value = inputField.value;
				return (value != '');	
				break;
			// Choose One List/Dropdown
			case "SELECT":
				var selectedIndex = inputField.selectedIndex;
				var value = inputField.options[selectedIndex].value;
				return (value != '0' && value != '');
				break;
		}
	} else {
		// Test if its a date
		if (document.getElementById(heading + "_DD")) {
			var monthElement = document.getElementById(heading + "_MM");
			var selectedIndex = monthElement.selectedIndex;
			var month = Number(monthElement.options[selectedIndex].value);
			var day = Number(document.getElementById(heading + "_DD").value);
			var year = Number(document.getElementById(heading + "_YYYY").value);
			if (month != '' && day != '' & year != '') return true;
		}
	}
	return false;
}

/// <summary>
/// Given an 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'</param>
PerseusSurvey.prototype.AnyAnswered = function(heading) {
	for (var x = 0; x < arguments.length; x++){
		if (this.IsAnswered(arguments[x])) return true;
	}
	return false;
}

/// <summary>
/// Given an 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'</param>
PerseusSurvey.prototype.AnyNotAnswered = function(heading) {
	for (var x = 0; x < arguments.length; x++){
		if (!this.IsAnswered(arguments[x])) return true;
	}
	return false;
}

/// <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>
PerseusSurvey.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>
PerseusSurvey.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>
PerseusSurvey.prototype.IsInRange = function(heading, minValue, maxValue) {
	var numValue = this.GetNumericValue(heading);
	if (minValue && numValue < minValue) return false;
	if (maxValue && numValue > maxValue) return false;
	return true;
}

/// <summary>
/// Indicates if the specified fill in topic contains a whole number.
/// </summary>
/// <param name="heading">A valid dbHeading</param>
PerseusSurvey.prototype.IsInteger = function(heading) {
	var inputField = document.getElementById(heading);
	if (inputField) {
		var text = inputField.value;
		// 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;
		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>
PerseusSurvey.prototype.IsFloat = function(heading) {
	var inputField = document.getElementById(heading);
	if (inputField) {
		var text = inputField.value;
		// 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;
		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>
PerseusSurvey.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>
PerseusSurvey.prototype.IsDate = function(heading) {
	// Get Month/Day/Year Values
	var monthElement = document.getElementById(heading + "_MM");
	var selectedIndex = monthElement.selectedIndex;
	var month = Number(monthElement.options[selectedIndex].value);
	var day = Number(document.getElementById(heading + "_DD").value);
	var year = Number(document.getElementById(heading + "_YYYY").value);
	// 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;
	 }
	if (year <= 0) 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>
PerseusSurvey.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 an list of field headings, returns their total as a number.
/// </summary>
/// <param>List of dbHeadings e.g. 'Q1_1', 'Q1_2', 'Q1_3'</param>
PerseusSurvey.prototype.NumericTotal = function() {		
	return this.calculateTotal(arguments);
}

/// <summary>
/// Given an 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>
PerseusSurvey.prototype.StringTotal = function() {
	var total = this.calculateTotal(arguments);	
	return this.ToRegionNumber(total);
}	

/// <summary>
/// Converts a number to a string with regional formatting.
/// </summary>
/// <param name="number">Number</param>
PerseusSurvey.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>
PerseusSurvey.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>
/// Hides rows (topics) in a table question based on a previous choose many's answers
/// And optionally sets odd/even row indicators.
/// </summary>
/// <param>
/// First arguement is value to test 1 for selected, 0 for not selected
/// Second arguement is true to display odd/even rows. false to not display odd/even rows.
/// Remaining arguements are the dependent value (Usually a placeholder e.g. %Q1_1%) and the row id.
/// e.g. 1, true, '1|Q2T1', '0|Q2T2', '0|Q2T3', '1|Q2T4', '0|Q2T5'
/// </param>
PerseusSurvey.prototype.DisplayDynamicRows = function() {	
	var viscount = 0;
	var value = arguments[0];
	var oddeven = arguments[1];
	for (var i = 2; i < arguments.length; i++) {		
		var pair = arguments[i].split("|");
		var row = document.getElementById(pair[1]);
		if (row) {
			if (pair[0] != value) {			
				row.style.display="none";
			} else if (oddeven) {
				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>
PerseusSurvey.prototype.DisplayDynamicColumns = function() {	
	var value = arguments[0];
	for (var i = 1; i < arguments.length; i++) {		
		var pair = arguments[i].split("|");
		var cells = document.getElementsByName(pair[1]);
		if (pair[0] != value) {
			for(j = 0; j < cells.length; j++){
				cells[j].style.display = "none";
			}
		}
	}
}

/// <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>
PerseusSurvey.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>
PerseusSurvey.prototype.RemoveListChoice = function(dbHeading, choiceValue) {

	var choiceList = document.getElementById(dbHeading);
	var optionCount = choiceList.options.length - 1;
	
	for (var i = optionCount; i > 0; i--) {
		if (choiceList.options[i].value == choiceValue) choiceList.options[i] = null;				
	}
}