function isUsingIE() {
	return (navigator.appName == "Microsoft Internet Explorer");
}

function BaseElement(elemId, onChangeFunction) {
	this.element = document.getElementById(elemId);
	if( ! (this.element) ) {
		return null;
	}
	this.element.onChangeFunction = onChangeFunction;
	
	this.element.changeListeners = [];
	
	this.element.addChangeListener = function(listener) {
		this.changeListeners[this.changeListeners.length] = listener;
	}
	
	this.element.fireChangeListeners = function() {
		for(var i = 0; i < this.changeListeners.length; i++) {
			this.changeListeners[i](this);
		}
	}

	this.element.validate = function() {
		return true;
	}
	
	this.element.reformatInput = function(optValue) {
		return optValue || this.value;
	}
	
	this.element.setReformattedInput = function(optValue) {
		if( optValue ) {
			this.value = this.reformatInput(optValue);
		} else {
			this.value = this.reformatInput();
		}
	}
	
	this.element.getValidationErrorText = function() {
		return "Validation Error";
	}

	
	this.element.confirm = function(messageText) {
		if( isUsingIE() ) {
			return confirm(messageText);
		} else {
			alert(messageText);
			return true;
		}
	}

	this.element.storeValue = function(optionalValue) {
		var v = this.reformatInput(optionalValue || this.value);
		if( v != null ) {
			this.initValue = optionalValue || this.value;
		}
	}
	
	this.element.reset = function() {
		this.value = this.initValue;
	}

	this.element.onfocus = function(evt) {
		evt = (evt) ? evt : ((window.event) ? event : null);
		if(evt) {
			var elem = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : null);
			if(elem) {
				elem.storeValue();
			}
		}
	}
	
	this.element.onchange = function(evt) {
		evt = (evt) ? evt : ((window.event) ? event : null);
		if(evt) {
			var elem = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : null);
			if(elem) {
				if( ! this.validate() ) {
					if( this.confirm(this.getValidationErrorText()) ) {
						if( evt.cancelBubble ) {
							evt.cancelBubble = true;
						}
						if( evt.returnValue ) {
							evt.returnValue  = false;
						}
						if( ! isUsingIE() ) {
							elem.focus();
						}
						return false;
					} else {
						elem.reset();
					}
				} else {
					this.setReformattedInput();
					if( this.onChangeFunction ) {
						this.onChangeFunction( this );
					}
					this.fireChangeListeners();
				}
				return true;
			}
		}
	}

	if( ! isUsingIE() ) {
		this.element.onblur = function(evt) {
			evt = (evt) ? evt : ((window.event) ? event : null);
			if(evt) {
				var elem = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : null);
				if(elem) {
					var v = this.input;
					if( this.reformatInput(v) == null ) {
						this.reset();
					}
				}
			}
		}
	}
}

function InputElement(elemId, onChangeFunction, allowZero) {
	this.InputElement_base = BaseElement;
	this.InputElement_base(elemId, onChangeFunction);

	if( ! (this.element) ) {
		return null;
	}
	
	if( allowZero ) {
		this.element.allowZero = allowZero;
	}

	this.element.getIntValue = function(optValue) {
		return (optValue) ? parseInt(optValue) : parseInt(this.value);
	}
	
	this.element.setIntValue = function(value) {
		var v = parseInt(value);
		this.value = isNaN(v) ? this.value : v;
		
		if( this.onstaychange ) {
			eval(this.onstaychange);
		}		
	}
	
	this.element.getValidationErrorText = function() {
		if( this.allowZero ) {
			return "Must enter a non-negative integer";
		} else {
			return "Must enter a positive integer";
		}
	}
	
	this.element.validate = function() {
		var formattedInput = this.reformatInput();
		var floorNumber = this.allowZero ? 0 : 1;
		return (! isNaN(formattedInput)) && (formattedInput >= floorNumber);
	}
	
	this.element.reformatInput = function(optValue) {
		var v = optValue || this.value;
		return parseInt(v);
	}
	
	if( isUsingIE() ) {
		this.element.onkeypress = function(evt) {
			evt = (evt) ? evt : ((window.event) ? event : null);
			if(evt) {
				var elem = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : null);
				if(elem) {
					var charCode = (evt.charCode) ? evt.charCode : ((evt.which) ? evt.which : evt.keyCode);
					
					if( (charCode >= 48 && charCode <= 57) ) {
					} else {
						evt.cancelBubble = true;
						evt.returnValue = false;
					}				
				}
			}
		}	
	}
}
InputElement.prototype = new BaseElement;

function DateElement(elemId, onChangeFunction) {
	this.DateElement_base = InputElement;
	this.DateElement_base(elemId, onChangeFunction);

	this.element.getDate = function(optValue) {
		var v = optValue || this.value;
		return this.__parseShortDate(v);
	}

	this.element.setDate = function(dt) {
		this.value = this.getDateString(dt) || "";
	}

	this.element.getDateString = function(optDate) {
		var dt = optDate || this.getDate();
		if( dt == null ) {
			return null;
		}
		return this.__getLeftZeroPadded(dt.getMonth()+1) + "/" 
					+ this.__getLeftZeroPadded(dt.getDate()) + "/" 
					+ this.__getLeftZeroPadded(dt.getYear() % 100);
	}

	this.element.setDateString = function(value) {
		this.setDate( getDate(value) );
	}
	
	this.element.getValidationErrorText = function() {
		return "Please enter date as MM/DD/YY";
	}

	this.element.validate = function() {
		var formattedInput = this.reformatInput();
		var valid = (formattedInput != null);
		return valid;
	}
	
	this.element.reformatInput = function(optInputValue) {
		var v = (optInputValue) ? this.getDate(optInputValue) : this.getDate();
		if( v == null ) {
			return null;
		}
		return this.getDateString(v);
	}
	
	this.element.daysBetween = function(otherDate) {
		var dt = this.getDate();
		if( dt == null || !( otherDate ) ) {
			return null;
		}
		return this.__signedDaysBetween(dt, otherDate);
	}
	
	this.element.__createRelativeDate = function(adate, nights) {
		if( adate == null ) {
			alert("__createRelativeDate param adate is null");
			return null;
		}
	
		var ndate = new Date();
		ndate.setDate(1);
		ndate.setYear(adate.getFullYear());
		
		ndate.setMonth(adate.getMonth());
		ndate.setDate(adate.getDate() + nights);
		return ndate;
	}

	this.element.createRelativeDate = function(nights) {
		var dt = this.getDate();
		if( dt == null ) {
			alert("dt == null");
			return;
		}
		return this.__createRelativeDate(dt, nights);
	}

	this.element.__signedDaysBetween = function(date1, date2) {
		var DSTAdjust = 0;
		var oneMinute = 60000;
		var oneDay = oneMinute*60*24;
		date1.setHours(0);
		date1.setMinutes(0);
		date1.setSeconds(0);
		date2.setHours(0);
		date2.setMinutes(0);
		date2.setSeconds(0);
		DSTAdjust =
			(date2.getTimezoneOffset() - date1.getTimezoneOffset())*oneMinute;
		var diff = date2.getTime() - date1.getTime() - DSTAdjust;
		return Math.ceil(diff/oneDay);
	}

	this.element.__parseShortDate = function(v) {
		var re = new RegExp("^ *(\\d{1,2})([/-])(\\d{1,2})\\2(\\d{2}|\\d{4}) *$","gi");
		var arr = re.exec(v);
		if( arr == null ) {
			return null;
		}
		var mo = RegExp.$1;
		var da = RegExp.$3;
		var yr = parseInt(RegExp.$4,10);
		if( yr < 100 ) {
			yr += 2000;
		}
		return new Date(yr, mo - 1, da);
	}
	
	this.element.__getLeftZeroPadded = function(nbr) {
		if( nbr < 10 ) {
			return "0" + nbr;
		}
		return nbr;
	}	

	if( isUsingIE() ) {
		this.element.onkeypress = function(evt) {
			evt = (evt) ? evt : ((window.event) ? event : null);
			if(evt) {
				var elem = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : null);
				if(elem) {
					var charCode = (evt.charCode) ? evt.charCode : ((evt.which) ? evt.which : evt.keyCode);
					
					if( (charCode >= 48 && charCode <= 57) || (charCode == 47) || (charCode == 45) ) {
					} else {
						evt.cancelBubble = true;
						evt.returnValue = false;
					}				
				}
			}
		}
	}
}
DateElement.prototype = new InputElement;

function DateRange(startId, endId, nightsId, onStayChange) {
	this.noChange = '';
	
	this.setNoChange = function(nc) {			
		this.noChange = nc;		
	}
	
	this.onStartChange = function(elem) {
		if (elem.manager.noChange == 'true') {						
			return true;
		}
		
		var edate = elem.manager.ed.getDate();
		var nights = elem.daysBetween(edate);
		if( elem.manager.__isValidNights(nights) ) {
			elem.manager.nt.setIntValue(nights);
		} else {
			var nts = elem.manager.nt.getIntValue();
			var bdate = elem.createRelativeDate(nts);
			elem.manager.ed.setDate(bdate);
		}
	}
	
	this.onEndChange = function(elem) {
		if (elem.manager.noChange == 'true') {						
			return true;
		}
		
		var bdate = elem.manager.bd.getDate();
		var nights = elem.daysBetween(bdate) * -1;
		if( elem.manager.__isValidNights(nights) ) {
			elem.manager.nt.setIntValue(nights);
		} else {
			var nts = elem.manager.nt.getIntValue();
			var edate = elem.createRelativeDate(nts * -1);
			elem.manager.bd.setDate(edate);
		}
	}
	
	this.onNightsChange = function(elem) {
		var nts = elem.getIntValue();
		elem.manager.setReturnDateByNights(nts);
	}
	
	this.setReturnDateByNights = function(value) {
		var edate = dateRange.bd.createRelativeDate(value);
		dateRange.ed.setDate(edate);
	}
	
	this.__isValidNights = function(nights) {
		return (nights > 0) && (nights < 100);
	}

	this.startObj  = new DateElement(startId, this.onStartChange);
	this.endObj    = new DateElement(endId, this.onEndChange);
	this.nightsObj = new InputElement(nightsId, this.onNightsChange);
	
	this.bd = this.startObj.element;
	this.bd.manager = this;
	
	this.ed = this.endObj.element;
	this.ed.manager = this;
	
	this.nt = this.nightsObj.element;
	this.nt.manager = this;

	if( onStayChange ) {	
		this.nt.onstaychange = onStayChange;
	}
}
