if(typeof Prototype=='undefined')alert("CalendarDateSelect Error: Prototype could not be found. Please make sure that your application's layout includes prototype.js before it includes calendar_date_select.js.");
if(Prototype.Version<"1.6")alert("Prototype 1.6.0 is required.");

Element.addMethods({
  purgeChildren: function(element) { $A(element.childNodes).each(function(e){$(e).remove();}); },
  build: function(element, type, options, style) {
    var newElement = Element.build(type, options, style);
    element.appendChild(newElement);
    return newElement;
  }
});

Element.build = function(type, options, style){
	var e=$(document.createElement(type));
  	$H(options).each(function(pair) { eval("e." + pair.key + " = pair.value" ); });
  	if (style) 
    	$H(style).each(function(pair) { eval("e.style." + pair.key + " = pair.value" ); });
  	return e;
};
nil = null;

Date.one_day = 24*60*60*1000;
Date.weekdays = $w("Sun Mon Tue Wed Thu Fri Sat");
Date.first_day_of_week = 0;
Date.months = $w("January February March April May June July August September October November December" );
Date.padded2 = function(hour) { var padded2 = parseInt(hour, 10); if (hour < 10) padded2 = "0" + padded2; return padded2; }
Date.prototype.getPaddedMinutes = function() { return Date.padded2(this.getMinutes()); }
Date.prototype.getAMPMHour = function() { var hour = this.getHours(); return (hour == 0) ? 12 : (hour > 12 ? hour - 12 : hour ) }
Date.prototype.getAMPM = function() { return (this.getHours() < 12) ? "AM" : "PM"; }
Date.prototype.stripTime = function() { return new Date(this.getFullYear(), this.getMonth(), this.getDate());};
Date.prototype.daysDistance = function(compare_date) { return Math.round((compare_date - this) / Date.one_day); };
Date.prototype.toFormattedString = function(include_time){
  var hour, str;
  str = Date.months[this.getMonth()] + " " + this.getDate() + ", " + this.getFullYear();
  
  if (include_time) { hour = this.getHours(); str += " " + this.getAMPMHour() + ":" + this.getPaddedMinutes() + " " + this.getAMPM() }
  return str;
}
Date.parseFormattedString = function(string) { return new Date(string);}
Math.floor_to_interval = function(n, i) { return Math.floor(n/i) * i;}
window.f_height = function() { return( [window.innerHeight ? window.innerHeight : null, document.documentElement ? document.documentElement.clientHeight : null, document.body ? document.body.clientHeight : null].select(function(x){return x>0}).first()||0); }
window.f_scrollTop = function() { return ([window.pageYOffset ? window.pageYOffset : null, document.documentElement ? document.documentElement.scrollTop : null, document.body ? document.body.scrollTop : null].select(function(x){return x>0}).first()||0 ); }

_translations={"OK":"OK","Now":"Now","Today":"Today"}

SelectBox=Class.create({
  	initialize:function(parent_element, values,html_options,style_options){
    	this.element = $(parent_element).build("select", html_options, style_options);
    	this.populate(values);
  	},
  	populate:function(values){
    	this.element.purgeChildren();
    	var that = this; 
		$A(values).each(function(pair){if (typeof(pair)!="object") {pair = [pair, pair]}; that.element.build("option", { value: pair[1], innerHTML: pair[0]}) });
  	},
  	setValue:function(value){
    	var e = this.element;
    	var matched = false;
    	$R(0, e.options.length - 1 ).each(function(i) { if(e.options[i].value==value.toString()) {e.selectedIndex = i; matched = true;}; } );
    	return matched;
  	},
  	getValue:function(){return $F(this.element)}
});

XDCalendar=Class.create({
  	initialize:function(target_element,options){
    	this.target_element = $(target_element); // Make sure it's an element, not a string...
    	if (!this.target_element) { alert("Target element " + target_element + " not found!"); return false;}
    	if (this.target_element.tagName != "INPUT") this.target_element = this.target_element.down("INPUT")
    
    	this.target_element.calendar_date_select = this;
    	this.last_click_at = 0;
		var now=new Date();
    	// Initialize the date control...
    	this.options=$H({
			embedded:false,
		  	popup:nil,
		  	time:false,
		  	buttons:true,
			ok:false,
			arrival:false,
			departure:false,
			above:false,
		  	year_range:[now.getFullYear(),now.getFullYear()+4],
		  	calendar_div:nil,
		  	close_on_click:nil,
		  	minute_interval:5,
		  	popup_by:this.target_element,
		  	month_year:"dropdowns",
		  	onchange:this.target_element.onchange,
		  	valid_date_check:nil
    	}).merge(options||{});
    
    	this.selection_made = $F(this.target_element).strip()!=="";
    	this.use_time = this.options.get("time");
    
    	this.callback("before_show")
    	this.calendar_div = $(this.options.get("calendar_div"));
    
    	this.parseDate();
    
    	// By default, stick it by the target element (if embedded, that's where we'll want it to show up)...
    	if (this.calendar_div == nil) { this.calendar_div = $( this.options.get("embedded") ? this.target_element.parentNode : document.body ).build('div'); }
    	if (!this.options.get("embedded")) this.calendar_div.setStyle( { position:"absolute", visibility: "hidden", left:0, top:0 } )
    
    	this.calendar_div.addClassName("calendar_date_select");
    
    	if (this.options.get("embedded")) this.options.set("close_on_click", false);
    	// Logic for close on click...
    	if (this.options.get("close_on_click")===nil ){
      		if (this.options.get("time"))
        		this.options.set("close_on_click", false);
      		else
        		this.options.set("close_on_click", true);
    	}
    
    	// set the click handler to check if a user has clicked away from the document
    	if(!this.options.get("embedded")){
      		Event.observe(document,"mousedown",this.closeIfClickedOut_handler=this.closeIfClickedOut.bindAsEventListener(this));
			Event.observe(document,"keypress",this.keyPress_handler=this.keyPress.bindAsEventListener(this));
    	}
    
    	this.init();
    	if(!this.options.get("embedded")) { this.positionCalendarDiv() };
    	this.callback("after_show")
  	},
  	_oldIE:function(){
		return(Prototype.Browser.IE&&parseFloat(navigator.appVersion.split(';')[1].strip().split(' ')[1])<=6)?true:false;
	},
  	positionCalendarDiv:function(){
		var above=false;
		var c_pos=this.calendar_div.cumulativeOffset(),c_left=c_pos[0],c_top=c_pos[1],c_dim=this.calendar_div.getDimensions(),c_height=c_dim.height,c_width=c_dim.width; 
		var w_top = window.f_scrollTop(), w_height = window.f_height();
		var e_dim = $(this.options.get("popup_by")).cumulativeOffset(), e_top = e_dim[1], e_left = e_dim[0], e_height = $(this.options.get("popup_by")).getDimensions().height, e_bottom = e_top + e_height;
		
		if ( (( e_bottom + c_height ) > (w_top + w_height)) && ( e_bottom - c_height > w_top )) above = true;
		if(this.options.get("above"))above = true;
		var left_px = e_left.toString() + "px", top_px = (above ? (e_top - c_height ) : ( e_top + e_height )).toString() + "px";
		
		this.calendar_div.style.left=left_px; this.calendar_div.style.top = top_px;
		this.calendar_div.setStyle({visibility:""});
		
		// Draw an iframe behind the calendar -- ugly hack to make IE 6 happy...
		if(this._oldIE())
		this.iframe=$(document.body).build("iframe",{src:"javascript:false",className:"ie6_blocker"},
			{left:left_px,top:top_px,height:c_height.toString()+"px",width:c_width.toString()+"px",border:"0px"})
  	},
  	init:function(){
		// Create the divs...
		this.header_div=new Element("div",{"class":"cds_header"});
		var hdStyle=$H({position:"relative",width:"100%",height:"22px",backgroundImage:"url(/images/roc_calendar_bkg.png)"});
		var hdStyleIE6=$H({position:"relative",width:"100%",height:"22px",backgroundImage:"url(/images/roc_calendar_bkg_ie6.png)"});
		if(this._oldIE())
			this.header_div.setStyle(hdStyleIE6.toObject());
		else
			this.header_div.setStyle(hdStyle.toObject());
		
		this.body_div=new Element("div",{"class":"cds_body"}).setStyle({clear:"left",borderLeft:"2px solid #003366",borderRight:"2px solid #003366"});
		this.buttons_div=new Element("div").setStyle({clear:"left",borderLeft:"2px solid #003366",borderRight:"2px solid #003366",textAlign:"center",backgroundColor:"#024",height:"14px",lineHeight:"10px",fontSize:"10px"});
		this.footer_div=new Element("div").setStyle({clear:"left",fontSize:"12px",fontWeight:"bold",textAlign:"center",color:"#024",height:"24px",lineHeight:"20px"});
		if(this._oldIE())
			this.footer_div.setStyle({backgroundImage:"url(/images/roc_calendar_bkg_ie6.png)"});
		else
			this.footer_div.setStyle({backgroundImage:"url(/images/roc_calendar_bottom_bkg.png)"});
		this.calendar_div.insert(this.header_div);
		this.calendar_div.insert(this.body_div);
		this.calendar_div.insert(this.buttons_div);
		this.calendar_div.insert(this.footer_div);
	
		this.initHeaderDiv();
		this.initButtonsDiv();
		this.initCalendarGrid();
		
		this.refresh();
		this.setUseTime(this.use_time);
  	},
  	initHeaderDiv:function(){
		var header_div=this.header_div;
		/*
		this.close_button = header_div.build("a", { innerHTML: "x", href:"#", onclick:function(){ 
			this.close(); return false; }.bindAsEventListener(this),className:"close" });
		this.next_month_button = header_div.build("a",{innerHTML: "&gt;",href:"#",onclick:function(){
			this.navMonth(this.date.getMonth() + 1 ); return false; }.bindAsEventListener(this),className:"next" });
		this.prev_month_button = header_div.build("a",{innerHTML: "&lt;",href:"#",onclick:function(){
			this.navMonth(this.date.getMonth() - 1 ); return false; }.bindAsEventListener(this),className:"prev" });
		*/
		if(this.options.get("month_year")=="dropdowns"){
			var monthContainer=new Element("div").setStyle({position:"absolute",left:"4px",top:"3px",width:"80px",height:"18px"});
			this.header_div.insert(monthContainer);
		  	this.month_select=new SelectBox(monthContainer,$R(0,11).map(function(m){return [Date.months[m], m]}),{onchange: function(){this.navMonth(this.month_select.getValue()) }.bindAsEventListener(this)},{color:"#002244",fontSize:"10px",height:"18px"}); 
			var yearContainer=new Element("div").setStyle({position:"absolute",left:"88px",top:"3px",width:"60px",height:"18px"});
		  	this.header_div.insert(yearContainer);
		  	this.year_select = new SelectBox(yearContainer,[],{className:"year",onchange:function(){this.navYear(this.year_select.getValue())}.bindAsEventListener(this)},{color:"#002244",fontSize:"10px",height:"18px"}); 
		  	this.populateYearRange();
		}else{
		  	this.month_year_label=header_div.build("span")
		}
  	},
  	initCalendarGrid: function() {
		var body_div = this.body_div;
		this.calendar_day_grid = [];
		var days_table = body_div.build("table", { cellPadding: "0px", cellSpacing: "0px", width: "100%" })
		// make the weekdays!
		var weekdays_row = days_table.build("thead").build("tr");
		Date.weekdays.each( function(weekday){ weekdays_row.build("th", {innerHTML: weekday});});
		
		var days_tbody = days_table.build("tbody")
		// Make the days!
		var row_number = 0, weekday;
		for(var cell_index = 0;cell_index<42;cell_index++){
			weekday = (cell_index+Date.first_day_of_week ) % 7;
			if ( cell_index % 7==0 )days_row=days_tbody.build("tr",{className:'row_'+row_number++});
			(this.calendar_day_grid[cell_index] = days_row.build("td",{
				calendar_date_select:this,
				onmouseover: function () { this.calendar_date_select.dayHover(this); },
				onmouseout: function () { this.calendar_date_select.dayHoverOut(this) },
				onclick: function() { this.calendar_date_select.updateSelectedDate(this, true); },
				className: (weekday==0) || (weekday==6) ? " weekend" : "" //clear the class
			},{ cursor: "pointer" })).build("div");
			this.calendar_day_grid[cell_index];
		}
  	},
  	initButtonsDiv: function()
  	{
    	var buttons_div=this.buttons_div;
		b=buttons_div.build("span",{innerHTML:(this.options.get("arrival"))?"Arrival Date":"Departure Date"});
		b.setStyle({color:"#FFFFFF",fontSize:"12px",fontWeight:"bold"});
  	},
  	refresh:function(){
    	this.refreshMonthYear();
    	this.refreshCalendarGrid();
    	this.setSelectedClass();
    	this.updateFooter();
  	},
  	refreshCalendarGrid:function(){
    	this.beginning_date = new Date(this.date).stripTime();
    	this.beginning_date.setDate(1);
    	this.beginning_date.setHours(12); // Prevent daylight savings time boundaries from showing a duplicate day
    	var pre_days = this.beginning_date.getDay() // draw some days before the fact
    	if (pre_days < 3) pre_days += 7;
    	this.beginning_date.setDate(1 - pre_days + Date.first_day_of_week);
    
    	var iterator = new Date(this.beginning_date);
    
    	var today = new Date().stripTime();
    	var this_month = this.date.getMonth();
    	vdc = this.options.get("valid_date_check");
    	for (var cell_index = 0;cell_index<42; cell_index++){
      		day = iterator.getDate(); month = iterator.getMonth();
      		cell = this.calendar_day_grid[cell_index];
      		Element.remove(cell.childNodes[0]); div = cell.build("div", {innerHTML:day});
      		if (month!=this_month) div.className = "other";
      		cell.day = day; cell.month = month; cell.year = iterator.getFullYear();
      		if (vdc) { if (vdc(iterator.stripTime())) cell.removeClassName("disabled"); else cell.addClassName("disabled") };
      		iterator.setDate( day + 1);
    	}
    
    	if(this.today_cell) this.today_cell.removeClassName("today");
    
    	if( $R( 0, 42 ).include(days_until = this.beginning_date.stripTime().daysDistance(today)) ){
      		this.today_cell = this.calendar_day_grid[days_until];
      		this.today_cell.addClassName("today");
    	}
  	},
  	refreshMonthYear:function(){
    	var m = this.date.getMonth();
    	var y = this.date.getFullYear();
    	// set the month
    	if(this.options.get("month_year")=="dropdowns"){
      		this.month_select.setValue(m, false);
      		var e = this.year_select.element; 
      		if (this.flexibleYearRange() && (!(this.year_select.setValue(y, false)) || e.selectedIndex <= 1 || e.selectedIndex >= e.options.length - 2 )) this.populateYearRange();
      		this.year_select.setValue(y);
    	}else{
      		this.month_year_label.update( Date.months[m] + " " + y.toString()  );
    	}
  	},
  	populateYearRange:function(){
    	this.year_select.populate(this.yearRange().toArray());
 	},
  	yearRange:function(){
    	if(!this.flexibleYearRange())
      		return $R(this.options.get("year_range")[0], this.options.get("year_range")[1]);
      
    	var y = this.date.getFullYear();
    	return $R(y - this.options.get("year_range"), y + this.options.get("year_range"));
  	},
  	flexibleYearRange:function(){ 
		return (typeof(this.options.get("year_range")) == "number"); 
	},
  	validYear: function(year){ 
		if(this.flexibleYearRange()){ 
			return true;
		}else{ 
			return this.yearRange().include(year);
		}  
	},
  	dayHover:function(element){
    	var hover_date = new Date(this.selected_date);
    	hover_date.setYear(element.year); 
		hover_date.setDate(element.day);
		hover_date.setMonth(element.month); 
    	this.updateFooter(hover_date.toFormattedString(this.use_time));
		element.setStyle({backgroundColor:"#FFC",color:"#5B1E00"});
  	},
  	dayHoverOut:function(element){ 
  		this.updateFooter(); 
		element.setStyle({backgroundColor:(element.hasClassName("weekend"))?"#699":"#069",color:"#FF0"});
	},
  	setSelectedClass: function(){
    	if (!this.selection_made) return;
    
    	// clear selection
    	if (this.selected_cell) this.selected_cell.removeClassName("selected");
    
    	if ($R(0,42).include( days_until = this.beginning_date.stripTime().daysDistance(this.selected_date.stripTime()) )) {
      		this.selected_cell = this.calendar_day_grid[days_until];
      		this.selected_cell.addClassName("selected");
    	}
  	},
  	reparse:function(){ this.parseDate(); this.refresh(); },
  	dateString:function(){
    	return (this.selection_made) ? this.selected_date.toFormattedString(this.use_time) : "&#160;";
  	},
  	parseDate:function(){
		var value = $F(this.target_element).strip()
		this.date = value=="" ? NaN : Date.parseFormattedString(this.options.get("date") || value);
		if (isNaN(this.date)) this.date = new Date();
		if (!this.validYear(this.date.getFullYear())) this.date.setYear( (this.date.getFullYear() < this.yearRange().start) ? this.yearRange().start : this.yearRange().end);
		this.selected_date = new Date(this.date);
		this.use_time = /[0-9]:[0-9]{2}/.exec(value) ? true : false;
		this.date.setDate(1);
  	},
	updateFooter:function(text){ 
  		if(!text)text=this.dateString(); 
		this.footer_div.purgeChildren(); 
		this.footer_div.build("span", {innerHTML: text }); },
  			updateSelectedDate:function(partsOrElement, via_click) {
    		var parts = $H(partsOrElement);
    		if ((this.target_element.disabled || this.target_element.readOnly) && this.options.get("popup") != "force") return false;
    		if (parts.get("day")) {
      			var t_selected_date = this.selected_date, vdc = this.options.get("valid_date_check");
      			for (var x = 0; x<=3; x++) t_selected_date.setDate(parts.get("day"));
      			t_selected_date.setYear(parts.get("year"));
      			t_selected_date.setMonth(parts.get("month"));
      
      			if (vdc && ! vdc(t_selected_date.stripTime())) { return false; }
      			this.selected_date = t_selected_date;
      			this.selection_made = true;
    		}
    
    	if (!isNaN(parts.get("hour"))) this.selected_date.setHours(parts.get("hour"));
    	if (!isNaN(parts.get("minute"))) this.selected_date.setMinutes( Math.floor_to_interval(parts.get("minute"), this.options.get("minute_interval")) );
		if (parts.get("hour") === "" || parts.get("minute") === "") 
		  	this.setUseTime(false);
		else if (!isNaN(parts.get("hour")) || !isNaN(parts.get("minute")))
		  	this.setUseTime(true);
		
		this.updateFooter();
		this.setSelectedClass();
		
		if (this.selection_made) this.updateValue();
		if (this.options.get("close_on_click")) { this.close(); }
		if (via_click && !this.options.get("embedded")) {
		  	if ((new Date() - this.last_click_at) < 333) this.close();
		  	this.last_click_at = new Date();
		}
  	},
  	navMonth:function(month){ 
  		(target_date = new Date(this.date)).setMonth(month); 
		return (this.navTo(target_date)); 
	},
  	navYear:function(year){ 
		(target_date = new Date(this.date)).setYear(year); return (this.navTo(target_date)); 
	},
  	navTo:function(date){
		if (!this.validYear(date.getFullYear())) return false;
		this.date = date;
		this.date.setDate(1);
		this.refresh();
		this.callback("after_navigate", this.date);
		return true;
  	},
  	setUseTime: function(turn_on){
    	this.use_time=this.options.get("time") && (this.options.get("time")=="mixed" ? turn_on : true) // force use_time to true if time==true && time!="mixed"
    	if(this.use_time && this.selected_date){ // only set hour/minute if a date is already selected
			var minute = Math.floor_to_interval(this.selected_date.getMinutes(), this.options.get("minute_interval"));
			var hour = this.selected_date.getHours();
		  
			this.hour_select.setValue(hour);
			this.minute_select.setValue(minute)
    	}else if(this.options.get("time")=="mixed"){
      		this.hour_select.setValue(""); this.minute_select.setValue("");
    	}
  	},
  	updateValue:function(){
		var last_value=this.target_element.value;
		this.target_element.value = this.dateString();
		if(last_value!=this.target_element.value) this.callback("onchange");
  	},
  	today:function(now){
		var d = new Date(); this.date = new Date();
		var o = $H({ day: d.getDate(), month: d.getMonth(), year: d.getFullYear(), hour: d.getHours(), minute: d.getMinutes()});
		if(!now) o = o.merge({hour: "", minute:""}); 
		this.updateSelectedDate(o, true);
		this.refresh();
  	},
  	close:function(){
		if (this.closed) return false;
		this.callback("before_close");
		this.target_element.calendar_date_select = nil;
		Event.stopObserving(document, "mousedown", this.closeIfClickedOut_handler);
		Event.stopObserving(document, "keypress", this.keyPress_handler);
		this.calendar_div.remove(); this.closed = true;
		if (this.iframe) this.iframe.remove();
		if (this.target_element.type!="hidden") this.target_element.focus();
		this.callback("after_close");
  	},
  	closeIfClickedOut:function(e){
    	if (! $(Event.element(e)).descendantOf(this.calendar_div) ) this.close();
  	},
  	keyPress:function(e){
    	if (e.keyCode==Event.KEY_ESC) this.close();
  	},
  	callback:function(name,param){ 
		if (this.options.get(name)) { this.options.get(name).bind(this.target_element)(param); } }
	}
);
