// (c) 2008 renouille at choobs dot org

function Calendar(obj, min_year, min_month, min_day, max_year, max_month, max_day) {
	var me = this;
	if (!max_day) {
		var now = new Date();
		this._year = this._today_year = now.getFullYear();
		this._month = this._today_month = now.getMonth();
		this._day = this._today_day = now.getDate();
	} else {
		this._year = this._today_year = max_year;
		this._month = this._today_month = max_month - 1;
		this._day = this._today_day = max_day;
	}
	min_month--;


	this._calendar = ["TABLE",{"class":"calendar"},["THEAD",["TR",["TH",["IMG",{"width":"13","height":"12","alt":"[prev]","src":"/lokiwoe/img/leftarrow.gif"}]],["TH",{"class":"header","colspan":"4"},["DIV",["SPAN","-"]," ",["SPAN","-"]]],["TH",["IMG",{"width":"13","height":"12","alt":"[next]","src":"/lokiwoe/img/rightarrow.gif"}]],["TH",{"class":"closebutton"},["IMG",{"width":"13","height":"13","alt":"[close]","src":"/lokiwoe/img/closebutton.gif"}]]],["TR",{"class":"border"},["TH","Sun"],["TH","Mon"],["TH","Tue"],["TH","Wed"],["TH","Thu"],["TH","Fri"],["TH","Sat"]]],["TBODY",["TR",["TD"],["TD"],["TD"],["TD"],["TD"],["TD"],["TD"]],["TR",["TD"],["TD"],["TD"],["TD"],["TD"],["TD"],["TD"]],["TR",["TD"],["TD"],["TD"],["TD"],["TD"],["TD"],["TD"]],["TR",["TD"],["TD"],["TD"],["TD"],["TD"],["TD"],["TD"]],["TR",["TD"],["TD"],["TD"],["TD"],["TD"],["TD"],["TD"]],["TR",["TD"],["TD"],["TD"],["TD"],["TD"],["TD"],["TD"]]]].parseJsonML(null);
	this._months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];

///////////////////////////////////////////////////////////////////////////////

	this._getDaysInMonth = function(year, month) {
		var result = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
		if ((month == 1) && ((year % 4) === 0) && (((year % 400) === 0) || ((year % 100) !== 0))) {
			return (result + 1);
		} else {
			return result;
		}
	};

	this._getMonthName = function(month) {
		return this._months[month];
	};

	this._getMonthFromName = function(monthname) {
		for (var i = 0; i < this._months.length; i++) {
			if (this._months[i] === monthname) { return i; }
		}
		return -1;
	};

	this._checkrange = function() {
		this._calendar.rows[0].cells[0].firstChild.style.display =
			(this._year <= min_year && this._month <= min_month) ? 'none' : 'inline';
		this._calendar.rows[0].cells[2].firstChild.style.display =
			(this._year >= this._today_year && this._month >= this._today_month) ? 'none' : 'inline';
	};

	this._setup = function() {
		var now = new Date();
		now.setDate(1);
		now.setFullYear(this._year);
		now.setMonth(this._month);
		var start = now.getDay();
		var finish = start + this._getDaysInMonth(this._year, this._month);
		var ll = this._getDaysInMonth(this._year, (this._month + 11) % 12); // year doesn't matter here
		var d, e = this._calendar.tBodies[0], f, i;
		this._calendar.rows[0].cells[1].firstChild.firstChild.firstChild.nodeValue = this._getMonthName(this._month);
		this._calendar.rows[0].cells[1].firstChild.firstChild.nextSibling.nextSibling.firstChild.nodeValue = this._year;
		this._calendar.rows[0].cells[1].firstChild.lastChild.previousSibling.style.display = 'none';	// month selection
		this._calendar.rows[0].cells[1].firstChild.lastChild.style.display = 'none';	// year selection
		for (i = 0; i < 42; i++) {
			f = e.rows[Math.floor(i / 7)].cells[i % 7];
			if (i >= start && i < finish) {
				f.firstChild.nodeValue = d = i - start + 1;
				if ((d > this._today_day && this._year == this._today_year && this._month == this._today_month) ||
						(d < min_day && this._year == min_year && this._month == min_month)) {
					f.className = 'forbidden';
				} else {
					f.className = '';
					if (d == this._today_day && this._year == this._today_year && this._month == this._today_month) {
						f.className = 'today';
					}
					if (d == this._selected_day && this._year == this._selected_year && this._month == this._selected_month) {
						f.className += ' selected';
					}
				}
			} else {
				f.firstChild.nodeValue = (i >= finish) ? (i - finish + 1) : (ll - start + i + 1);
				f.className = 'oob';
			}
		}
	};

	this.toString = function() {
		var result = this._year.toString() + '-';
		if (this._month < 9) { result += '0'; }
		result += ((this._month + 1) + '-');
		if (this._day < 10) { result += '0'; }
		return (result + this._day);
	};

	this.show = function() {
		var ymd = obj.value.match(/^([0-9]{4})-([0-9]{2})-([0-9]{2})$/);
		this._selected_year = this._selected_month = this._selected_day = -1;
		if (ymd) {
			this._year = this._selected_year = parseInt(ymd[1], 10);
			this._month = this._selected_month = parseInt(ymd[2], 10) - 1;
			this._day = this._selected_day = parseInt(ymd[3], 10);
		}
		if (!ymd || this._year < min_year ||
				(this._year == min_year && (this._month < min_month || (this._month == min_month && this._day < min_day))) ||
			this._year > this._today_year ||
				(this._year == this._today_year && (this._month > this._today_month || (this._month == this._today_month && this._day > this._today_day))))
		{
			this._year = this._today_year;
			this._month = this._today_month;
			this._day = this._today_day;
		}
		this._checkrange();
		this._setup();
		this._calendar.style.display = '';
	};

	this.hide = function() {
		this._calendar.style.display = 'none';
	};

	this.showing = function() {
		return (this._calendar.style.display !== 'none');
	};

	this.cleanup = function() {
		for (var y = 0; y < 6; y++) {
			for (var x = 0; x < 7; x++) {
				this._calendar.tBodies[0].rows[y].cells[x].onclick = null;
			}
		}
		this._calendar.rows[0].cells[0].firstChild.onclick = null;
		this._calendar.rows[0].cells[1].firstChild.firstChild.onclick = null;
		this._calendar.rows[0].cells[1].firstChild.firstChild.nextSibling.nextSibling.onclick = null;
		this._calendar.rows[0].cells[1].firstChild.lastChild.previousSibling.onclick = null;
		this._calendar.rows[0].cells[1].firstChild.lastChild.onclick = null;
		this._calendar.rows[0].cells[2].firstChild.onclick = null;
		this._calendar.rows[0].cells[3].firstChild.onclick = null;
	};

///////////////////////////////////////////////////////////////////////////////

	var e = this._calendar.tBodies[0];
	var y, x;
	for (y = 0; y < e.rows.length; y++) {
		for (x = 0; x < e.rows[y].cells.length; x++) {
			e.rows[y].cells[x].appendChild(document.createTextNode(''));
			e.rows[y].cells[x].onclick = function() {
				if (this.className.match(/\boob\b|\bforbidden\b/)) { return; }
				me._day = this.firstChild.nodeValue;
				obj.value = me.toString();
				me.hide();
			};
		}
	}

	e = createElement('ul');
	for (y = 0; y <= 11; y++) {
		x = createElement('li');
		x.appendChild(document.createTextNode(this._getMonthName(y)));
		e.appendChild(x);
	}
	this._calendar.rows[0].cells[1].firstChild.appendChild(e);

	e = createElement('ul');
	for (y = min_year; y <= this._today_year; y++) {
		x = createElement('li');
		x.appendChild(document.createTextNode(y));
		e.appendChild(x);
	}
	this._calendar.rows[0].cells[1].firstChild.appendChild(e);

// select month
	this._calendar.rows[0].cells[1].firstChild.firstChild.onclick = function() {
		var e = this.parentNode.lastChild.previousSibling;
		if (e.style.display === 'block') { return; }
		e.nextSibling.style.display = 'none';
		e.style.left = e.parentNode.firstChild.offsetLeft - 4 + 'px';
		e.style.top = e.parentNode.firstChild.offsetHeight + 3 + 'px';
		var f = e.getElementsByTagName('li');
		for (var i = 0; i < f.length; i++) {
			if ((me._year === min_year && i < min_month) || (me._year === me._today_year && i > me._today_month)) {
				f[i].className = 'disabled';
			} else if (i === me._month) {
				f[i].className = 'selected';
			} else {
				f[i].className = '';
			}
		}
		e.style.display = 'block';
	};

// selected month
	this._calendar.rows[0].cells[1].firstChild.lastChild.previousSibling.onclick = function(e) {
		if (!e) { var e = window.event; }
		var clicked = (e.target) ? e.target : e.srcElement;
		if (clicked.nodeType === 3) { clicked = clicked.parentNode; }
		if (clicked.nodeName.toLowerCase() !== 'li' || clicked.className.match(/\bdisabled\b/)) { return; }
		me._month = me._getMonthFromName(clicked.firstChild.nodeValue);
		me._checkrange();
		me._setup();
	};

// select year
	this._calendar.rows[0].cells[1].firstChild.firstChild.nextSibling.nextSibling.onclick = function() {
		var e = this.parentNode.lastChild;
		if (e.style.display === 'block') { return; }
		e.previousSibling.style.display = 'none';
		e.style.left = e.parentNode.firstChild.nextSibling.nextSibling.offsetLeft - 4 + 'px';
		e.style.top = e.parentNode.firstChild.nextSibling.nextSibling.offsetHeight + 3 + 'px';
		var f = e.getElementsByTagName('li');
		for (var i = 0; i < f.length; i++) {
			f[i].className = (i === me._year - min_year) ? 'selected' : '';
		}
		e.style.display = 'block';
	};

// selected year
	this._calendar.rows[0].cells[1].firstChild.lastChild.onclick = function(e) {
		if (!e) { var e = window.event; }
		var clicked = (e.target) ? e.target : e.srcElement;
		if (clicked.nodeType === 3) { clicked = clicked.parentNode; }
		if (clicked.nodeName.toLowerCase() !== 'li') { return; }
		me._year = parseInt(clicked.firstChild.nodeValue, 10);
		if (me._year === min_year && me._month < min_month) {
			me._month = min_month;
		} else if (me._year === me._today_year && me._month > me._today_month) {
			me._month = me._today_month;
		}
		me._checkrange();
		me._setup();
	};

// previous month
	this._calendar.rows[0].cells[0].firstChild.onclick = function() {
		if (--me._month < 0) {
			me._month = 11;
			me._year--;
		}
		me._checkrange();
		me._setup();
	};

// next month
	this._calendar.rows[0].cells[2].firstChild.onclick = function() {
		if (++me._month > 11) {
			me._month = 0;
			me._year++;
		}
		me._checkrange();
		me._setup();
	};

// close window
	this._calendar.rows[0].cells[3].firstChild.onclick = function() {
		me.hide();
	};

///////////////////////////////////////////////////////////////////////////////

	this.hide();
	this._calendar.style.left = (obj.parentNode.offsetWidth - 210) + 'px';
	this._calendar.style.top = obj.offsetHeight + 3 + 'px';
	obj.parentNode.insertBefore(this._calendar, obj.nextSibling);
}

