UtilForm = new function () {
	this.countChar = function (str,chr) {
		var _len = str.length;
		var _result = 0;
		for (var _i = 0; _i < _len; _i++) {
			if (str.charAt(_i) == chr) {
				_result++;
			}
		}
		return _result;
	}
	
	this.countNonASCII = function (str) {
		var _len = str.length;
		var _result = 0;
		for (var _i = 0; _i < _len; _i++) {
			if (str.charCodeAt(_i) > 127) {
				_result++;
			}
		}
		return _result;
	}
	
	this.countWhiteSpaces = function (str) {
		var _len = str.length;
		var _result = 0;
		for (var _i = 0; _i < _len; _i++) {
			if (str.charCodeAt(_i) < 33) {
				_result++;
			}
		}
		return _result;
	}
	
	this.countNonDigits = function (str) {
		var _len = str.length;
		var _result = 0;
		for(var _i = 0; _i < _len; _i++) {
			if ((str.charCodeAt(_i) < 48) || (str.charCodeAt(_i) > 57)) {
				_result++;
			}
		}
		return _result;
	}
	
	this.isInteger = function (n) {
		return (!isNaN(n) && (Math.ceil(n) == Math.floor(n)));
	}
	
	this.isNatural = function (n) {
		return this.isInteger(n) && (n >= 0);
	}
	
	this.isPositiveNumber = function (n) {
		return (!isNaN(n) && (n > 0));
	}
	
	this.isPositiveInteger = function (n) {
		return this.isInteger(n) && (n > 0);
	}
	
	this.trimLeft = function (str) {
		var _len = str.length;
		var _i;
		var _result = new String(str);
		if (_len < 1) {
			return _result;
		}
		for (_i = 0; _i < _len; _i++) {
			if ((str.charCodeAt(_i) > 32) || (str.charCodeAt(_i) < -1)) {
				break;
			}
		}
		if (_i < 1) {
			return _result;
		}
		_result = _result.substring(_i,_len);
		return _result;
	}
	
	this.trimRight = function (str) {
		var _len = str.length;
		var _i;
		var _result = new String(str);
		if (_len < 1) {
			return _result;
		}
		for (_i = 0; _i < _len; _i++) {
			if ((str.charCodeAt(_len - _i - 1) > 32) || (str.charCodeAt(_i) < -1)) {
				break;
			}
		}
		if (_i < 1) {
			return _result;
		}
		_result = _result.substring(0,_len - _i);
		return _result;
	}
	
	this.trim = function (str) {
		var _result = this.trimLeft(str);
		if (_result.length > 0) {
			_result = this.trimRight(_result);
		}
		return _result;
	}
	
	this.isBlank = function (str) {
		return (str == null) || (this.trimLeft(str).length == 0);
	}
	
	this.isEmail = function (str) {
		var _str = new String(this.trim(str));
		if (this.countWhiteSpaces(_str) > 0) {
			return false;
		}
		if (this.countNonASCII(_str) > 0) {
			return false;
		}
		if ((_str.length < 6) || (this.countChar(_str,"@") != 1)) {
			return false;
		}
		var leftPart = _str.substring(0,_str.indexOf("@"));
		var rightPart = _str.substr(_str.indexOf("@") + 1);
		return ((leftPart.length > 0) && (rightPart.length > 3)
			&& (this.countChar(rightPart,".") > 0)
			&& (rightPart.charAt(rightPart.length - 1) != ".")
			&& (rightPart.charAt(0) != "."));
	}
	
	this.isPhoneNumber = function (str) {
		var _len = str.length;
		var _result = true;
		var _code;
		if (_len < 1) {
			return false;
		}
		for(var _i = 0; _i < _len ; _i++) {
			_code = str.charCodeAt(_i);
			if(
				(_code == 32) // space
				|| ((_code >= 48) && (_code <= 57)) // digits
				|| (_code == 43) // plus sign
				|| (_code == 45) // minus sign
				) {
				continue;
			}
			_result = false;
			break;
		}
		return _result;
	}
	
	this.isUrl = function (str) {
		var _str = new String(this.trim(str));
		if (this.countWhiteSpaces(_str) > 0) {
			return false;
		}
		if (this.countChar(_str,".") < 1) {
			return false;
		}
		return true;
	}
	
	this.fillLeft = function (s,c,l) {
		if (s.length >= l) {
			return new String(s);
		}
		var result = "";
		for (var i = 0; i < (l - s.length); i++) {
			result += c;
		}
		return result + s;
	}
	
	this.fillRight = function (s,c,l) {
		if (s.length >= l) {
			return new String(s);
		}
		var result = "";
		for (var i = 0; i < (l - s.length); i++) {
			result += c;
		}
		return s + result;
	}
	
	/*
	 * Function call onFocus="textFocus(this);" onBlur="textBlur(this);"
	 */
	this.textFocus = function (el, val) {
		if (val) {
			el.defaultValue = val;
			if (el.value == val) {
				el.value = "";
			}
		} else if (el.value != "") {
			el.defaultValue = el.value;
			el.value = "";
		}
	}
	
	this.textBlur = function (el, val) {
		if (val) {
			el.defaultValue = val;
		}
		if (el.value == "") {
			el.value = el.defaultValue;
		}
	}
		
	this.findXCoord = function (evt) {
		if (evt.x) {
			return evt.x;
		}
		if (evt.pageX) {
			return evt.pageX;
		}
	}
	
	this.findYCoord = function (evt) {
		if (evt.y) {
			return evt.y;
		}
		if (evt.pageY) {
			return evt.pageY;
		}
		return null;
	}
		
	this.getElementInAllB = function (str) {
		if (document.layers) {
			return document.layers[str];
		} else if (document.getElementById) {
			return document.getElementById(str);
		} else if (document.all) {
			return document.all[str];
		}
		return null;
	}
	
	this.findFormElement = function (theForm, name) {
		for (var i = 0; i < theForm.elements.length; i++) {
			var el = theForm.elements[i];
			if ((el.name == name) || (el.id == name)) {
				return el;
			}
		}
		return null;
	}
	
	this.buildUrl = function (link) {
		if (link.charAt(0) == '/') {
			return link;
		}
		var p = BASE_URL.indexOf(";jsession");
		if (p == -1) {
			return BASE_URL + link;
		}
		return BASE_URL.substr(0, p) + link + BASE_URL.substr(p, BASE_URL.length);
	}
}

DateUtil = new function () {
	this.MSEC_PER_MINUTE = 1000 * 60;
	this.MSEC_PER_HOUR = this.MSEC_PER_MINUTE * 60;
	this.MSEC_PER_DAY = this.MSEC_PER_HOUR * 24;
	// statndard minimal OUT date for calendars
	this.STANDARD_MIN_OUT_DATE = new Date();
	// statndard minimal stay for calendars (in days)
	this.STANDARD_MIN_STATE = 0;
	
	var utcHours = this.STANDARD_MIN_OUT_DATE.getHours()
			+ this.STANDARD_MIN_OUT_DATE.getTimezoneOffset() / 60;
	if (utcHours >= 15) {
		this.STANDARD_MIN_OUT_DATE.setTime(this.STANDARD_MIN_OUT_DATE.getTime()
			+ this.MSEC_PER_HOUR * (48 - utcHours));
	} else {
		this.STANDARD_MIN_OUT_DATE.setTime(this.STANDARD_MIN_OUT_DATE.getTime()
			+ this.MSEC_PER_HOUR * 12);
	}
	
	this.checkInOutDates = function (outDateStr, inDateStr, fmt, isOneWay) {
		isOneWay = (isOneWay == true);
		var msecPerDay = 24 * 60 * 60 * 1000;
		var currDT = new Date();
		currDT.setHours(0);
		currDT.setMinutes(0);
		currDT.setSeconds(0);
		currDT.setMilliseconds(0);
		var outDT = Date.parseDate(outDateStr, fmt);
		if (outDT == null) {
			return Resources.ERR_INVALID_OUT_DATE;
		}
		if ((outDT.getTime() - currDT.getTime()) < msecPerDay) {
			return Resources.ERR_OUT_DATE_TOO_SMALL;
		}
		if (isOneWay) {
			return null;
		}
		var inDT = Date.parseDate(inDateStr, fmt);
		if (inDT == null) {
			return Resources.ERR_INVALID_IN_DATE;
		}
		if ((inDT.getTime() - outDT.getTime()) < msecPerDay) {
			return Resources.ERR_INVALID_OUT_IN_INTERVAL;
		}
		if ((outDT.getTime() - currDT.getTime()) >= 331 * msecPerDay) {
			return Resources.ERR_OUT_DATE_TOO_BIG;
		}
		if ((inDT.getTime() - currDT.getTime()) >= 331 * msecPerDay) {
			return Resources.ERR_IN_DATE_TOO_BIG;
		}
		return null;
	};

	/*
	 * Compares two dates and returns: -1 if date1 earlier date2, 0 if date1 equals date2 and 1 if date1 later date2.
	 * date1 and date2 are objects of type Date
	 */
	this.compareDates = function (date1,date2) {
		var dateInt1 = date1.getTime();
		var dateInt2 = date2.getTime();
		if (dateInt1 == dateInt2) {
			return 0;
		} else if (dateInt1 < dateInt2) {
			return -1;
		} else {
			return 1;
		}
	};
	
	this.isLeapYear = function (year) {
		if (year % 4 != 0) {
			return false;
		} else if (year % 400 == 0) {
			return true;
		} else if (year % 100 != 0) {
			return true;
		} else {
			return false;
		}
	};
	
	this.getDaysInMonth = function (month,year) {
		if ((month < 1) || (month > 12)) {
			return 0;
		}
		var _daysInMonth = new Array(31,28,31,30,31,30,31,31,30,31,30,31);
		var _result = _daysInMonth[month - 1];
		if ((month == 2) && this.isLeapYear(year)) {
			_result++;
		}
		return _result;
	};
	
	this.isCorrectDate = function (year,month,day) {
		if (!UtilForm.isNatural(year) || !UtilForm.isNatural(month)
				|| !UtilForm.isNatural(day)) {
			return false;
		}
		if ((year < 1) || (month < 1) || (month > 12) || (day < 1)) {
			return false;
		}
		var _daysInMonth = this.getDaysInMonth(month,year);
		if (day > _daysInMonth) {
			return false;
		}
		return true;
	};
	
	/**
	 *  Tries to identify the date represented in a string.  If successful it also
	 *  calls this.setDate which moves the calendar to the given date.
	 */
	this.isValidDateString = function (str, fmt) {
		return str == Date.parseDate(str, fmt).print(fmt);
	};
	
	this.isOutDateEnabled = function (date) {
		var diff = date.getTime() - this.STANDARD_MIN_OUT_DATE.getTime()
			+ this.MSEC_PER_DAY;
		return (diff >= 0) && (diff <= 331 * this.MSEC_PER_DAY);
	}
	
	this.isInDateEnabled = function (outDate, date) {
		if (outDate == null) {
			outDate = this.STANDARD_MIN_OUT_DATE;
		}
		var diff = date.getTime() - outDate.getTime()
			- this.STANDARD_MIN_STATE * this.MSEC_PER_DAY;
		return (diff >= 0) && (diff <= 331 * this.MSEC_PER_DAY);
	}
}

CalendarRestrictions = function (minDateStr, maxDateStr, fmt) {
	this.minDate = Date.parseDate(minDateStr, fmt);
	this.maxDate = Date.parseDate(maxDateStr, fmt);
	this.disabledDates = new Array();
	
	this.isDateEnabled = function (date) {
		var result = (date.getTime() >= this.minDate.getTime())
			&& (date.getTime() <= this.maxDate.getTime());
		if (!result) {
			return false;
		}
		for (var i = 0; i < this.disabledDates.length; i++) {
			if (date.getTime() == this.disabledDates[i].getTime()) {
				return false;
			}
		}
		return true;
	};
	
	this.addDisabledDates = function (datesStr, fmt) {
		var p = this.disabledDates.length;
		for (var i = 0; i < datesStr.length; i++) {
			this.disabledDates[p + i] =
				Date.parseDate(datesStr[i], fmt);
		}
	}
}

GeoNavigator = new function () {
	this.dataElement = null;
	
	this.show = function (theForm, pointType, event) {
		//this.dataElement = theForm.elements[pointType];
		this.dataElement = UtilForm.findFormElement(theForm, pointType);
		this.showWnd(event);
	}
	
	this.setPoint = function (value) {
		if (this.dataElement != null) {
			this.dataElement.value = value;
		}
	}
	
	this.showWnd = function (event) {
		var geoNav = document.getElementById("geoNavDiv");
		if (event.pageX != null) {
			geoNav.style.left = event.pageX + "px";
			geoNav.style.top = event.pageY + "px";
		} else {
			geoNav.style.left = event.x + document.body.scrollLeft + "px";
			geoNav.style.top = event.y + document.body.scrollTop + "px";
		}
		geoNav.style.display = "block";
		document.getElementById("geoNavFrame").src =
			"geoNavigator.do?pattern=" + encodeURIComponent(this.dataElement.value);
	}
	
	this.closeWindow = function (windowRef) {
		if ((windowRef.opener != null) && (windowRef.opener != self)) {
			windowRef.opener.GeoNavigator.hideWnd(windowRef);
		} else {
			parent.GeoNavigator.hideWnd();
		}
	}
	
	this.hideWnd = function (windowRef) {
		if (windowRef != null) {
			windowRef.close();
		} else  {
			document.getElementById("geoNavDiv").style.display = "none";
			document.getElementById("geoNavFrame").src = "about:blank";
		}
	}
}



DomUtil = new function () {
	this.findParent = function (node, name, id) {
		if (node == null) {
			return null;
		}
		if (node.nodeName == name) {
			if (id == null) {
				return node;
			} else if (node.getAttribute("id") == id) {
				return node;
			}
		}
		return this.findParent(node.parentNode, name, id);
	}
	
	this.findChild = function (node, name, id) {
		if (node == null) {
			return null;
		}
		var children = node.childNodes;
		for (var i = 0; i < children.length; i++) {
			var result = children.item(i);
			if (result.nodeName == name) {
				//alert("node=" + result.nodeName + ", id=" + result.getAttribute("id"));
				if (id == null) {
					return result;
				} else if (result.getAttribute("id") == id) {
					return result;
				}
			}
			result = this.findChild(result, name, id);
			if (result != null) {
				return result;
			}
		}
		return null;
	}
	
	this.visitNodes = function (parent, nodeName, callback) {
		if (parent == null) {
			return;
		}
		var children = parent.childNodes;
		var idx = -1;
		for (var i = 0; i < children.length; i++) {
			var child = children.item(i);
			if (child.nodeName == nodeName) {
				idx++;
				callback(child, idx);
			}
			this.visitNodes(child, nodeName, callback);
		}
	}
}

SearchUtil = new function () {
	this.validateRouteSegment = function (theForm, idx) {
		var startPoint = UtilForm.findFormElement(theForm, "routeSegment[" + idx + "].startPoint");
		var endPoint = UtilForm.findFormElement(theForm, "routeSegment[" + idx + "].endPoint");
		var dateStr = UtilForm.findFormElement(theForm, "routeSegment[" + idx + "].dateStr");
		if ((startPoint == null) || (endPoint == null) || (dateStr == null)) {
			return null;
		}
		if (UtilForm.isBlank(startPoint.value)) {
			alert(Resources.ERR_INVALID_START_POINT);
			startPoint.focus();
			return false;
		}
		if (UtilForm.isBlank(endPoint.value)) {
			alert(Resources.ERR_INVALID_END_POINT);
			endPoint.focus();
			return false;
		}
		if (startPoint.value == endPoint.value) {
			alert(Resources.ERR_INVALID_START_END_POINTS);
			endPoint.focus();
			return false;
		}
		if (!DateUtil.isValidDateString(dateStr.value, Resources.DATE_FORMAT)) {
			alert(Resources.ERR_INVALID_OUT_DATE);
			dateStr.focus();
			return false;
		}
		return true;
	}
	
	this.doSearch = function (theForm) {
		var idx = 0;
		while (true) {
			var validationResult = this.validateRouteSegment(theForm, idx);
			if (validationResult == null) {
				break;
			}
			if (validationResult == false) {
				return false;
			}
			idx++;
		}
		if ((theForm.routeType != null) && ((theForm.routeType.value == "1")
				|| ((theForm.routeType[0] != null)
				&& theForm.routeType[0].checked))) {
			if (!DateUtil.isValidDateString(theForm.returnDateStr.value,
					Resources.DATE_FORMAT)) {
				alert(Resources.ERR_INVALID_IN_DATE);
				theForm.returnDateStr.focus();
				return false;
			}
		}
		if ((theForm.searchMode != null) && ((theForm.searchMode.value == "2")
				|| ((theForm.searchMode[1] != null)
				&& theForm.searchMode[1].checked))
				&& (theForm.returnDateStr != null)) {
			var datesCheckResult = DateUtil.checkInOutDates(
				theForm["routeSegment[0].dateStr"].value,
				theForm.returnDateStr.value, Resources.DATE_FORMAT,
				!isRoundTrip(theForm));
			if (datesCheckResult != null) {
				alert(datesCheckResult);
				return false;
			}
		}
		return true;
		function isRoundTrip(theForm) {
			return (theForm.routeType != null) && ((theForm.routeType.value == 1)
				|| ((theForm.routeType[0] != null)
				&& theForm.routeType[0].checked));
		}
	}
	
	this.airVendorsChanged = function (theForm, forceSelection) {
		theForm.anyAirVendor[0].checked = !forceSelection;
		theForm.anyAirVendor[1].checked = forceSelection;
		if (forceSelection) {
			var selectedCount = 0;
			var opts = theForm.airVendors.options;
			var optLen = opts.length;
			for (var i = 0; i < optLen; i++) {
				if (opts[i].selected) {
					selectedCount++;
				}
				if (selectedCount > 3) {
					break;
				}
			}
			if (selectedCount == 0) {
				opts[0].selected = true;
			}
		}
	}
	
	this.routeSegmentDateChanged = function (field) {
		var theForm = field.form;
		if (!DateUtil.isValidDateString(field.value, Resources.DATE_FORMAT)) {
			return;
		}
		if (!theForm.returnDateStr) {
			return;
		}
		var outDate = Date.parseDate(field.value, Resources.DATE_FORMAT);
		if (!DateUtil.isValidDateString(theForm.returnDateStr.value,
				Resources.DATE_FORMAT)) {
			outDate.setDate(outDate.getDate() + 7);
			theForm.returnDateStr.value = outDate.print(Resources.DATE_FORMAT);
			return;
		}
		var inDate = Date.parseDate(theForm.returnDateStr.value,
			Resources.DATE_FORMAT);
		if (inDate.getTime() <= outDate.getTime()) {
			outDate.setDate(outDate.getDate() + 7);
			theForm.returnDateStr.value = outDate.print(Resources.DATE_FORMAT);
		}
	}
	
	this.updateSegmentBoxes = function () {
		var children =
			UtilForm.getElementInAllB("routeSegment_0").parentNode.childNodes;
		var idx = -1;
		for (var i = 0; i < children.length; i++) {
			var child = children.item(i);
			var id =
				(child.getAttribute != null) ? child.getAttribute("id") : null;
			if (("TABLE" == child.nodeName) && (id != null)
					&& (id.indexOf("routeSegment_") == 0)) {
				idx++;
				if (idx > 0) {
					this.updateSegmentBox(child, idx);
				}
			}
		}
	}

	this.updateSegmentBox = function (node, idx) {
		node.setAttribute("id", "routeSegment_" + idx);
		var removeRouteSegmentBoxNode =
			DomUtil.findChild(node, "TR", "removeRouteSegmentBox");
		DomUtil.findChild(removeRouteSegmentBoxNode, "A").setAttribute("href",
				"javascript:SearchUtil.deleteRouteSegment('routeSegment_"
				+ idx + "')");
		removeRouteSegmentBoxNode.style.display =
			document.all ? "block" : "table-row";
		var replaceIdxFunc = function(nd) {
			if (nd.name != null) {
				nd.name = nd.name.replace(
					/routeSegment\[\d+\]/g, "routeSegment[" + idx + "]");
			}
			if (nd.id != null) {
				nd.id = nd.id.replace(/\[\d+\]/g, "[" + idx + "]");
			}
		};
		DomUtil.visitNodes(node, "INPUT", replaceIdxFunc);
		DomUtil.visitNodes(node, "SELECT", replaceIdxFunc);
		DomUtil.visitNodes(node, "A", replaceIdxFunc);
		DomUtil.visitNodes(node, "A", function(nd) {
			if (nd.id == "geoNav[" + idx + "].startPoint") {
				nd.onclick = function(event) {
					GeoNavigator.show(DomUtil.findParent(nd, "FORM"),
						"routeSegment[" + idx + "].startPoint",
						document.all ? window.event : event);
				}
			} else if (nd.id == "geoNav[" + idx + "].endPoint") {
				nd.onclick = function(event) {
					GeoNavigator.show(DomUtil.findParent(nd, "FORM"),
						"routeSegment[" + idx + "].endPoint",
						document.all ? window.event : event);
				}
			}
		});
		DomUtil.visitNodes(node, "INPUT", function(nd) {
			if (nd.id != null) {
				nd.id = nd.id.replace(/dateStr_\d+/g, "dateStr_" + idx);
			}
		});
		DomUtil.visitNodes(node, "IMG", function(nd) {
			if (nd.id != null) {
				nd.id = nd.id.replace(/dateTrigger_\d+/g, "dateTrigger_" + idx);
			}
		});
		Calendar.setup({
			inputField  : "dateStr_" + idx,
			ifFormat    : Resources.DATE_FORMAT,
			button      : "dateTrigger_" + idx,
			firstDay    : 1,
			electric    : false,
			cache       : true,
			disableFunc : isRouteSegmentDateDisabled
		});
	}
	
	this.addRouteSegment = function () {
		var src = UtilForm.getElementInAllB("routeSegment_0");
		var dest = src.cloneNode(true);
		DomUtil.visitNodes(dest, "INPUT", function(nd) {
			nd.value = "";
		});
		src.parentNode.insertBefore(dest,
			UtilForm.getElementInAllB("returnDateBox"));
		this.updateSegmentBoxes();
	}
	
	this.deleteRouteSegment = function (segmentId) {
		var routeSegmentBoxNode = UtilForm.getElementInAllB(segmentId);
		if (routeSegmentBoxNode == null) {
			return;
		}
		routeSegmentBoxNode.parentNode.removeChild(routeSegmentBoxNode);
		this.updateSegmentBoxes();
	}
	
	this.deleteAllRouteSegments = function () {
		var idx = 1;
		var doUpdate = false;
		while (true) {
			var routeSegmentBoxNode =
				UtilForm.getElementInAllB("routeSegment_" + idx);
			if (routeSegmentBoxNode == null) {
				break;
			}
			routeSegmentBoxNode.parentNode.removeChild(routeSegmentBoxNode);
			doUpdate = true;
			idx++;
		};
		if (doUpdate) {
			this.updateSegmentBoxes();
		}
	}
	
	this.routeTypeChanged = function (theForm) {
		if (theForm.routeType[0].checked) {
			// RT
			theForm.searchMode[0].disabled = false;
			UtilForm.getElementInAllB("tariffModeBox").style.display =
				document.all ? "block" : "table-row";
			theForm.returnDateStr.disabled = false;
			theForm.returnTimeInterval.disabled = false;
			UtilForm.getElementInAllB("returnDateBox").style.display = "block";
			UtilForm.getElementInAllB("newRouteSegmentBox").style.display = "none";
			this.deleteAllRouteSegments();
		} else if (theForm.routeType[1].checked) {
			// OW simple
			theForm.searchMode[0].disabled = false;
			UtilForm.getElementInAllB("tariffModeBox").style.display =
				document.all ? "block" : "table-row";
			theForm.returnDateStr.disabled = true;
			theForm.returnTimeInterval.disabled = true;
			UtilForm.getElementInAllB("returnDateBox").style.display = "none";
			UtilForm.getElementInAllB("newRouteSegmentBox").style.display = "none";
			this.deleteAllRouteSegments();
		} else {
			// OW complex
			if (theForm.searchMode[0].checked) {
				theForm.searchMode[1].checked = true;
			}
			theForm.searchMode[0].disabled = true;
			UtilForm.getElementInAllB("tariffModeBox").style.display = "none";
			theForm.returnDateStr.disabled = true;
			theForm.returnTimeInterval.disabled = true;
			UtilForm.getElementInAllB("returnDateBox").style.display = "none";
			UtilForm.getElementInAllB("newRouteSegmentBox").style.display = "block";
		}
	}
}