Index: /trunk/htdocs/scripts/atoa-query.js
===================================================================
--- /trunk/htdocs/scripts/atoa-query.js	(revision 190)
+++ /trunk/htdocs/scripts/atoa-query.js	(revision 190)
@@ -0,0 +1,379 @@
+var showUsageText, hideUsageText;
+
+var standardProjCodeRE = /^([a-z]+)(\d+)$/i;
+
+var engineeringWarning = [
+	"The project code(s) you have entered may return engineering data that may not be of any scientific value.",
+	"",
+	"Do you wish to continue?"
+];
+
+var txtDateFrom, txtDateTo;
+
+window.onload = function() {
+
+	showUsageText = document.createTextNode("Expand Instructions");
+	hideUsageText = document.createTextNode("Hide Instructions");
+	
+	var usageToggleContainer = document.getElementById("divUsageToggle");
+	var usageToggle = document.createElement("a");
+	
+	usageToggle.href = "#";
+	usageToggle.id = "aUsage";
+	DOMUtils.addEventListener(usageToggle, "click", usageToggleHandler);
+	usageToggle.appendChild(showUsageText);
+
+	var calButtonText = document.createTextNode("Calendar");	
+	
+	var fromCalendarButton = document.createElement("button");
+	try { fromCalendarButton.type = "button"; } catch (e) { }
+	fromCalendarButton.id = "btnDateFromCalendar";
+	fromCalendarButton.appendChild(calButtonText.cloneNode(true));
+	
+	var toCalendarButton = document.createElement("button");
+	try { toCalendarButton.type = "button"; } catch (e) { }
+	toCalendarButton.id = "btnDateToCalendar";
+	toCalendarButton.appendChild(calButtonText.cloneNode(true));
+	
+	document.getElementById("divDateFrom").appendChild(fromCalendarButton);
+	document.getElementById("divDateTo").appendChild(toCalendarButton);
+	
+    txtDateFrom = document.createElement("input");
+    txtDateTo = document.createElement("input");
+	
+	var calFrom = Calendar.setup(
+	{
+	  inputField: txtDateFrom,
+	  onUpdate  : dateFromUpdate,
+	  ifFormat    : "%d-%b-%Y",    // the date format
+	  button      : "btnDateFromCalendar",       // ID of the button
+	  range       : getCalendarYearRange("selYearFrom")
+	});
+	
+	var calTo = Calendar.setup(
+	{
+	  inputField: txtDateTo,
+	  onUpdate  : dateToUpdate,
+	  ifFormat    : "%d-%b-%Y",    // the date format
+	  button      : "btnDateToCalendar",       // ID of the button
+	  range       : getCalendarYearRange("selYearTo")
+	});
+	
+	DOMUtils.addEventListener(document.getElementById("selDayFrom"), "change", dateFromChangeHandler);
+	DOMUtils.addEventListener(document.getElementById("selMonthFrom"), "change", dateFromChangeHandler);
+	DOMUtils.addEventListener(document.getElementById("selYearFrom"), "change", dateFromChangeHandler);
+	
+	DOMUtils.addEventListener(document.getElementById("selDayTo"), "change", dateToChangeHandler);
+	DOMUtils.addEventListener(document.getElementById("selMonthTo"), "change", dateToChangeHandler);
+	DOMUtils.addEventListener(document.getElementById("selYearTo"), "change", dateToChangeHandler);
+	
+	var frm = document.getElementById("frmSearch");
+	var val = new Validator(frm);
+	
+	/*
+	val.addFieldValidator(
+		document.getElementById("txtProjectCode"), 
+		new MandatoryValidator()
+	);
+	*/
+	
+	val.setBeforeSubmitHandler(beforeSubmit);
+	
+	var integerFields = ["txtRAHour", "txtRAMinute", "txtDecDegree", "txtDecMinute"];
+	
+	for (var field in integerFields) {
+		val.addFieldValidator(
+			document.getElementById(integerFields[field]),
+			new IntegerValidator()
+		);
+	}
+	
+	var realFields = ["txtRASecond", "txtDecSecond"];
+	
+	for (var field in realFields) {
+		val.addFieldValidator(
+			document.getElementById(realFields[field]),
+			new RealValidator()
+		);
+	}
+	
+	/*
+	var dateFields = ["txtDateFrom", "txtDateTo"];
+	for (var field in dateFields) {
+		val.addFieldValidator(
+			document.getElementById(dateFields[field]),
+			new DateValidator()
+		);
+	}
+	*/
+	
+	usageToggleContainer.appendChild(usageToggle);
+	
+}
+
+var dateFromChangeHandler = {
+	handleEvent: function(ev) {
+		updateCalendarDate(txtDateFrom, "selDayFrom", "selMonthFrom", "selYearFrom");
+	}
+}
+
+var dateToChangeHandler = {
+	handleEvent: function(ev) {
+		updateCalendarDate(txtDateTo, "selDayTo", "selMonthTo", "selYearTo");
+	}
+}
+
+function updateCalendarDate(calInput, dayControl, monthControl, yearControl) {
+	
+	dayControl = DOMUtils.resolveElement(dayControl);
+	monthControl = DOMUtils.resolveElement(monthControl);
+	yearControl = DOMUtils.resolveElement(yearControl);
+	
+	var date = new Date();
+	
+	date.setDate(1);
+	
+	if (yearControl.value != "") {
+		date.setFullYear(yearControl.value);
+	}
+	
+	if (monthControl.value != "") {
+		date.setMonth(monthControl.selectedIndex - 1);
+	}
+	
+	if (dayControl.value != "") {
+		date.setDate(dayControl.value);
+	}
+	
+	var months = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"];
+	
+	calInput.value = date.getDate() + "-" + months[date.getMonth()] + "-" + date.getFullYear();
+}
+
+function getCalendarYearRange(selectControl) {
+	if (typeof selectControl == "string")
+		selectControl = document.getElementById(selectControl);
+
+	var minYear = selectControl.options.item(1).value;
+	var maxYear = selectControl.options.item(selectControl.options.length - 1).value;
+
+	return [minYear, maxYear];
+}
+
+function dateToUpdate(cal) {
+	updateDateControls(cal.date, "selDayTo", "selMonthTo", "selYearTo");
+}
+
+function dateFromUpdate(cal) {
+	updateDateControls(cal.date, "selDayFrom", "selMonthFrom", "selYearFrom");
+}
+
+function updateDateControls(date, dayId, monthId, yearId) {
+	var dayHTML = document.getElementById(dayId);
+	var monthHTML = document.getElementById(monthId);
+	var yearHTML = document.getElementById(yearId);
+	
+	dayHTML.selectedIndex = date.getDate();
+	monthHTML.selectedIndex = date.getMonth() + 1;
+	yearHTML.value = date.getFullYear();
+}
+
+function getDateTimeFromControls(dayId, monthId, yearId, hourId, minuteId) {
+	var date;
+	
+	date = getDateFromControls(dayId, monthId, yearId);
+	
+	var hourHTML = document.getElementById(hourId);
+	var minuteHTML = document.getElementById(minuteId);
+	
+	if (minuteHTML.value != "" && hourHTML.value == "")
+		throw "Not a valid date";
+	
+	if (hourHTML.value != "" && date == null)
+		throw "Not a valid date";
+	
+	if (date == null)
+		return null;
+		
+	if (minuteHTML.value == "" && hourHTML.value == "")
+		return date;
+	
+	date.setMinutes(minuteHTML.value);
+	date.setHours(hourHTML.value);
+	
+	return date;
+}
+
+function getDateFromControls(dayId, monthId, yearId) {
+	var dayHTML = document.getElementById(dayId);
+	var monthHTML = document.getElementById(monthId);
+	var yearHTML = document.getElementById(yearId);
+	
+	if (dayHTML.value != "" && monthHTML.value == "")
+		throw "Not a valid date";
+	
+	if (monthHTML.value != "" && yearHTML.value == "")
+		throw "Not a valid date";
+		
+	if (dayHTML.value == "" && monthHTML.value == "" && yearHTML.value == "") 
+		return null;
+	
+	return new Date(
+		yearHTML.value,
+		monthHTML.selectedIndex - 1,
+		dayHTML.selectedIndex
+	);
+}
+
+function normaliseProjectCode(projCode) {
+	projCode = projCode.trim().toLowerCase();
+	if (!standardProjCodeRE.test(projCode)) {
+		return [projCode, Math.NaN];
+	}
+	
+	var matches = standardProjCodeRE.exec(projCode);
+	var normProj = [matches[1], Number(matches[2])];
+
+	return normProj;
+}
+
+function isEngineeringProject(projCode) {
+	normProj = normaliseProjectCode(projCode);
+	
+	if (isNaN(normProj[1])) {
+		return true;
+	}
+	
+	var astroPrefixes = ["c", "cx", "v", "s"];
+	var exceptions = [normaliseProjectCode("c000"), normaliseProjectCode("c999")];
+	
+	for (var astroIndex in astroPrefixes) {
+		if (astroPrefixes[astroIndex] == normProj[0]) {
+			for (var exceptionIndex in exceptions) {
+				if (exceptions[exceptionIndex].toString() == normProj.toString()) {
+					return true;
+				}
+			}
+		}
+	}
+	
+	return false;
+}
+
+function beforeSubmit(val) {
+
+	/*
+	var dateFromHTML = document.getElementById("txtDateFrom");
+	var dateToHTML = document.getElementById("txtDateTo");
+
+	var dateFrom = val.getField(dateFromHTML);
+	var dateTo = val.getField(dateToHTML);
+	
+	var dateFromObj = val.getValidator(dateFrom, DateValidator).validatedDate;
+	var dateToObj = val.getValidator(dateTo, DateValidator).validatedDate;
+	
+	*/
+	
+	var dateTo, dateFrom;
+	var hasMinimumCriteria = false;
+	var atLeastOneOf = ["txtProjectCode", "txtSourceName", "txtObsLastName", "txtRAHour", "txtRAMinute", "txtRASecond", "txtDecDegree", "txtDecMinute", "txtDecSecond"];
+	
+	try { 
+		dateFrom = getDateTimeFromControls("selDayFrom", "selMonthFrom", "selYearFrom", "selHourFrom", "selMinuteFrom");
+	} catch (e) {
+		alert("'Date From' is not a valid date");
+		return false;
+	}
+	
+	try {
+		dateTo = getDateTimeFromControls("selDayTo", "selMonthTo", "selYearTo", "selHourTo", "selMinuteTo");
+	} catch (e) {
+		alert("'Date To' is not a valid date");
+		return false;
+	}
+	
+	if (dateFrom != null && dateTo != null)
+		if (dateFrom.valueOf() > dateTo.valueOf()) {
+			alert("'Date From' must be before 'Date To'");
+			return false;
+		}
+	
+	hasMinimumCriteria = (dateFrom != null || dateTo != null);
+		
+	if (!hasMinimumCriteria)
+		for (var element in atLeastOneOf) {
+			if (document.getElementById(atLeastOneOf[element]).value.toString().trim() != "") {
+				hasMinimumCriteria = true;
+			}
+		}
+	
+	if (!hasMinimumCriteria) {
+		var message = [
+			"You must enter a value for at least one of:",
+			" * Project Code", 
+			" * Date From",
+			" * Date To",
+			" * Surname",
+			" * Source Name",
+			" * Source Position"
+		];
+		alert(message.join("\n"));
+		return false;
+	}
+	
+	var engineering = false;
+	var txtProjectCode = document.getElementById("txtProjectCode");
+	var projectCodes = txtProjectCode.value.split(/[ ;:,]/g);
+	
+	for (var x in projectCodes) {
+		projectCodes[x] = projectCodes[x].replace(/\s/g, "");
+		if (projectCodes[x] != "" && isEngineeringProject(projectCodes[x])) {
+			engineering = true; break;
+		}
+	}
+	
+	if (engineering)
+		if (!confirm(engineeringWarning.join("\n"))) {
+			txtProjectCode.select();
+			return false;
+		}
+	
+	return true;
+}
+
+var usageToggleHandler = {
+	handleEvent: function(ev) {
+		if (window.event) {
+			ev = window.event;
+			ev.currentTarget = ev.srcElement;
+		}
+		
+		var usageContainer = document.getElementById("divUsage");
+		var display, text;
+		
+		if (document.defaultView) {
+			var usageStyle = document.defaultView.getComputedStyle(usageContainer, null);
+			if (usageStyle == null) { // KHTML returns null for some reason if the element is not displayed
+				display = "none";
+			} else {
+        		display = usageStyle.getPropertyValue("display");
+        	}
+        } else {
+        	if (usageContainer.currentStyle) {
+        		display = usageContainer.currentStyle.display;
+        	} else {
+        		display = usageContainer.style.display;
+        	}
+        }
+        
+        if (display == "none") {
+        	usageContainer.style.display = "block";
+        	text = hideUsageText;
+        } else {
+        	usageContainer.style.display = "none";
+        	text = showUsageText;
+        }
+        
+        ev.currentTarget.replaceChild(text, ev.currentTarget.childNodes[0]);
+	}
+}
