var mooCalendar = {

	daysInWeek: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
	monthsInYear: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
	daysInMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
	minYear: 1900,
	maxYear: new Date().getFullYear(),
	curDate: 0,
	labelChars: 1,
	itemBuffer: 40,
	dateFormat: 'd/m/y',
	triggerElement: null,
	insertElement: null,
	created: false,
	active: false,
	FX: null,
	docBody: null,
	hasFocus: false,
	timeoutId: null,
	
	
	start: function(){
		if (!$('mooCalendar')) {
			mooCalendar.create();
		}
		
		var calInputs = $$('input.mooCalendar');
		if ( calInputs.length ) {
			calInputs.each(function(elem, idx) {
				elem.addEvent('click', function() {
					mooCalendar.FX.cancel();
					mooCalendar.toggleCalendar(elem)
				});
			});
		}
	},
	
	
	create: function() {
		var cal = new Element('div', {id: 'mooCalendar'});
		cal.setStyle('opacity', 0);
		cal.setStyle('display', 'none');
		
		var tmp = $$('body');
		this.docBody = tmp[0]
		this.docBody.adopt(cal);
		
		this.FX = new Fx.Morph(cal, {	'duration': 600, 
										'wait': false, 
										'transition': Fx.Transitions.Quad.easeOut, 
										'onComplete': 	function() { 
															if ( $('mooCalendar').getStyle('opacity') == 0 )
																$('mooCalendar').setStyle('display', 'none')
															if ( mooCalendar.timeoutId ) {
																window.clearTimeout(mooCalendar.timeoutId);
																mooCalendar.timeoutId = null;
															}
														}
										});
		
		cal.addEvent('mouseover', function() {
			mooCalendar.hasFocus = true;
		});
		
		cal.addEvent('mouseout', function() {
			mooCalendar.hasFocus = false;
			mooCalendar.timeoutId = window.setTimeout(mooCalendar.delayedHide, 4000);
		});
		
		mooCalendar.created = true;
	},
	
	
	toggleCalendar: function(triggerElement) {
		if ( !triggerElement ) {
			alert('No trigger element specified, please check your code.');
			return false;
		}
		
		if ( triggerElement != mooCalendar.triggerElement ) {
			mooCalendar.triggerElement = triggerElement;
			mooCalendar.insertElement = triggerElement;
			
			if ( mooCalendar.triggerElement.value ) {
				var split = mooCalendar.triggerElement.value.split('/');
				
				if ( split[0] && split[1] && split[2] ) {
					var d = parseInt(split[0], 10);
					var m = parseInt(split[1], 10);
					var y = parseInt(split[2], 10);
				} else {
					var y = null;
					var m = null;
					var d = null;
				}
			} else {
				var y = null;
				var m = null;
				var d = null;
			}
			
			this.curDate = {'y': parseInt(y, 10), 'm': parseInt(m, 10), 'd': parseInt(d, 10)};
		
			mooCalendar.display(y, m, d);
		} else {
			mooCalendar.hide();
			mooCalendar.triggerElement = null;
			mooCalendar.insertElement = null;
		}
	},
	
	
	display: function(y, m, d) {
		var date = new Date();
		
		if ( !y ) {		var y = date.getFullYear();		}
		if ( !m ) {		var m = date.getMonth() + 1;	}
		if ( !d ) {		var d = date.getDate();			}
		
		var layoutDate = new Date(y, m - 1, 1, 0, 0, 0, 0);
		var startDay = layoutDate.getDay();
		
		if ( m == 2 ) {
			if ( y % 4 == 0 ) {
				var daysInMonth = 28;
			} else {
				var daysInMonth = this.daysInMonth[m-1];
			}
		} else {
			var daysInMonth = this.daysInMonth[m-1];
		}
		
		// Clear all the contents from the frame for redisplay
		$('mooCalendar').empty();
		
		this.createDateDropdowns(y, m);
		this.createWeekHeaders();
		this.createMonthFrame(y, m, d, startDay, daysInMonth);
		
		// Get positioning data
		$('mooCalendar').setStyle('display', 'block');
		ePos = this.triggerElement.getPosition();
		eSize = this.triggerElement.getSize();
		wSize = this.docBody.getSize();
		cSize = $('mooCalendar').getSize();
		
		// Position it!
		if ( ePos.y + eSize.y + cSize.y + this.itemBuffer > wSize.y ) {
			$('mooCalendar').setStyle('position', 'absolute');
			$('mooCalendar').setStyle('left', ePos.x + 'px');
			$('mooCalendar').setStyle('top', (ePos.y - cSize.y) + 'px');
		} else {
			$('mooCalendar').setStyle('position', 'absolute');
			$('mooCalendar').setStyle('left', ePos.x + 'px');
			$('mooCalendar').setStyle('top', ePos.y + eSize.y + 'px');
		}
		
		this.FX.start({ 'opacity': [$('mooCalendar').getStyle('opacity'), 0.95]	});
	},
	
	
	reDisplay: function(y, m) {
		var layoutDate = new Date(y, m - 1, 1, 0, 0, 0, 0);
		var startDay = layoutDate.getDay();
		
		if ( m == 2 ) {
			if ( y % 4 == 0 ) {
				var daysInMonth = 28;
			} else {
				var daysInMonth = this.daysInMonth[m-1];
			}
		} else {
			var daysInMonth = this.daysInMonth[m-1];
		}
		
		// Remove the current month display
		$('calMonthFrame').dispose();
		
		this.createMonthFrame(y, m, 1, startDay, daysInMonth);
		
		
		ePos = this.triggerElement.getPosition();
		eSize = this.triggerElement.getSize();
		wSize = this.docBody.getSize();
		cSize = $('mooCalendar').getSize();
		
		// Position it!
		if ( ePos.y + eSize.y + cSize.y + this.itemBuffer > wSize.y ) {
			$('mooCalendar').setStyle('position', 'absolute');
			$('mooCalendar').setStyle('left', ePos.x + 'px');
			$('mooCalendar').setStyle('top', (ePos.y - cSize.y) + 'px');
		} else {
			$('mooCalendar').setStyle('position', 'absolute');
			$('mooCalendar').setStyle('left', ePos.x + 'px');
			$('mooCalendar').setStyle('top', ePos.y + eSize.y + 'px');
		}
	},
	
	
	delayedHide: function() {
		if ( !mooCalendar.hasFocus ) {
			mooCalendar.hide();
			mooCalendar.triggerElement = null;
			mooCalendar.insertElement = null;
		}
	},
	
	
	hide: function() {
		if ( mooCalendar.timeoutId ) {
			window.clearTimeout(mooCalendar.timeoutId);
			mooCalendar.timeoutId = null;
		}
		
		this.FX.start({ 'opacity': [$('mooCalendar').getStyle('opacity'), 0]	});
	},
	
	
	createDateDropdowns: function(y, m) {
		var ddContain = new Element('div', {'class': 'calDropdownContainer'});
		var ddYear = new Element('select', {id: 'calYear', 'class': 'calYear'});
		var ddMonth = new Element('select', {id: 'calMonth', 'class': 'calMonth'});
		var btnClose = new Element('input', {id: 'btnCloseCalendar', 'type': 'button', 'value': 'X'});
		
		for ( var x = this.minYear; x <= this.maxYear; x++ ) {
			ddYear.adopt(new Element('option', {value: x, text: x, selected: ((y == x) ? true : false)}));
		}
		
		// Add onChange update event
		ddYear.addEvent('change', function() {		mooCalendar.reDisplay($('calYear').value, $('calMonth').value);	});
		
		for ( var x = 0; x < 12; x++ ) {
			ddMonth.adopt(new Element('option', {value: (x+1), text: this.monthsInYear[x], selected: ((m - 1 == x) ? true : false)}));
		}
		
		// Add onChange update event
		ddMonth.addEvent('change', function() {		mooCalendar.reDisplay($('calYear').value, $('calMonth').value);	});
		
		btnClose.addEvent('click', function() {		mooCalendar.hide();	});
		
		ddContain.adopt(ddMonth, ddYear, btnClose);
		
		$('mooCalendar').adopt(ddContain);
	},
	
	
	createWeekHeaders: function() {
		var weekdayContain = new Element('div', {'class': 'calWeekdayHeader'});
		var weekdayList = new Element('ul', {'class': 'calWeekdayList'});
		
		for ( var x = 0; x < 7; x++ ) {
			weekdayList.adopt(new Element('li', {text: this.daysInWeek[x].substr(0, this.labelChars), 'class': 'calDayHeader calDayCell calDay' + x}));
		}
		
		weekdayContain.adopt(weekdayList);
		$('mooCalendar').adopt(weekdayContain);
	},
	
	
	createMonthFrame: function(y, m, d, start, days) {
		var calUL = new Element('ul', {'class': 'calMonthFrame',	id: 'calMonthFrame'});
		var cellCount = 0;
		
		// Pad the start of the month as necessary
		for ( var x = 0; x < start; x++ ) {
			calUL.adopt(new Element('li', {'class': 'calDayBlank calDayCell'}));
			cellCount++;
		}
		
		today = new Date();
		var tY = today.getFullYear();
		var tM = today.getMonth() + 1;
		var tD = today.getDate();
		
		// Fill in the days
		for ( var x = 1; x <= days; x++ ) {
			// Selected Class
			if ( this.curDate.y == y && this.curDate.m == m && this.curDate.d == x ) {
				var selectedClass = ' selected';
			} else {
				var selectedClass = '';
			}
			
			// Today Class
			if ( tY == y && tM == m && tD == x ) {
				var todayClass = ' today';
			} else {
				var todayClass = '';
			}
			
			var li = new Element('li', {	'class': 'calDayFilled calDayCell calDay' + (cellCount%7) + ((d == x) ? ' calDaySelected' : '') + selectedClass + todayClass, 
											text: x,
											dayNum: x});
			
			li.addEvent('click', function() {		mooCalendar.fillDate(this.getProperty('dayNum'));	 });
			
			calUL.adopt(li);
			cellCount++;
		}
		
		// Pad the end of the month as necessary
		while ( cellCount % 7 != 0 ) {
			calUL.adopt(new Element('li', {'class': 'calDayBlank calDayCell'}));
			cellCount++;
		}
		
		// Attach it to the calendar
		$('mooCalendar').adopt(calUL, new Element('div', {'class': 'clear'}));
	},
	
	
	fillDate: function(day) {
		if ( this.insertElement && this.insertElement.value != 'undefined' ) {
			this.insertElement.value = $('calYear').value + (($('calMonth').value < 10) ? '0' : '') + $('calMonth').value + ((day < 10) ? '0' : '') + day;
		}
		
		if ( this.triggerElement && this.triggerElement.value != 'undefined' ) {
			var date = this.dateFormat;
			date = date.replace(/d/, ((day < 10) ? '0' : '') + day);
			date = date.replace(/m/, (($('calMonth').value < 10) ? '0' : '') + $('calMonth').value);
			date = date.replace(/y/, $('calYear').value);
			this.triggerElement.value = date;
		}
		
		this.hide();
		this.triggerElement = null;
		this.insertElement = null;
	},
	
	
	setOptions: function(options) {
		if ( options.minYear ) {			this.minYear = parseInt(options.minYear);			}
		if ( options.maxYear ) {			this.maxYear = parseInt(options.maxYear);			}
		if ( options.curDate ) {			this.curDate = parseInt(options.curDate);			}
		if ( options.triggerElement ) {		this.triggerElement = options.triggerElement;		}
		if ( options.insertElement ) {		this.triggerElement = options.insertElement;		}
		if ( options.labelChars ) {			this.labelChars = parseInt(options.labelChars);		}
		if ( options.dateFormat ) {			this.labelChars = parseInt(options.dateFormat);		}
	}
	
};

window.addEvent('domready', mooCalendar.start);
