function DateRange(lower, upper) {
	var self = this;
	this.date_default = 'mm/dd/yyyy';
	this.$lower = $(lower);
	this.$upper = $(upper);
	this.date_in = null;
	this.date_out = null;
	this.linked = new Array();
	this.date_min_selectable = new Date((new Date()).getTime() + 2 * 86400000);
	this.init = function() {
		var dmin = self.$lower.val();
		var dmax = self.$lower.val();
		var pattern = /^\d{1,2}(\/)\d{1,2}\1\d{4}$/;
		if (dmin.search(pattern) != -1) {
			self.date_in = new Date(dmin);
		}
		if (dmax.search(pattern) != -1) {
			self.date_out = new Date(dmax);
		}
	};
	this.set_date = function(bound, date) {
		switch (bound) {
		case 'lower':
			this.date_in = date;
			this.$lower.datepicker('disable');
			this.$lower.datepicker('setDate', date);
			this.$lower.datepicker('enable');
		case 'upper':
			this.date_out = date;
			this.$upper.datepicker('disable');
			this.$upper.datepicker('setDate', date);
			this.$upper.datepicker('enable');
		}
	};
	this.beforeShowDay = function(date) {
		var mm = date.getMonth();
		var dd = date.getDate();
		var yy = date.getFullYear();
		var time = date.getTime();
		if (self.date_in && self.$lower.val() != self.date_default) {
			if (yy == self.date_in.getFullYear() && mm == self.date_in.getMonth()
					&& dd == self.date_in.getDate()) {
				return [ false, 'ui-datepicker-selected-day-ts' ];
			}
		}
		if (self.date_out && self.$upper.val() != self.date_default) {
			if (yy == self.date_out.getFullYear() && mm == self.date_out.getMonth()
					&& dd == self.date_out.getDate()) {
				return [ false, 'ui-datepicker-selected-day-ts' ];
			}
		}
		if (self.$lower.val() != self.date_default
				&& self.$upper.val() != self.date_default) {
			if ((self.date_out && self.date_out.getTime() > time)
					&& (self.date_in && time > self.date_in.getTime()))
				return [ true, 'ui-datepicker-in-range-day-ts' ];
		}
		return (self.date_min_selectable.getTime() <= time ? [ true,
				'ui-datepicker-selectable-day-ts' ] : [ false,
				'ui-datepicker-unselectable-day-ts' ]);
	};
	this.link = function(other) {
		self.linked.push(other);
	};
	this.clear_link = function(other) {
		self.linked.clear();
	};
	this.validate = function(is_one_way) {
		var regex_date = /^(?=\d)(?:(?:(?:(?:(?:0?[13578]|1[02])(\/|-|\.)31)\1|(?:(?:0?[1,3-9]|1[0-2])(\/|-|\.)(?:29|30)\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})|(?:0?2(\/|-|\.)29\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))|(?:(?:0?[1-9])|(?:1[0-2]))(\/|-|\.)(?:0?[1-9]|1\d|2[0-8])\4(?:(?:1[6-9]|[2-9]\d)?\d{2}))($|\ (?=\d)))?(((0?[1-9]|1[012])(:[0-5]\d){0,2}(\ [AP]M))|([01]\d|2[0-3])(:[0-5]\d){1,2})?$/;
		var $a = this.$lower;
		var $b = this.$upper;
		var tx1 = $a.val();
		var tx2 = $b.val();
		if (is_one_way == true) {
			if (tx1.match(regex_date)) {
				var lo = $a.datepicker("getDate");
				var cd = new Date();
				cd.setHours(0);
				cd.setMinutes(0);
				cd.setSeconds(0);
				cd.setMilliseconds(0);
				var dt = lo.getTime() - cd.getTime();
				if ((2 * 24 * 3600 * 1000) <= dt) {
					return(true);
				}
			}
		} else {
			if (tx1.match(regex_date) && tx2.match(regex_date)) {
				var lo = $a.datepicker("getDate");
				var cd = new Date();
				cd.setHours(0);
				cd.setMinutes(0);
				cd.setSeconds(0);
				cd.setMilliseconds(0);
				var dt = lo.getTime() - cd.getTime();
				if ((2 * 24 * 3600 * 1000) <= dt) {
					return(true);
				}
			}
		}
		return(false);
	};
	this.init();
	$('#' + this.$lower.attr('id')).datepicker( {
		altField: '#' + this.$lower.attr('id') + '_alt',
		mandatory : true,
		showOn : 'both',
		buttonImageOnly : true,
		buttonImage : '/img/calendar.gif',
		changeFirstDay : false,
		gotoCurrent : true,
		yearRange : '-0:+1',
		showAnim : 'fadeIn',
		prevText : '<',
		nextText : '>',
		changeMonth : true,
		changeYear : true,
		numberOfMonths : 1,
		beforeShow : function() {
			var $t = $(this);
			if ($t.val() == self.date_default) {
				if ($t.attr('id') == self.$lower.attr('id')) {
					var d = self.date_out;
					if (d) {
						self.date_in = d;
						$t.datepicker('setDate', d);
					}
				} else if ($t.attr('id') == self.$upper.attr('id')) {
					var d = self.date_in;
					if (d) {
						self.date_out = d;
						$t.datepicker('setDate', d);
					}
				}
			}
			return {
				minDate : self.date_min_selectable,
				beforeShowDay : self.beforeShowDay
			};
		},
		onSelect : function(date) {
			if ($(this).attr('id') == self.$lower.attr('id')) {
				self.date_in = new Date(date);
				for (i in self.linked) {
					if (self.linked[i].date_in == null) {
					  self.linked[i].date_in = self.date_in;
					}
				}
				if (self.date_out < self.date_in) {
					self.date_out = null;
					self.$upper.val(self.date_default);
					for (i in self.linked) {
						self.linked[i].date_out = null;
						self.linked[i].$upper.val(self.date_default);
					}
				}
				for (i in self.linked) {
					if(self.linked[i].$lower.val() == 'mm/dd/yyyy') {
						self.linked[i].$lower.val(self.$lower.val());
						self.linked[i].$lower.datepicker('setDate', self.linked[i].$lower.datepicker('getDate'));
					}
				}
			} else if ($(this).attr('id') == self.$upper.attr('id')) {
				self.date_out = new Date(date);
				for (i in self.linked) {
					if (self.linked[i].date_out == null)
						self.linked[i].date_out = self.date_out;
				}
				if (self.date_out < self.date_in) {
					self.date_in = null;
					self.$lower.val(self.date_default);
					for (i in self.linked) {
						self.linked[i].date_in = null;
						self.linked[i].$lower.val(self.date_default);
					}
				}
				for (i in self.linked) {
					if(self.linked[i].$upper.val() == 'mm/dd/yyyy') {
						self.linked[i].$upper.val(self.$upper.val());
						self.linked[i].$upper.datepicker('setDate', self.linked[i].$upper.datepicker('getDate'));
					}
				}
			}
		}
	});
	
	var lower_field_id = this.$lower.attr('id'); 
	$('#' + lower_field_id + '_alt').click(function(e) {
		$('#' + lower_field_id).datepicker('show');
	});
	
	$('#' + this.$upper.attr('id')).datepicker( {
		altField: '#' + this.$upper.attr('id') + '_alt',
		mandatory : true,
		showOn : 'both',
		buttonImageOnly : true,
		buttonImage : '/img/calendar.gif',
		changeFirstDay : false,
		gotoCurrent : true,
		yearRange : '-0:+1',
		showAnim : 'fadeIn',
		prevText : '<',
		nextText : '>',
		changeMonth : true,
		changeYear : true,
		numberOfMonths : 1,
		beforeShow : function() {
			var $t = $(this);
			if ($t.val() == self.date_default) {
				if ($t.attr('id') == self.$lower.attr('id')) {
					var d = self.date_out;
					if (d) {
						self.date_in = d;
						$t.datepicker('setDate', d);
					}
				} else if ($t.attr('id') == self.$upper.attr('id')) {
					var d = self.date_in;
					if (d) {
						self.date_out = d;
						$t.datepicker('setDate', d);
					}
				}
			}
			return {
				minDate : self.date_min_selectable,
				beforeShowDay : self.beforeShowDay
			};
		},
		onSelect : function(date) {
			if ($(this).attr('id') == self.$lower.attr('id')) {
				self.date_in = new Date(date);
				for (i in self.linked) {
					if (self.linked[i].date_in == null) {
					  self.linked[i].date_in = self.date_in;
					}
				}
				if (self.date_out < self.date_in) {
					self.date_out = null;
					self.$upper.val(self.date_default);
					for (i in self.linked) {
						self.linked[i].date_out = null;
						self.linked[i].$upper.val(self.date_default);
					}
				}
				for (i in self.linked) {
					if(self.linked[i].$lower.val() == 'mm/dd/yyyy') {
						self.linked[i].$lower.val(self.$lower.val());
						self.linked[i].$lower.datepicker('setDate', self.linked[i].$lower.datepicker('getDate'));
					}
				}
			} else if ($(this).attr('id') == self.$upper.attr('id')) {
				self.date_out = new Date(date);
				for (i in self.linked) {
					if (self.linked[i].date_out == null)
						self.linked[i].date_out = self.date_out;
				}
				if (self.date_out < self.date_in) {
					self.date_in = null;
					self.$lower.val(self.date_default);
					for (i in self.linked) {
						self.linked[i].date_in = null;
						self.linked[i].$lower.val(self.date_default);
					}
				}
				for (i in self.linked) {
					if(self.linked[i].$upper.val() == 'mm/dd/yyyy') {
						self.linked[i].$upper.val(self.$upper.val());
						self.linked[i].$upper.datepicker('setDate', self.linked[i].$upper.datepicker('getDate'));
					}
				}
			}
		}
	});
	
	var upper_field_id = this.$upper.attr('id'); 
	$('#' + upper_field_id + '_alt').click(function(e) {
		$('#' + upper_field_id).datepicker('show');
	});

}