function PickerPopup(p, pos) {
	if (!p.popupable) {
		alert('PickerPopup: This object isn\'t pop-upable');
		return;
	}
	this.pos = pos || PickerPopup.BELOWFIELD;
	this.p = p;
	this.p.elInput.style.display = '';
	this.p.el.style.position = 'absolute';
	this.p.el.style.zIndex = 100;
	this.p.el.style.display = 'none';
	this.p.el.onmouseover = PickerPopup.handleMouseOver;
	this.p.el.onmouseout = PickerPopup.handleMouseOut;
	this.ponPick = this.p.onpick;
	this.p.onpick = PickerPopup.handleDatePick;

	this.elButton = document.createElement("a");
	this.elButton.href = "#";
	this.elButton.className = "pickerbutton " + this.p.popupClassName;
	this.elButton.onclick = PickerPopup.handleButtonClick;
	//this.elButton.style.background = "url(" + _DP_BUTTON_IMAGE + ") top left no-repeat;"
	
	this.p._PP_obj = this;
	this.p.elInput._PP_obj = this;

	this.open = false;

	if (this.p.elInput.nextSibling) {
		this.p.elInput.parentNode.insertBefore(this.elButton, this.p.elInput.nextSibling);
	} else {
		this.p.elInput.parentNode.appendChild(this.elButton);
	}
}

PickerPopup.BELOWBUTTON = 1;
PickerPopup.BELOWFIELD = 2;
PickerPopup.ABOVEBUTTON = 3;
PickerPopup.ABOVEFIELD = 4;

PickerPopup.handleButtonClick = function(e) {
	var obj = this.previousSibling._PP_obj;
	var e = e || window.event;
	if (obj.open) {
		obj.close();
	} else {
		obj.popup();
	}
	e.cancelBubble = true;
	if (e.stopPropagation) {
		e.stopPropagation();
	}
	return false;
};

PickerPopup.handleMouseOver = function() {
	var obj = this.nextSibling._PP_obj;
	obj.mouseOver = true;
};

PickerPopup.handleMouseOut = function() {
	var obj = this.nextSibling._PP_obj;
	obj.mouseOver = false;
};

PickerPopup.handleDocumentClick = function() {
	var obj = document._PP_obj;
	if (obj.mouseOver == false) {
		obj.close();
	}
};

PickerPopup.handleDatePick = function() {
	var obj = this._PP_obj;
	obj.close();
	if (obj.ponPick) {
		obj.ponPick();
	}
};

PickerPopup.getOffset = function(node, prop) {
    var value = 0;
    
    while (node) {
        value += node[prop];
        node = node.offsetParent;
    }
    
    return value;
};

PickerPopup.prototype.popup = function() {
	switch (this.pos) {
		case PickerPopup.BELOWBUTTON:
			this.p.el.style.left = PickerPopup.getOffset(this.elButton, "offsetLeft") + 4 + "px";
			this.p.el.style.top = PickerPopup.getOffset(this.elButton, "offsetTop") + this.elButton.offsetHeight + "px";
			break;
		case PickerPopup.BELOWFIELD:
			this.p.el.style.left = PickerPopup.getOffset(this.p.elInput, "offsetLeft") + 4 + "px";
			this.p.el.style.top = PickerPopup.getOffset(this.p.elInput, "offsetTop") + this.p.elInput.offsetHeight + "px";
			break;
	}
	this.mouseOver = false;
	document._PP_obj = this;
	document.onclick = PickerPopup.handleDocumentClick;
	this.open = true;
	this.p.el.style.display = '';
	switch (this.pos) {
		case PickerPopup.ABOVEBUTTON:
			this.p.el.style.left = PickerPopup.getOffset(this.elButton, "offsetLeft") + 4 + "px";
			this.p.el.style.top = PickerPopup.getOffset(this.elButton, "offsetTop") - this.p.el.offsetHeight + "px";
			break;
		case PickerPopup.ABOVEFIELD:
			this.p.el.style.left = PickerPopup.getOffset(this.p.elInput, "offsetLeft") + 4 + "px";
			this.p.el.style.top = PickerPopup.getOffset(this.p.elInput, "offsetTop") - this.p.el.offsetHeight + "px";
			break;
	}
};

PickerPopup.prototype.close = function() {
	document.onclick = null;
	document._PP_obj = null;
	this.open = false;
	this.p.el.style.display = 'none';
}

Date.prototype.dateEquals = function(d) {
	return d.getDay() == this.getDay() && d.getMonth() == this.getMonth() && this.getFullYear() == this.getFullYear();
};

function DatePicker(el, initialDate, format, showInput) {
	var w, d, tr, td;
	
	el = $e(el);
	this.el = document.createElement("div");
	
	this.el._DP_obj = this;

	if (!format) {
		this.format = "d.m.y";
	} else {
		this.format = format;
	}
	
	if (initialDate) {
		this.date = initialDate
	} else if (el.value) {
		this.date = DatePicker.parseDate(el.value, this.format) || new Date();
	} else {
		this.date = new Date();
	}
	this.oldDate = this.date;
	
/*	while (this.el.firstChild) {
		this.el.removeChild(this.el.firstChild);
	}*/

	this.el.className = "datePicker";
	
	this.elTable = document.createElement("table");
	this.elCal = document.createElement("tbody");
	
	tr = document.createElement("tr");
	for (d = 0; d < 7; ++d) {
		td = document.createElement("th");
		td.appendChild(document.createTextNode(this.getShortDayName(d)));
		tr.appendChild(td);
	}
	this.elCal.appendChild(tr);
	
	for (w = 0; w < 6; ++w) {
		tr = document.createElement("tr");
		for (d = 0; d < 7; ++d) {
			td = document.createElement("td");
			td.appendChild(document.createTextNode(" "));
			td.onclick = DatePicker.handleGoToDay;
			tr.appendChild(td);
		}
		this.elCal.appendChild(tr);
	}

	this.elTable.appendChild(this.elCal);
	this.el.appendChild(this.elTable);

	this.elMonDisp = document.createElement("div");
	this.elMonDisp.className = "monthDisplay";
	this.elMonDisp.appendChild(document.createTextNode(" "));
	this.el.insertBefore(this.elMonDisp, this.elTable);

	this.elPrevYear = document.createElement("div");
	this.elPrevYear.className = "previousYear";
	this.elPrevYear.onclick = /*this.elPrevYear.ondblclick = */DatePicker.handleGoPrevYear;
	this.elPrevYear.title = _DP_TOOLTIPS["prevYear"];
	this.el.insertBefore(this.elPrevYear, this.elMonDisp);

	this.elPrev = document.createElement("div");
	this.elPrev.className = "previousMonth";
	this.elPrev.onclick = DatePicker.handleGoPrev;
	this.elPrev.title = _DP_TOOLTIPS["prevMonth"];
	this.el.insertBefore(this.elPrev, this.elMonDisp);

	this.elNextYear = document.createElement("div");
	this.elNextYear.className = "nextYear";
	this.elNextYear.onclick = /*this.elNextYear.ondblclick = */DatePicker.handleGoNextYear;
	this.elNextYear.title = _DP_TOOLTIPS["nextYear"];
	this.el.insertBefore(this.elNextYear, this.elMonDisp);
	
	this.elNext = document.createElement("div");
	this.elNext.className = "nextMonth";
	this.elNext.onclick = DatePicker.handleGoNext;
	this.elNext.title = _DP_TOOLTIPS["nextMonth"];
	this.el.insertBefore(this.elNext, this.elMonDisp);
	
	this.elInput = el;
	this.elInput.parentNode.insertBefore(this.el, this.elInput);
//	this.elInput.parentNode.removeChild(this.elInput);
//	this.el.appendChild(this.elInput);
	
	this.onchange = this.elInput.onchange;
	this.onpick = null;
	
	if (!showInput) {
		this.elInput.style.display = "none";
	} else {
		this.elInput.onkeyup = DatePicker.handleInputChange;
	}
	
	this.lastRendYear = -1;
	this.lastRendMonth = -1;

	this.render(true);
}

DatePicker.prototype.popupable = true;
DatePicker.prototype.popupClassName = "datepicker";

DatePicker.handleGoPrev = function() {
	this.parentNode._DP_obj.moveMonth(-1);
};

DatePicker.handleGoNext = function() {
	this.parentNode._DP_obj.moveMonth(1);
};

DatePicker.handleGoPrevYear = function() {
	this.parentNode._DP_obj.moveYear(-1);
};

DatePicker.handleGoNextYear = function() {
	this.parentNode._DP_obj.moveYear(1);
};

DatePicker.handleGoToDay = function() {
	var obj = this.parentNode.parentNode.parentNode.parentNode._DP_obj;
	if (this._DP_otherMonth != 0) {
		obj.moveMonth(this._DP_otherMonth, true);
	}
	obj.goToDay(this._DP_day);
	obj.fireOnPick();
};

DatePicker.handleInputChange = function() {
	var obj = this.previousSibling._DP_obj;
	var d = DatePicker.parseDate(this.value, obj.format);
	if (d) {
		obj.goToDate(d);
	}
};

DatePicker.prototype.fireOnChange = function() {
	if (this.onchange) {
		this.onchange();
	}
};

DatePicker.prototype.fireOnPick = function() {
	if (this.onpick) {
		this.onpick();
	}
};

DatePicker.prototype.render = function(initial) {
	var day, weekDay, tr, td;
	var year = this.date.getFullYear();
	var month = this.date.getMonth();
	if (!initial) {
	    this.elInput.value = DatePicker.formatDate(this.date, this.format);
	}
	this.elMonDisp.firstChild.nodeValue = this.getMonthName(this.date) + " " + year;
	if (this.lastRendYear == year && this.lastRendMonth == month) {
		this.quickRender();
		return;
	}
	this.lastRendYear = year;
	this.lastRendMonth = month;
	var today = new Date();
	var todayDay = today.getDate();
	var todayMonth = today.getMonth();
	var todayYear = today.getFullYear();
	var selDay = this.date.getDate();
	var firstDayOfWeek = this.getDayOfWeek(new Date(year, month, 1));
	var numDays = this.getNumberOfDays(this.date);
	var lastNumDays = this.getNumberOfDays(new Date((month == 0) ? year - 1 : year, (month == 0) ? 11 : month - 1, 1));
	if (firstDayOfWeek > 0) {
		--month;
		if (month < 0) {
			month = 11;
			--year;
		}
	}
	tr = this.elCal.firstChild.nextSibling;
	td = tr.firstChild;
	for (state = 0, weekDay = 0, cell = 0, day = lastNumDays - firstDayOfWeek + 1; cell < 42; ++weekDay, ++day, ++cell) {
		if (state == 0 && day == lastNumDays + 1) {
			day = 1;
			state = 1;
			++month;
			if (month > 11) {
				month = 0;
				++year;
			}
		}
		if (state == 1 && day == numDays + 1) {
			day = 1;
			state = 2;
			++month;
			if (month > 11) {
				month = 0;
				++year;
			}
		}
		if (weekDay == 7) {
			weekDay = 0;
			tr = tr.nextSibling;
			td = tr.firstChild;
		}
		td.firstChild.nodeValue = day;
		td._DP_day = day;
		if (state == 0) {
		 	td.className = "otherMonth";
			td._DP_otherMonth = -1;
		} else if (state == 1) {
			td.className = "";
			if (year == todayYear && month == todayMonth && day == todayDay) {
				td.className += " today";
			}
			if (day == selDay) {
				td.className += " selected";
			}
			td._DP_otherMonth = 0;
		} else {
			td.className = "otherMonth";
			td._DP_otherMonth = 1;
		}
		td = td.nextSibling;
	}
};

DatePicker.prototype.quickRender = function() {
	var tdl = this.elCal.getElementsByTagName("td"), i, td;
	var today = new Date();
	var todayDay = today.getDate();
	var todayMonth = today.getMonth();
	var todayYear = today.getFullYear();
	var month = this.date.getMonth();
	var year = this.date.getFullYear();
	var selDay = this.date.getDate();
	for (i = 0; i < tdl.length; ++i) {
		td = tdl[i];
		if (td._DP_otherMonth == 0) {
			td.className = "";
			if (year == todayYear && month == todayMonth && td._DP_day == todayDay) {
				td.className += " today";
			}
			if (td._DP_day == selDay) {
				td.className += " selected";
			}
		}
	}
}

DatePicker.prototype.getDayOfWeek = function(date) {
	var day = date.getDay();
	return (day == 0 ? 6 : day - 1);
};

DatePicker.prototype.getNumberOfDays = function(date) {
	var year = date.getYear();
	var isLeap = ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0));
	return [31, (isLeap ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][date.getMonth()];
}

DatePicker.prototype.getMonthName = function(date) {
	return _DP_MONTH_NAMES[date.getMonth()];
};

DatePicker.prototype.getShortDayName = function(day) {
	return _DP_DAY_NAMES[day];
};

DatePicker.prototype.moveMonth = function(m, noRender) {
	var numDays;
	var day = this.date.getDate();
	var month = this.date.getMonth() + m;
	var year = this.date.getFullYear();
	
	if (month < 0) {
		--year;
		month = 11;
	}
	if (month > 11) {
		++year;
		month = 0;
	}
	numDays = this.getNumberOfDays(new Date(year, month, 1));
	if (day > numDays) {
		day = numDays;
	}
	this.goToDate(new Date(year, month, day), noRender);
};

DatePicker.prototype.moveYear = function(y, noRender) {
	var numDays;
	var day = this.date.getDate();
	var month = this.date.getMonth();
	var year = this.date.getFullYear() + y;
	
	numDays = this.getNumberOfDays(new Date(year, month, 1));
	if (day > numDays) {
		day = numDays;
	}
	this.goToDate(new Date(year, month, day), noRender);
};

DatePicker.prototype.goToDay = function(d, noRender) {
	this.goToDate(new Date(this.date.getFullYear(), this.date.getMonth(), d), noRender);
};

DatePicker.prototype.goToDate = function(d, noRender) {
	this.date = d;
	if (!noRender) {
		this.render();
	}
	if (!this.date.dateEquals(this.oldDate)) {
		this.fireOnChange();
	}
	this.oldDate = this.date;
};

DatePicker.formatDate = function(d, f) {
	var r = f;
	var day = d.getDate(), month = d.getMonth() + 1;
	r = r.replace(/d/g, day);
	r = r.replace(/D/g, (day > 9) ? day : "0" + day);
	r = r.replace(/m/g, month);
	r = r.replace(/M/g, (month > 9) ? month : "0" + month);
	r = r.replace(/y/g, d.getFullYear());
	return r;
};

DatePicker.parseDate = function(s, f) {
	var r = "", i, c, cs = "", matches, d = new Date();
	for (i = 0; i < f.length; ++i) {
		c = f.charAt(i);
		if (c == "d" || c == "m") {
			r += "(\\d{0,2})";
			cs += c;
		} else if (c == "y") {
			r += "(\\d{4})";
			cs += c;
		} else if (c == "D" || c == "M") {
			r += "(\\d{2})";
			cs += c;
		} else {
			r += "\\" + c;
		}
	}
	if (matches = new RegExp(r, "").exec(s)) {
		for (i = 0; i < matches.length; ++i) {
			switch (cs.charAt(i)) {
				case "d":
				case "D":
					d.setDate(matches[i + 1]);
					break;
				case "m":
				case "M":
					d.setMonth(parseInt(matches[i + 1]) - 1);
					break;
				case "y":
					d.setFullYear(matches[i + 1]);
					break;
			}
		}
	} else {
		return null;
	}
	return d;
};

// Copied from lutil.js

function $e(e) {
	if (typeof e == 'string') {
		return document.getElementById(e);
	} else {
		return e;
	}
}

var _DP_MONTH_NAMES = ["tammi", "helmi", "maalis", "huhti", "touko", "kesä",
    "heinä", "elo", "syys", "loka", "marras", "joulu"];
var _DP_DAY_NAMES = ["ma", "ti", "ke", "to", "pe", "la", "su"];
var _DP_TOOLTIPS = {prevYear: "Edellinen vuosi", prevMonth: "Edellinen kuukausi",
    nextYear: "Seuraava vuosi", nextMonth: "Seuraava kuukausi"};