var CalendarController = new Object();

Object.extend(CalendarController, {

	calendars: [],
	observing: false,

	addCalendar: function(calendar) {
		this.calendars.push(calendar);
		return this.calendars.length - 1;
	},

	observe: function() {
		var targ = this;
		if (!this.observing) {
			this.observing = true;
			Event.observe(document, 'mouseup', function(e) { targ.closeCalendars(e) }, false);
		}
	},

	closeCalendars: function(e) {
		this.calendars.each(function(calendar) {
			var node = Event.element(e);
			while (node != document) {
				if(node == calendar.cal_icon || node == calendar.calendar_container) {
					break;
				}
				node = node.parentNode;
			}
			if (node != calendar.cal_icon && node != calendar.calendar_container) {
				calendar.hideCalendar();
			}
		});

	}

});

var Calendar = Class.create();

Calendar.prototype = {

	separator: '-',
	days:      ['S', 'M', 'T', 'W', 'T', 'F', 'S'],
	months:    ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],

	initialize: function(cal_icon) {
		var targ = this;
		if (!CalendarController) {
			 alert('No Calendar Controller is defined, ensure that CalendarController exists, and is initialised');
			return false;
		} else {
			 CalendarController.observe();
		}
		this.id = CalendarController.addCalendar(this);
		this.cal_icon = document.getElementById(cal_icon);
		this.cal_icon.onclick = function() { targ.showCalendar(); }

		this.calendar_container = document.createElement('div');
		this.calendar_container.className = 'calendar';
	},

	showCalendar: function() {

		var targ = this;
		this.cal_icon.parentNode.appendChild(this.calendar_container);
		if (!this.form) {
			alert('Unable to locate form elements for calendar, use setFields()'); return false;
		}
		this.getDefaultDate();
		this.generateCalendar();
		this.cal_icon.onclick = function() { targ.hideCalendar(); }
	},
		
	hideCalendar: function() {
		if (this.calendar_container.parentNode && typeof this.calendar_container.parentNode.innerHTML != 'undefined') {
			var targ = this;
			this.calendar_container.innerHTML = '';
			this.cal_icon.parentNode.removeChild(this.calendar_container);
			this.cal_icon.onclick = function() { targ.showCalendar(); }
		}
	},

	getDefaultDate: function() {
		this.selected_date = this.convertDateFrom();
		this.form_date = new Date(this.selected_date.valueOf());
		
		if (this.selected_date < this.min_date) {
			this.selected_date = new Date(this.min_date.valueOf());
		} else if (this.selected_date > this.max_date) {
			this.selected_date = new Date(this.max_date.valueOf());
		}
	},

	generateCalendar: function() {
		var targ = this;
		var cal_content, nextmonth, prevmonth, beginday, lastday, currentdate, daystyle, rowpos;

		nextmonth = new Date(this.selected_date.valueOf());
		nextmonth.setMonth(nextmonth.getMonth() + 1);
		prevmonth = new Date(this.selected_date.valueOf());
		prevmonth.setMonth(prevmonth.getMonth() - 1);
		beginday = new Date(this.selected_date.valueOf());
		beginday.setDate(1);

		cal_table = $E({tag: 'table', className: 'calendar-container'});
		cal_tbody = $E({tag: 'tbody'});
		cal_row = $E({tag: 'tr', className: 'calendar-header'});
		
		if (prevmonth < this.min_date) {
			cal_cell = $E({tag: 'td'});
		} else {
			cal_cell = $E({tag: 'td', className: 'jump-month', innerHTML: '&laquo;', onclick: function() { targ.updateDate(0,-1,0) }});
		}
		cal_row.appendChild(cal_cell);
		cal_cell = $E({tag: 'td', colSpan: 5, innerHTML: this.months[this.selected_date.getMonth()] + ' ' + this.selected_date.getFullYear()});
		cal_row.appendChild(cal_cell);
		if (nextmonth > this.max_date) {
			cal_cell = $E({tag: 'td'});
		} else {
			cal_cell = $E({tag: 'td', className: 'jump-month', innerHTML: '&raquo;', onclick: function() { targ.updateDate(0,1,0) }});
		}
		cal_row.appendChild(cal_cell);
		cal_tbody.appendChild(cal_row);

		cal_row = $E({tag: 'tr', className: 'day-names'});
		for(d = 0; d < this.days.length; d++) {
			cal_cell = $E({tag: 'td', innerHTML: this.days[d]});
			cal_row.appendChild(cal_cell);
		}
		cal_tbody.appendChild(cal_row);

		cal_row = $E({tag: 'tr'});

		for (var i=0; i<beginday.getDay(); i++) {
			cal_cell = $E({tag: 'td'});
			cal_row.appendChild(cal_cell);
		}

		rowpos = i+1;

		lastday = this.selected_date.formatDate('t');

		for (var i = 1; i<=lastday; i++) {
			currentdate = new Date(this.selected_date.getFullYear(), this.selected_date.getMonth(), i);
			
			daystyle = (currentdate.valueOf() == this.form_date.valueOf() ? '-selected' : '');
			
			if (currentdate < this.min_date || currentdate > this.max_date) {
				cal_cell = $E({tag: 'td', className: 'unavailable-day', children: {tag: 'span', innerHTML: i}});
			} else {
				cal_cell = $E({
					tag: 'td', className: 'select-date'+daystyle, 
					children: {tag: 'a', href: '#', onclick: function(){ targ.selectDate(this.innerHTML); return false; }, innerHTML: i}
				});
			}
			cal_row.appendChild(cal_cell);

			if (rowpos == 7 && i < lastday) {
				cal_tbody.appendChild(cal_row);
				cal_row = $E({tag: 'tr'});
				rowpos = 0;
			}

			rowpos++;				
		}

		if (rowpos > 0) {
			for (i = rowpos; i<=7;i++ ) {
				cal_cell = $E({tag: 'td'});
				cal_row.appendChild(cal_cell);
			}
		}
		cal_tbody.appendChild(cal_row);

		cal_table.appendChild(cal_tbody);
		this.calendar_container.appendChild(cal_table);

		
	},

	selectDate: function(newdate) {
		this.selected_date.setDate(newdate);
		this.convertDateTo(this.selected_date);	
		this.hideCalendar();
		if (this.postOperation) {
            this.postOperation();
        }
	},

	updateDate: function(year, month, day) {
		if (year) {
			this.selected_date.setFullYear(this.selected_date.getFullYear() + year);
		}
		if (month) {
			this.selected_date.setMonth(this.selected_date.getMonth() + month);
		}
		if (day) {
			this.selected_date.setDate(this.selected_date.getDate() + day);
		}

		this.calendar_container.innerHTML = '';

		this.generateCalendar();


	},

	setFields: function(obj) {
		this.form = {};
		for(i in obj) {
			switch (i) {
				case 'day':
					this.form.day = [1, obj[i][0], document.getElementById(obj[i][1])];
				break;
				case 'day-month':
					this.form.daymon = [2, obj[i][0], document.getElementById(obj[i][1])];
				break;
				case 'month':
					this.form.mon = [3, obj[i][0], document.getElementById(obj[i][1])];
				break;
				case 'month-year':
					this.form.monyr = [4, obj[i][0], document.getElementById(obj[i][1])];
				break;
				case 'year':
					this.form.yr = [5, obj[i][0], document.getElementById(obj[i][1])];
				break;
				case 'day-month-year':
					this.form.daymonyr = [6, obj[i][0], document.getElementById(obj[i][1])];
				break;
				case 'year-month-day':
					this.form.yrmonday = [7, obj[i][0], document.getElementById(obj[i][1])];
				break;

			}
		}
	},

	setLimits: function(min_date, max_date) {
		this.min_date = new Date(min_date);
		this.max_date = new Date(max_date);
		this.min_date.setHours(0,0,0,0);
		this.max_date.setHours(0,0,0,0);
	},

	convertDateFrom: function() {
		var day, month, year, tmp;
		for (i in this.form) {
			var dateval = this.form[i][2].value;
			switch (i) {
				case 'day':
					day = dateval;
				break;
				case 'mon':
					month = dateval;
				break;
				case 'daymon':
					tmp = dateval.split(this.separator);
					day = tmp[0]; month = tmp[1];
				break;
				case 'monyr':
					tmp = dateval.split(this.separator);
					month = tmp[0]; year = tmp[1];
				break;
				case 'yr':
					year = dateval;
				break;
				case 'daymonyr':
					tmp = dateval.split(this.separator);
					day = tmp[0]; month = tmp[1]; year = tmp[2];
				break;
				case 'yrmonday':
					tmp = dateval.split(this.separator);
					year = tmp[0]; month = tmp[1]; day = tmp[2];
				break;
			}
		}
		if ((''+year).length == 2) { year = '20'+''+year; }
		if (isFinite(month)) {
			return new Date(year, month-1, day);
		} else {
			return new Date(month+' '+day+', '+year);
		}
	},

	convertDateTo: function(thedate) {
		var target, format, value, tmp;
		for (i in this.form) {
			target = this.form[i][2];
			format = this.form[i][1];
			value = thedate.formatDate(format);

			for (var i=0; i<target.options.length; i++ ) {
				if (target.options[i].value == value) {
					 target.options[i].selected = 'selected';
				} else if (target.options[i].selected) {
					 target.options[i].selected = '';
				}
			}
		}
	}

}