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: (new Date().getFullYear() - 10),
	maxYear: (new Date().getFullYear() + 10),
	curDate: 0,
	labelChars: 1,
	itemBuffer: 40,
	dateFormat: 'd/m/y',
	triggerElement: null,
	insertElement: null,
	created: false,
	active: false,
	FX: null,
	docBody: null,
	hasFocus: false,
	
	
	start: function(){
		if (!$('mooCalendar')) {
			mooCalendar.create();
		}
	},
	
	
	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') }});
		
		cal.addEvent('mouseover', function() {
			mooCalendar.hasFocus = true;
		});
		
		cal.addEvent('mouseout', function() {
			mooCalendar.hasFocus = false;
			window.setTimeout(mooCalendar.delayedHide, 4000);
		});
		
		mooCalendar.created = true;
	},
	
	
	toggleCalendar: function(triggerElement, insertElement, startDate) {
		if ( !triggerElement ) {
			alert('No trigger element specified, please check your code.');
			return false;
		}
		
		if ( triggerElement != mooCalendar.triggerElement ) {
			mooCalendar.triggerElement = triggerElement;
			mooCalendar.insertElement = insertElement;
			
			if ( startDate ) {
				var y = startDate.substr(0, 4);
				var m = startDate.substr(4, 2);
				var d = startDate.substr(6, 2);
			} else {
				var y = null;
				var m = null;
				var d = null;
			}
			
			this.curDate = {'y': y, '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]	});
		
		// Woo IE6, shittest browser ever.
		if ( navigator.appVersion.toLowerCase().indexOf('msie') != -1 ) {
			// Hide all selects
			var selects = $$('select');
			selects.each(function(select, idx) {
				if ( select.id != 'calYear' && select.id != 'calMonth' ) {
					select.setStyle('visibility', 'hidden');
				} else {
					select.setStyle('visibility', 'visible');
				}
			});
		}
	},
	
	
	reDisplay: function(y, m) {
		var layoutDate = new Date(y, m - 1, 1, 0, 0, 0, 0);
		var jsMonth = m - 1;
		
		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();
//		}
	},
	
	
	hide: function() {
		this.FX.start({ 'opacity': [$('mooCalendar').getStyle('opacity'), 0]	});
		
		
		// Woo IE6, shittest browser ever.
		if ( navigator.appVersion.toLowerCase().indexOf('msie') != -1 ) {
			// Hide all selects
			var selects = $$('select');
			selects.each(function(select, idx) {
				if ( select.id != 'calYear' && select.id != 'calMonth' ) {
					select.setStyle('visibility', 'visible');
				} else {
					select.setStyle('visibility', 'hidden');
				}
			});
		}
	},
	
	
	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'});
		
		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);	});
		
		ddContain.adopt(ddMonth, ddYear);
		$('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();
	},
	
	
	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);
