// -----------------------------------------------------------------------------------
//
//	Calendar v1.0
//	by Alonzo Turner - http://www.subtextproductions.com
//	11/16/07
//
//	For more information on this script, visit:
//	http://www.subtextproductions.com/opensource
//
//	Licensed under the Creative Commons Attribution 2.5 License - http://creativecommons.org/licenses/by/2.5/
//	
//	Calendar is based on Tim Harper's Calendar Date Select 1.11.1 - http://code.google.com/p/calendardateselect/
//
//	Credit also due to those who have helped, inspired, and made their code available to the public.
//	Including: Lokesh Dhakar(huddletogether.com), Thomas Fuchs(mir.aculo.us), Sam Stephenson(prototypejs.org), and others.
//
//
// -----------------------------------------------------------------------------------
/*

	TABLE OF CONTENTS
	-----------------
	
	SANITY CHECK

	EXTEND STRING OBJECT
	- pad()

	EXTEND DATE OBJECT
	- getMonths()
	- getYearRange()
	- getCalendarMonth()
	- getCalendarYear()
	
	EXTEND ELEMENT METHODS
	- append()
	- prepend()

	SELECTBOX CLASS DECLARATION
	- initialize()
	- populate()
	- setValue()
	- getValue()
	
	CALENDAR CLASS DECLARATION
	- initialize()
	- build()
	- populate()
	- position()
	- update()
	- emphasize()
	- understate()
	- select()
	- close()
	- setSelectedDate()
	
	INSTANTIATION
	- addLoadEvent(initScrollBars)
	
*/
// -----------------------------------------------------------------------------------
if ((typeof Prototype == 'undefined') || (Prototype.Version < "1.6")){ alert("Prototype 1.6.0 is required."); }

String.prototype.pad = function(someString, someLength, somePosition){
    return someString || (someString = " "), (someLength -= this.length) > 0 ? (someString = new Array(Math.ceil(someLength / someString.length) + 1).join(someString)).substr(0, somePosition = !somePosition ? someLength : somePosition == 1 ? 0 : Math.ceil(someLength / 2)) + this + someString.substr(0, someLength - somePosition) : this;
}

Date.prototype.getMonths = function(){
	return [['0', 'January'], ['1', 'February'], ['2', 'March'], ['3', 'April'], ['4', 'May'], ['5', 'June'], ['6', 'July'], ['7', 'August'], ['8', 'September'], ['9', 'October'], ['10', 'November'], ['11', 'December']];
}

Date.prototype.getYearRange = function(someInteger){
	var someYear = parseInt(this.getFullYear());
	return $R(someYear - someInteger, someYear + someInteger);
}

Date.prototype.getCalendarMonth = function(){
	return String(this.getMonth() + 1);
}

Date.prototype.getCalendarYear = function(){
	return String(this.getFullYear());
}

Date.prototype.getDayOfWeek = function(){
	var someWeekday;
	switch(this.getDay()){
	case 0:
		someWeekday = "Sunday";
		break;
	case 1:
		someWeekday = "Monday";
		break;
	case 2:
		someWeekday = "Tuesday";
		break;
	case 3:
		someWeekday = "Wednesday";
		break;
	case 4:
		someWeekday = "Thursday";
		break;
	case 5:
		someWeekday = "Friday";
		break;
	case 6:
		someWeekday = "Saturday";
		break;
	}
	return someWeekday;
}

Date.prototype.getUserFormat = function(){
	var someWeekday, someDay, someMonth, monthList = this.getMonths(), someYear;
	someWeekday = this.getDayOfWeek();
	someMonth = monthList[this.getMonth()][1];
	someDay = this.getDate();
	someYear = this.getFullYear();
	return someWeekday + " " + someMonth + " " + someDay + ", " + someYear;
}

Date.prototype.getMysqlFormat = function(){
	var someYear, someMonth, someDay;
	someYear = this.getFullYear();
	someMonth = this.getCalendarMonth().pad("0", 2, 0);
	someDay = String(this.getDate()).pad("0", 2, 0);
	return someMonth + "/" + someDay + "/" + someYear;
}

Element.addMethods({
	append: function(element, type, attributes, style){
		element = $(element);
		var someElement = new Element(type, attributes);
		someElement.setStyle(style);
		element.insert({ bottom: someElement });
		return someElement;
	},
	
	prepend: function(element, type, attributes, style){
		element = $(element);
		var someElement = new Element(type, attributes);
		someElement.setStyle(style);
		element.insert({ top: someElement });
		return someElement;
	}
});

var SelectBox = Class.create({
	initialize: function(element, values, selected, options, style){
		this.dropdown = $(element).append("select", options, style);
		this.populate(values);
		this.setValue(selected);
	},
	
	populate: function(values){
		this.dropdown.update();
		values.each(function(pair){
			if(typeof(pair) != "object"){
				pair = [pair, pair];
			}
			this.dropdown.insert(new Element("option", { value: pair[0]}).update(pair[1]));
		}, this);
	},
	
	element: function(){
		return this.dropdown;
	},
	
	setValue: function(value){
		var targetIndex = $A(this.dropdown.options).pluck('value').indexOf(value);
		if(targetIndex >= 0){
			this.dropdown.selectedIndex = targetIndex;
		}
	},
	
	getValue: function(){
		return $F(this.dropdown);
	}
});

var Calendar = Class.create({
	initialize: function(){
		this.body = $(document.body);
		this.date = new Date();
		this.day = this.date.getDate();
		this.month = this.date.getMonth();
		this.year = this.date.getFullYear();
		this.focus = this.trigger.bindAsEventListener(this);
		this.illuminate = this.emphasize.bindAsEventListener(this);
		this.obscure = this.understate.bindAsEventListener(this);
		this.click = this.select.bindAsEventListener(this);
		this.active = false;
		this.build();
		new Draggable(this.container.identify(), { handle: this.handle });
	},
	
	build: function(){
		var style = {
			position: 'absolute',
			left: '0px',
			top: '0px',
			display: 'none',
			zIndex: 10000
		};
		this.container = this.body.append('div', { className: "calendar_" }, style);
		this.handle = this.container.append('div', { className: "handle_" }, {});
		this.handle.update(this.date.getUserFormat());
		this.buttons = this.container.append('div', { className: "calendarButtons_" }, {});
		var updateFunction = this.update.bindAsEventListener(this);
		this.buttons.append('a', { href: '#', id: 'previous-month_' }, { fontSize: '1.25em' }).update("&lt;");
		$('previous-month_').observe('click', updateFunction);
		this.monthSelect = new SelectBox(this.buttons, this.date.getMonths(), String(this.date.getMonth()), { name: 'selectMonth', id: 'selectMonth_' }, { fontSize: '1em' });
		this.monthSelect.element().observe('change', updateFunction);
		this.yearSelect = new SelectBox(this.buttons, this.date.getYearRange(5), this.date.getCalendarYear(), { name: 'selectYear', id: 'selectYear_' }, {});
		this.yearSelect.element().observe('change', updateFunction);
		this.buttons.append('a', { href: '#', id: 'next-month_' }, { fontSize: '1.25em' }).update("&gt;");
		$('next-month_').observe('click', updateFunction);
		this.table = this.container.append('table', { width: '100%', cellpadding: '0', cellspacing: '0', border: '0' });
		var someHead = this.table.append('thead', {}, {}).append('tr', {}, {});
		$w("S M T W T F S").each(function(e){
			someHead.append('th', {}, {}).update(e);
		});
		this.grid = this.table.append('tbody', {}, {});
		$R(0, 42, true).each( function(someInteger){
			var someRow;
			if(someInteger % 7 == 0){
				someRow = this.grid.append('tr', {}, {});
			}else{
				someRow = this.grid.select('tr:last-child');
				someRow = someRow[0];
			}
			someRow.append('td', {}, {}).observe('click', this.click);
		}, this );
		this.foot = this.container.append('div', { className: 'foot_' }, {});
		var theCloser = this.close.bind(this);

		this.container.append('a', { href: '#', className: 'upper-left_ close_' }, {}).update('X').observe('click', theCloser);

		
		this.foot.append('a', { href: '#' }, {}).update('Today').observe('click', this.setTodaysDate.bind(this));
		this.container.select('td').each( function(someElement){
			someElement.observe('mouseover', this.illuminate);
			someElement.observe('mouseout', this.obscure);
		}, this);
		this.populate(this.month, this.year);
		this.watch();
	},
		
	populate: function(someMonth, someYear){
		var i = 0, someDay = new Date(), someWeekDay;
		someDay.setDate(1);//ALWAYS SET DAY BEFORE MONTH AND YEAR
		someDay.setMonth(someMonth);
		someDay.setFullYear(someYear);
		someWeekDay = someDay.getDay();
		i = 1 - someWeekDay;
		this.grid.select('td').each(function(someElement){
			someDay.setDate(1);//RESET THE DATE OBJECT
			someDay.setFullYear(someYear);
			someDay.setMonth(someMonth);
			someDay.setDate(i);
			someElement.classNames().each(function(someName){
				someElement.removeClassName(someName);
			});
			if(someDay.getDate() == this.day && someDay.getMonth() == this.month && someDay.getFullYear() == this.year){
				someElement.addClassName('today_');
			}else{
				if(someDay.getMonth() != someMonth){
					someElement.addClassName('obscure_');
				}
			}
			var someWeekDay = someDay.getDay();
			if( someWeekDay == 0 || someWeekDay == 6 ){
				someElement.addClassName('weekend_');
			}
			someElement.update(someDay.getDate());
			i++;
		}, this);
		delete someDay;
	},
	
	watch: function(){
		$$('input.date-select_').each( function(someElement){
			someElement.observe('focus', this.focus);
		}, this);
	},

	position: function(someElement){
		var someElement = $(someElement);
		var someOffset = someElement.cumulativeOffset();
		var someStyle = {
			top: (someOffset.top ) + 'px',
			left: (someOffset.left - 200 ) + 'px'
		};
		this.container.setStyle(someStyle);
	},
	
	update: function(someEvent){
		someEvent.stop();
		var someOptions = $A(this.yearSelect.element().options).pluck('value');
		var firstYear = someOptions.first();
		var lastYear = someOptions.last();
		var someMonth = this.monthSelect.getValue();
		var someYear = this.yearSelect.getValue();
		var someTarget = someEvent.element();
		switch(someTarget.id){
		case 'selectYear_':
		case 'selectMonth_':
			this.handle.update();
			break;
		case 'previous-month_':
			if(someMonth == 0){
				someMonth = 11;
				someYear--;
				if(someYear >= firstYear){
					this.yearSelect.setValue(String(someYear));
				}else{
					return false;
				}
			}else{
				someMonth--;
			}
			this.handle.update();
			break;
		case 'next-month_':
			if(someMonth == 11){
				someMonth = 0;
				someYear++;
				if(someYear <= lastYear){
					this.yearSelect.setValue(String(someYear));
				}else{
					return false;
				}
			}else{
				someMonth++;
			}
			this.handle.update();
			break;
		default:
			if(someTarget.hasClassName('date-select_')){
				var re = /^([0-9]{2})\/([0-9]{2})\/([0-9]{4})$/;
				re.test($F(someTarget));
				someYear = String(RegExp.$3);
				someMonth = RegExp.$1 - 1;
				someDay = String(parseInt(RegExp.$2));
				this.yearSelect.setValue(someYear);
				this.monthSelect.setValue(String(someMonth));
				var someBox = this.container.select('td:not(.obscure_)').find(function(i){
					return i.innerHTML = someDay;
				});
				this.setSelectedDate(someBox);
				this.handle.update(this.date.getUserFormat());
			}
		}
		this.monthSelect.setValue(String(someMonth));
		this.populate(someMonth, someYear);
	},
	
	trigger: function(someEvent){
		var someElement = someEvent.element();
		var re = /^([0-9]{2})\/([0-9]{2})\/([0-9]{4})$/;
		this.active = true;
		this.position(someElement);
		this.input = someElement;
		if(re.test($F(this.input)) && $F(this.input) != '0000-00-00'){
			this.update(someEvent);
		}else{
			this.setTodaysDate(someEvent);
		}
		this.container.show();
	},
		
	emphasize: function(someEvent){
		var someElement = someEvent.element();
		if(!someElement.hasClassName('close_')){
			this.setSelectedDate(someElement);
			this.handle.update(this.date.getUserFormat());
		}
		someElement.addClassName('highlight_');
	},
	
	understate: function(someEvent){
		var someElement = someEvent.element();
		if(!someElement.hasClassName('close_')){
			this.handle.update();
		}
		someElement.removeClassName('highlight_');
	},
	
	select: function(someEvent){
		this.setSelectedDate(someEvent.element());
		this.input.value = this.date.getMysqlFormat();
		this.close(someEvent);
	},
	
	close: function(someEvent){
		someEvent.stop();
		if(this.active){
			this.container.hide().setStyle({ top: '0px', left: '0px' });
			this.active = false;
		}
	},
	
	setSelectedDate: function(someElement){
		var someNumber = someElement.innerHTML;
		var someMonth = this.monthSelect.getValue();
		var someYear = this.yearSelect.getValue();
		this.date.setDate(1);
		this.date.setMonth(someMonth);
		this.date.setFullYear(someYear);
		if(someElement.hasClassName('obscure_')){
			if(someNumber > 15){
				if(someMonth == 0){
					someMonth = 11;
					someYear--;
					this.date.setYear(someYear);
				}else{
					someMonth--;
				}
			}else{
				if(someMonth == 11){
					someMonth = 0;
					someYear++;
					this.date.setYear(someYear);
				}else{
					someMonth++;
				}
			}
			this.date.setMonth(someMonth);
		}
		this.date.setDate(someNumber);
	},
	
	setTodaysDate: function(someEvent){
		someEvent.stop();
		this.date.setYear(this.year);
		this.yearSelect.setValue(String(this.year));
		this.date.setMonth(this.month);
		this.monthSelect.setValue(String(this.month));
		this.date.setDate(this.day);
		this.handle.update(this.date.getUserFormat());
		this.populate(this.month, this.year);
	}
});
