(function() {
	
	jQuery.rentalCalendar = function(a,b,c) {
		var template = '\
		<div id="rentalCalendar" style="display:none" class="rental-calendar">\
			<div class="rental-calendar-inner clearfix"> \
				<div class="rental-calendar-header">\
					<div class="rental-calendar-prev-month">&lt;</div>\
					<div class="rental-calendar-cur-month">Jan 2011</div>\
					<div class="rental-calendar-next-month">&gt;</div>\
				</div>\
				<ul class="rental-calendar-daynames">\
					<li>Mo</li>\
					<li>Tu</li>\
					<li>We</li>\
					<li>Th</li>\
					<li>Fr</li>\
					<li>Sa</li>\
					<li>Su</li>\
				</ul>\
				<ul class="rental-calendar-dates">\
				\
				</ul>\
			</div>\
			<div class="rental-calendar-close">Close</div>\
		</div>';
				
		var self;
		if ($("#rentalCalendar").length != 1) {
			self = $(template).appendTo("body");
		} else {
			self = $("#rentalCalendar");
		}
		
		//init.
		var onSelectHandler = self.data("onSelectHandler");
		if (!self.hasClass("init")) {
			self.addClass("init");
			self.find(".rental-calendar-prev-month").bind("click", prevMonth);
			self.find(".rental-calendar-next-month").bind("click", nextMonth);
			self.find(".rental-calendar-close").bind("click", close);
			setMonthNames(["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]);
		}
		
		function getCurrentRenderDate() {
			var d = self.data("currentRenderDate");
			if (d == undefined || d == null || d == "") {
				d = new Date();
				self.data("currentRenderDate", d);
			}
			return d;			
		}
		function setCurrentRenderDate(theDate) {
			self.data("currentRenderDate", theDate);
		}
				
		if (a != null && a.constructor == String) {
			switch(a) {
				case "openWithDate":
					openWithDate(b, c);
					break;
				case "openWithDateSelected":
					openWithDateSelected(b, c);
					break;
				case "open":
					open(b);
					break;
				case "prevMonth":
					prevMonth();
					break;
				case "nextMonth":
					nextMonth();
					break;
				case "setCheckIn":
					self.data("checkIn", b);
					break;
				case "setDayNames":
					setDayNames(b);
					break;
				case "setMonthNames":
					setMonthNames(b);
					break;
				case "setCloseTitle":
					self.find(".rental-calendar-close").text(b);
					break;
				case "getMonthName":
					return self.data("monthNames")[b];
				case "setDate":
					setDate(b);
					break;
				case "close":
					close();
					break;
				case "getDate":
					return getDate();
				case "onSelect":
					onSelectHandler = b;
					self.data("onSelectHandler", b);
					break;
				default:
					throw("Unknown action '"+a+"' for calendar.");
			}
		}
		
		function setDayNames(b) {
			var items = self.find(".rental-calendar-daynames li");
			for (var i=0; i<b.length; i++) {
				$(items[i]).text(b[i]);
			}
		}
		function setMonthNames(b) {
			self.data("monthNames", b);
		}
		function getMonthName(nr) {
			return self.data("monthNames")[nr];
		}
		
		function render(theDate) {
			setCurrentRenderDate(theDate);
			self.find(".rental-calendar-cur-month").text(getMonthName(theDate.getMonth()) + " " + theDate.getFullYear());
			// Draw the dates.
			var firstOfMonth = new Date(theDate.getFullYear(), theDate.getMonth(), 1);
			// What weekday?
			var day = firstOfMonth.getDay();
			// How many days in this month?
			var lastOfMonth = new Date(theDate.getFullYear(), theDate.getMonth()+1, 0);
			var daysInMonth = lastOfMonth.getDate();
			// Calculate padding.
			var padding = (day == 0) ? 6 : day-1;
			// draw.
			var dates = self.find(".rental-calendar-dates");
			dates.empty();
			for (var i=0; i<padding; i++) {
				dates.append('<li class="pad">-</li>');
			}
			var now = new Date();
			var today = (now.getFullYear() == theDate.getFullYear() && now.getMonth() == theDate.getMonth()) ? now.getDate() : -1;
			var selectedDate = getDate();
			var selected = (selectedDate.getFullYear() == theDate.getFullYear() && selectedDate.getMonth() == theDate.getMonth()) ? selectedDate.getDate() : -1;
			for (var j=1; j<=daysInMonth; j++) {
				var dateStr = theDate.getFullYear()+"/"+(theDate.getMonth()+1)+"/"+j;
				if (j == today) {
					if (j == selected) {
						dates.append('<li class="today selected" title="Today" date="'+dateStr+'">'+j+"</li>");						
					} else {
						dates.append('<li class="today" title="Today" date="'+dateStr+'">'+j+"</li>");						
					}
				} else if (j == selected) {
					dates.append('<li class="selected" date="'+dateStr+'">'+j+"</li>");
				} else {
					dates.append('<li date="'+dateStr+'">'+j+"</li>");
				}
			}
			self.find(".rental-calendar-dates li").bind("click", handleDateClick);
		}
				
		function getDate() {
			var d = self.data("selectedDate");
			if (d == null || d == undefined || d == "") {
				d = new Date();
				self.attr("selectedDate", d);
			}
			return d;
		}
		function setDate(theDate) {
			self.data("selectedDate", theDate);
			render(theDate);
			self.show();
			self.trigger("onSelect", [theDate, self.data("checkIn")]);			
		}
		
		function openWithDateSelected(theDate, showBelowObj) {
			setDate(theDate);
			if (showBelowObj != null) {
				position(showBelowObj);				
			}
		}
		
		function close() {
			self.hide();
		}

		function position(showBelowObj) {
			var theShowBelowObj = $(showBelowObj);
			var offset = theShowBelowObj.offset();
			var x = offset.left;
			var y = offset.top;
		
			x += theShowBelowObj.width()/2;
			y += theShowBelowObj.height();
		
			x -= self.width()/2;
		
			self.css("left", x);
			self.css("top", y);
		}
		
		function openWithDate(theDate, showBelowObj) {
			if (theDate == null || theDate == undefined || theDate == "") {
				theDate = new Date();
			}
			render(theDate);
			if (showBelowObj != null) {
				position(showBelowObj);
			}
			self.show();
		}
		function prevMonth() {
			var d = getCurrentRenderDate();
			render(new Date(d.getFullYear(), d.getMonth()-1, 1));
		}
		function nextMonth() {
			var d = getCurrentRenderDate();
			render(new Date(d.getFullYear(), d.getMonth()+1, 1))
		}
		
		function handleDateClick(e) {
			var d = $(e.target).attr("date");
			if (d == null || d == undefined || d == "") return;
			setDate(new Date(d));
			self.hide();
		}
		
		return self;
	}
	
})();
