var DatePickerUtils = {
	oneDayInMs	: 24 * 3600 * 1000,
	_daysInMonth	: [31,28,31,30,31,30,31,31,30,31,30,31],

	getMonthDays: function(year, month){
		if(((0 == (year%4)) && ((0 != (year%100)) || (0 == (year%400)))) && (month == 1)){
			return 29;
		}
		return this._daysInMonth[month];
	},
	parseDate: function(dateString){
		var dateObj = DatePickerUtils.ansiDateToObject(dateString);
		if (!dateObj) {
			var relDate = parseFloat(dateString);
			dateObj = new Date();
			dateObj.setTime(dateObj.getTime() + dateString * this.oneDayInMs);
		}
		return dateObj;
	},
	dateObjectToAnsi: function(dateObj) {
		if (!dateObj) return null;
		return dateObj.getFullYear().toPaddedString(4) + '-' + (dateObj.getMonth() + 1).toPaddedString(2) + '-' + dateObj.getDate().toPaddedString(2);
	},
	ansiDateToObject: function(ansiDate) {
		var dateObj = null;
		var parsedDate = String(ansiDate).match(/^(\d+)-0*(\d+)-0*(\d+)$/);
		if (parsedDate){
			dateObj = new Date(parsedDate[1],parsedDate[2] - 1,parsedDate[3]);
		}
		return dateObj;
	},
	yearMonthToAnsiStub: function(year, month) {
		return year.toPaddedString(4)+'-'+(month+1).toPaddedString(2)+'-';
	},
	noDatesBefore: function (firstDate) {
		return new DatePickerFilter(
			function(year, month) {
				var testDate = DatePickerUtils.dateObjectToAnsi(
				DatePickerUtils.parseDate(firstDate));
				var dateFilter = new Array();
				var monthDays = DatePickerUtils.getMonthDays(year, month);
				var calDate = DatePickerUtils.yearMonthToAnsiStub(year,month);
				for (var i = 1; i <= monthDays; i++){
					dateFilter[i] = (testDate > (calDate+i.toPaddedString(2)) );
				}
				return dateFilter;
			},
			function(year, month) {
				var testDate = DatePickerUtils.dateObjectToAnsi(DatePickerUtils.parseDate(firstDate));
				var calDate = DatePickerUtils.yearMonthToAnsiStub(year,month) + DatePickerUtils.getMonthDays(year,month);
				return (testDate <= calDate);
			}
		);  
	},
	noDatesAfter: function (firstDate) {
		return new DatePickerFilter(
			function(year, month) {
				var testDate = DatePickerUtils.dateObjectToAnsi(
				DatePickerUtils.parseDate(firstDate));
				var dateFilter = new Array();
				var monthDays = DatePickerUtils.getMonthDays(year, month);
				var calDate = DatePickerUtils.yearMonthToAnsiStub(year,month);
				for (var i = 1; i <= monthDays; i++){
					dateFilter[i] = (testDate < (calDate+i.toPaddedString(2)) );
				}
				return dateFilter;
			},
			function(year, month) {
				var testDate = DatePickerUtils.dateObjectToAnsi(DatePickerUtils.parseDate(firstDate));
				var calDate = DatePickerUtils.yearMonthToAnsiStub(year,month) + '01';
				return (testDate >= calDate);
			}
		);  
	},
	noWeekends: function () {
		return new DatePickerFilter(
			function(year, month) {
				var dateFilter = new Array();
				var monthDays = DatePickerUtils.getMonthDays(year, month);
				var calDate = new Date(year,month,1);
				for (var i = 1; i <= monthDays; calDate.setFullYear(year,month,++i)){
					dateFilter[i] = ((calDate.getDay() % 6) == 0);
				}
				return dateFilter;
			},
			null
		);  
	}
};
	
var DatePickerFormatter = Class.create();
DatePickerFormatter.prototype = {
	initialize: function(format, separator) {
		if (Object.isUndefined(format)){
			format = ["yyyy", "mm", "dd"];
		}
		if (Object.isUndefined(separator)){
			separator = "-";
		}
		this._format 	= format;
		this.separator	= separator;
		this._formatYearIndex	= format.indexOf("yyyy");
		this._formatMonthIndex= format.indexOf("mm");
		this._formatDayIndex	= format.indexOf("dd");
		this._yearRegexp	= /^\d{4}$/;
		this._monthRegexp 	= /^0\d|1[012]|\d$/;
		this._dayRegexp 	= /^0\d|[12]\d|3[01]|\d$/;
	},
	match: function(str) {
		var d = str.split(this.separator);
		if (d.length < 3){
			return false;
		}
		var year = d[this._formatYearIndex].match(this._yearRegexp);
		if (year) { year = year[0] } else { return false }
		var month = d[this._formatMonthIndex].match(this._monthRegexp);
		if (month) { month = month[0] } else { return false }
		var day = d[this._formatDayIndex].match(this._dayRegexp);
		if (day) { day = day[0] } else { return false }
		return [year, month, day];
	},
	currentDate: function() {
		var d = new Date;
		return this.dateToString(d.getFullYear(), d.getMonth() + 1, d.getDate());
	},
	dateToString: function(year, month, day, separator) {
		if (Object.isUndefined(separator)){
			separator = this.separator;
		}
		var a = [0, 0, 0];
		a[this._formatYearIndex]	= year;
		a[this._formatMonthIndex] 	= month.toPaddedString(2);
		a[this._formatDayIndex] 	= day.toPaddedString(2);
		return a.join(separator);
	}
}; 
	
var DatePickerFilter = Class.create();
DatePickerFilter.prototype = {
	initialize : function (dateFilterFunction, monthFilterFunction) {
		if (dateFilterFunction) this.badDates = dateFilterFunction;
		if (monthFilterFunction) this.validMonthP = monthFilterFunction;
	},
	badDates : null,
	validMonthP : null,
	append : function (nextFilter) {
		if (!this.badDates){
			this.badDates = nextFilter.badDates;
		}else if (nextFilter.badDates){
			var firstBadDates = this.badDates;
			this.badDates = function (year, month) {
				var results1 = firstBadDates(year,month);
				var results2 = nextFilter.badDates(year,month);
				for (var i = 0; i < results1.length; i++){
					results1[i] = results1[i] || results2[i];
				}
				return results1;
			};
		}
		if (!this.validMonthP){
			this.validMonthP = nextFilter.validMonthP;
		}else if (nextFilter.validMonthP){
			var firstValidMonthP = this.validMonthP;
			this.validMonthP = function (year, month) {
				return firstValidMonthP(year,month) && nextFilter.validMonthP(year,month);
			};
		}
		return this;
	}
};
	
var DatePicker	= Class.create();
DatePicker.prototype	= {
	Version	: '1.0.0',
	_relative	: null,
	_div		: null,
	_zindex	: 1,
	_keepFieldEmpty: false,
	_dateFormat	: null,
	_language	: 'nl',
	_language_month	: $H({
	'fr' : [ 'Janvier', 'F&#233;vrier', 'Mars', 'Avril', 'Mai', 'Juin', 
	'Juillet', 'Aout', 'Septembre', 'Octobre', 'Novembre',
	'D&#233;cembre' ],
	'en' : [ 'January', 'February', 'March', 'April', 'May', 'June', 'July',
	'August', 'September', 'October', 'November', 'December' ],
	'sp' : [ 'Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio',
	'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre' ],
	'it' : [ 'Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno',
	'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre',
	'Dicembre' ],
	'de' : [ 'Januar', 'Februar', 'M&#228;rz', 'April', 'Mai', 'Juni', 'Juli',
	'August', 'September', 'Oktober', 'November', 'Dezember' ],
	'pt' : [ 'Janeiro', 'Fevereiro', 'Mar&#231;o', 'Abril', 'Maio', 'Junho',
	'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro' ],
	'hu' : [ 'Janu&#225;r', 'Febru&#225;r', 'M&#225;rcius', '&#193;prilis', 
	'M&#225;jus', 'J&#250;nius', 'J&#250;lius', 'Augusztus',
	'Szeptember', 'Okt&#243;ber', 'November', 'December' ],
	'lt' : [ 'Sausis', 'Vasaris', 'Kovas', 'Balandis', 'Gegu&#382;&#279;',
	'Bir&#382;elis', 'Liepa', 'Rugj&#363;tis', 'Rus&#279;jis',
	'Spalis', 'Lapkritis', 'Gruodis' ],
	'nl' : [ 'januari', 'februari', 'maart', 'april', 'mei', 'juni', 'juli',
	'augustus', 'september', 'oktober', 'november', 'december' ],
	'dk' : [ 'Januar', 'Februar', 'Marts', 'April', 'Maj', 'Juni', 'Juli',
	'August', 'September', 'Oktober', 'November', 'December' ],
	'no' : [ 'Januar', 'Februar', 'Mars', 'April', 'Mai', 'Juni', 'Juli',
	'August', 'September', 'Oktober', 'November', 'Desember' ],
	'lv' : [ 'Janv&#257;ris', 'Febru&#257;ris', 'Marts', 'Apr&#299;lis',
	'Maijs', 'J&#363;nijs', 'J&#363;lijs', 'Augusts', 'Septembris',
	'Oktobris', 'Novembris', 'Decemberis' ],
	'ja' : [ '1&#26376;', '2&#26376;', '3&#26376;', '4&#26376;', '5&#26376;',
	'6&#26376;', '7&#26376;', '8&#26376;', '9&#26376;',
	'10&#26376;', '11&#26376;', '12&#26376;' ],
	'fi' : [ 'Tammikuu', 'Helmikuu', 'Maaliskuu', 'Huhtikuu', 'Toukokuu',
	'Kes&#228;kuu', 'Hein&#228;kuu', 'Elokuu', 'Syyskuu', 'Lokakuu',
	'Marraskuu', 'Joulukuu' ],
	'ro' : [ 'Ianuarie', 'Februarie', 'Martie', 'Aprilie', 'Mai', 'Junie',
	'Julie', 'August', 'Septembrie', 'Octombrie', 'Noiembrie',
	'Decembrie' ],
	'zh' : [ '1&#32;&#26376;', '2&#32;&#26376;', '3&#32;&#26376;', 
	'4&#32;&#26376;', '5&#32;&#26376;', '6&#32;&#26376;',
	'7&#32;&#26376;', '8&#32;&#26376;', '9&#32;&#26376;',
	'10&#26376;', '11&#26376;', '12&#26376;'],
	'sv' : [ 'Januari', 'Februari', 'Mars', 'April', 'Maj', 'Juni', 'Juli',
	'Augusti', 'September', 'Oktober', 'November', 'December' ]
	}),
	_language_day	: $H({
	'fr'	: [ 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam', 'Dim' ],
	'en'	: [ 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun' ],
	'sp'	: [ 'Lun', 'Mar', 'Mie', 'Jue', 'Vie', 'S&#224;b', 'Dom' ],
	'it'	: [ 'Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab', 'Dom' ],
	'de'	: [ 'Mon', 'Die', 'Mit', 'Don', 'Fre', 'Sam', 'Son' ],
	'pt'	: [ 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'S&#225;', 'Dom' ],
	'hu'	: [ 'H&#233;', 'Ke', 'Sze', 'Cs&#252;', 'P&#233;', 'Szo', 'Vas' ],
	'lt'  : [ 'Pir', 'Ant', 'Tre', 'Ket', 'Pen', '&Scaron;e&scaron;', 'Sek' ],
	'nl'	: [ 'ma', 'di', 'wo', 'do', 'vr', 'za', 'zo' ],
	'dk'	: [ 'Man', 'Tir', 'Ons', 'Tor', 'Fre', 'L&#248;r', 'S&#248;n' ],
	'no'	: [ 'Man', 'Tir', 'Ons', 'Tor', 'Fre', 'L&#248;r', 'Sun' ],
	'lv'	: [ 'P', 'O', 'T', 'C', 'Pk', 'S', 'Sv' ],
	'ja'	: [ '&#26376;', '&#28779;', '&#27700;', '&#26408;', '&#37329;', 
	'&#22303;', '&#26085;' ],
	'fi'	: [ 'Ma', 'Ti', 'Ke', 'To', 'Pe', 'La', 'Su' ],
	'ro'	: [ 'Lun', 'Mar', 'Mie', 'Joi', 'Vin', 'Sam', 'Dum' ],
	'zh'	: [ '&#21608;&#19968;', '&#21608;&#20108;', '&#21608;&#19977;', 
	'&#21608;&#22235;', '&#21608;&#20116;', '&#21608;&#20845;', 
	'&#21608;&#26085;' ],
	'sv'	: [ 'M&#229;n', 'Tis', 'Ons', 'Tor', 'Fre', 'L&#246;r', 
	'S&#246;n' ]
	}),
	_language_close	: $H({
	'fr'	: 'fermer',
	'en'	: 'close',
	'sp'	: 'cierre',
	'it'	: 'fine',
	'de'	: 'schliessen',
	'pt'	: 'fim',
	'hu'	: 'bez&#225;r',
	'lt'  : 'udaryti',
	'nl'	: 'sluiten',
	'dk'	: 'luk',
	'no'	: 'lukk',
	'lv'	: 'aizv&#275;rt',
	'ja'	: '&#38281;&#12376;&#12427;',
	'fi'	: 'sulje',
	'ro'	: 'inchide',
	'zh'	: '&#20851;&#32;&#38381',
	'sv'	: 'st&#228;ng'
	}),
	_language_date_format : $H({
	'en': [ ["mm", "dd", "yyyy"], "/" ],
	'lt': [ ["yyyy", "mm", "dd"], "-" ],
	'fr': [ ["dd", "mm", "yyyy"], "/" ],
	'sp': [ ["dd", "mm", "yyyy"], "/" ],
	'it': [ ["dd", "mm", "yyyy"], "/" ],
	'de': [ ["dd", "mm", "yyyy"], "/" ],
	'pt': [ ["dd", "mm", "yyyy"], "/" ],
	'hu': [ ["dd", "mm", "yyyy"], "/" ],
	'nl': [ ["dd", "mm", "yyyy"], "-" ],
	'dk': [ ["dd", "mm", "yyyy"], "/" ],
	'no': [ ["dd", "mm", "yyyy"], "/" ],
	'lv': [ ["dd", "mm", "yyyy"], "/" ],
	'ja': [ ["yyyy", "mm", "dd"], "-" ],
	'fi': [ ["dd", "mm", "yyyy"], "/" ],
	'ro': [ ["dd", "mm", "yyyy"], "/" ],
	'zh': [ ["yyyy", "mm", "dd"], "-" ],
	'sv': [ ["dd", "mm", "yyyy"], "/" ]
	}),
	_todayDate		: new Date(),
	_currentDate		: null,
	_clickCallback		: Prototype.emptyFunction,
	_cellCallback		: Prototype.emptyFunction,
	_dateFilter : new DatePickerFilter(),
	_id_datepicker		: null,
	_topOffset		: 30,
	_leftOffset		: 0,
	_isPositionned		: false,
	_relativePosition 	: true,
	_setPositionTop 	: 0,
	_setPositionLeft	: 0,
	_bodyAppend		: false,
	_showEffect		: "appear", 
	_showDuration		: 0.2,
	_enableShowEffect 	: true,
	_closeEffect		: "fade", 
	_closeEffectDuration	: 0.2,
	_enableCloseEffect 	: true,
	_closeTimer		: null,
	_enableCloseOnBlur	: false,
	_afterClose	: Prototype.emptyFunction,
	getMonthLocale	: function ( month ){
		return	this._language_month.get(this._language)[month];
	},
	getLocaleClose	: function () {
		return	this._language_close.get(this._language);
	},
	recalculateDate: function(newDate){
		this._currentDate = newDate;
		if (! this._df.match(this._currentDate)) {
			this._currentDate = this._df.currentDate();
			if (!this._keepFieldEmpty){
				$(this._relative).value = this._currentDate;
			}
		}
		var a_date = this._df.match(this._currentDate);
		this._currentYear 	= Number(a_date[0]);
		this._currentMonth	= Number(a_date[1]) - 1;
		this._currentDay	= Number(a_date[2]);
	},
	_initCurrentDate : function () {
		if (!this._dateFormat){
			this._dateFormat = this._language_date_format.get(this._language);
		}
		this._df = new DatePickerFormatter(this._dateFormat[0], this._dateFormat[1]);
		this.recalculateDate($F(this._relative));
	},
	initialize	: function ( h_p ) {
		this._relative= h_p["relative"];
		if (h_p["language"]){
			this._language = h_p["language"];
		}
		this._zindex	= ( h_p["zindex"] ) ? parseInt(Number(h_p["zindex"])) : 1;
		if (!Object.isUndefined(h_p["keepFieldEmpty"])){
			this._keepFieldEmpty	= h_p["keepFieldEmpty"];
		}
		if (Object.isFunction(h_p["clickCallback"])) {
			this._clickCallback	= h_p["clickCallback"];
		}
		if (!Object.isUndefined(h_p["leftOffset"])){
			this._leftOffset	= parseInt(h_p["leftOffset"]);
		}
		if (!Object.isUndefined(h_p["topOffset"])){
			this._topOffset	= parseInt(h_p["topOffset"]);
		}
		if (!Object.isUndefined(h_p["relativePosition"])){
			this._relativePosition = h_p["relativePosition"];
		}
		if (!Object.isUndefined(h_p["showEffect"])){
			this._showEffect 	= h_p["showEffect"];
		}
		if (!Object.isUndefined(h_p["enableShowEffect"])){
			this._enableShowEffect	= h_p["enableShowEffect"];
		}
		if (!Object.isUndefined(h_p["showDuration"])){
			this._showDuration 	= h_p["showDuration"];
		}
		if (!Object.isUndefined(h_p["closeEffect"])){
			this._closeEffect 	= h_p["closeEffect"];
		}
		if (!Object.isUndefined(h_p["enableCloseEffect"])){
			this._enableCloseEffect	= h_p["enableCloseEffect"];
		}
		if (!Object.isUndefined(h_p["closeEffectDuration"])){
			this._closeEffectDuration = h_p["closeEffectDuration"];
		}
		if (Object.isFunction(h_p["afterClose"])){
			this._afterClose	= h_p["afterClose"];
		}
		if (!Object.isUndefined(h_p["externalControl"])){
			this._externalControl= h_p["externalControl"];
		}
		if (!Object.isUndefined(h_p["dateFormat"])){
			this._dateFormat	= h_p["dateFormat"];
		}
		if (Object.isFunction(h_p["cellCallback"])){
			this._cellCallback	= h_p["cellCallback"];
		}
		this._setPositionTop	= ( h_p["setPositionTop"] ) ? 
		parseInt(Number(h_p["setPositionTop"])) : 0;
		this._setPositionLeft	= ( h_p["setPositionLeft"] ) ? 
		parseInt(Number(h_p["setPositionLeft"])) : 0;
		if (!Object.isUndefined(h_p["enableCloseOnBlur"]) && h_p["enableCloseOnBlur"]){
			this._enableCloseOnBlur	= true;
		}
		if (!Object.isUndefined(h_p["dateFilter"]) && h_p["dateFilter"]){
			this._dateFilter = h_p["dateFilter"];
		}
		if (!Object.isUndefined(h_p["disablePastDate"]) && h_p["disablePastDate"]){
			this._dateFilter.append(DatePickerUtils.noDatesBefore(0));
		}else if (!Object.isUndefined(h_p["disableFutureDate"]) && !h_p["disableFutureDate"]){
			this._dateFilter.append(DatePickerUtils.noDatesAfter(0));
		}
		this._id_datepicker		= 'datepicker-'+this._relative;
		this._id_datepicker_prev	= this._id_datepicker+'-prev';
		this._id_datepicker_next	= this._id_datepicker+'-next';
		this._id_datepicker_hdr	= this._id_datepicker+'-header';
		this._id_datepicker_ftr	= this._id_datepicker+'-footer';
		this._div = new Element('div', {id: this._id_datepicker, className: 'datepicker', style: 'display: none; z-index:'+this._zindex });
		this._div.innerHTML = '<table><thead><tr><th width="10px" id="'+this._id_datepicker_prev+'" style="cursor: pointer;">&nbsp;&lt;&lt;&nbsp;</th><th id="'+this._id_datepicker_hdr+'" colspan="5"></th><th width="10px" id="'+this._id_datepicker_next+'" style="cursor: pointer;">&nbsp;&gt;&gt;&nbsp;</th></tr></thead><tbody id="'+this._id_datepicker+'-tbody"></tbody><tfoot><td colspan="7" id="'+this._id_datepicker_ftr+'"></td></tfoot></table>';
		Event.observe(this._relative, 'click', this.click.bindAsEventListener(this), false);
		document.observe('dom:loaded', this.load.bindAsEventListener(this), false);
		if ( this._enableCloseOnBlur ) {
			Event.observe(this._relative, 'blur', function(e){this._closeTimer = this.close.bind(this).delay(1);}.bindAsEventListener(this));
			Event.observe(this._div, 'click', function(e){if (this._closeTimer){window.clearTimeout(this._closeTimer); this._closeTimer = null;}});
		}
	},
	load: function () {
		if (this._externalControl) {
			Event.observe(this._externalControl, 'click', this.click.bindAsEventListener(this), false);
		}
		if (this._relativeAppend) {
			if ($(this._relative).parentNode) {
				this._div.innerHTML = this._wrap_in_iframe(this._div.innerHTML);
				$(this._relative).parentNode.appendChild( this._div );
			}
		} else {
			var body	= document.getElementsByTagName("body").item(0);
			if (body) {
				this._div.innerHTML = this._wrap_in_iframe(this._div.innerHTML);
				body.appendChild(this._div);
			}
			if ( this._relativePosition ) {
				var a_pos = Element.cumulativeOffset($(this._relative));
				this.setPosition(a_pos[1], a_pos[0]);
			} else {
				if (this._setPositionTop || this._setPositionLeft){
					this.setPosition(this._setPositionTop, this._setPositionLeft);
				}
			}
		}
		this._initCurrentDate();
		$(this._id_datepicker_ftr).innerHTML = this.getLocaleClose();
		Event.observe($(this._id_datepicker_prev), 'click', this.prevMonth.bindAsEventListener(this), false);
		Event.observe($(this._id_datepicker_next), 'click', this.nextMonth.bindAsEventListener(this), false);
		Event.observe($(this._id_datepicker_ftr), 'click', this.close.bindAsEventListener(this), false);
	},
	_wrap_in_iframe	: function ( content ) {
		return	( Prototype.Browser.IE ) ? "<div style='height:167px;width:185px;background-color:white;align:left'><iframe width='100%' height='100%' marginwidth='0' marginheight='0' frameborder='0' src='about:blank' style='filter:alpha(Opacity=50);'></iframe><div style='position:absolute;background-color:white;top:2px;left:2px;width:180px'>" + content + "</div></div>" : content;
	},
	visible	: function () {
		return	$(this._id_datepicker).visible();
	},
	click: function () {
		if ( $(this._id_datepicker) == null ) this.load();
		if (!this._isPositionned && this._relativePosition) {
			var a_lt = Element.positionedOffset($(this._relative));
			$(this._id_datepicker).setStyle({'left': Number(a_lt[0]+this._leftOffset)+'px', 'top': Number(a_lt[1]+this._topOffset)+'px'});
			this._isPositionned	= true;
		}
		if (!this.visible()) {
			this._initCurrentDate();
			this._redrawCalendar();
		}
		if (this._clickCallback() !== Prototype.emptyFunction){
			eval(this._clickCallback());
			this._redrawCalendar();
		}
		if ( this._enableShowEffect ) {
			new Effect.toggle(this._id_datepicker, 
			this._showEffect, { duration: this._showDuration });
		} else {
			$(this._id_datepicker).show();
		}
	},
	close: function () {
		if ( this._enableCloseEffect ) {
			switch(this._closeEffect) {
				case 'puff': 		new Effect.Puff(this._id_datepicker, {duration : this._closeEffectDuration });
					break;
				case 'blindUp': 	new Effect.BlindUp(this._id_datepicker, {duration : this._closeEffectDuration });
					break;
				case 'dropOut': 	new Effect.DropOut(this._id_datepicker, {duration : this._closeEffectDuration }); 
					break;
				case 'switchOff': 	new Effect.SwitchOff(this._id_datepicker, {duration : this._closeEffectDuration }); 
					break;
				case 'squish': 		new Effect.Squish(this._id_datepicker, {duration : this._closeEffectDuration });
					break;
				case 'fold': 		new Effect.Fold(this._id_datepicker, {duration : this._closeEffectDuration });
					break;
				case 'shrink': 		new Effect.Shrink(this._id_datepicker, {duration : this._closeEffectDuration });
					break;
				default: 			new Effect.Fade(this._id_datepicker, {duration : this._closeEffectDuration });
					break;
			};
		} else {
			$(this._id_datepicker).hide();
		}
		eval(this._afterClose());
	},
	setDateFormat	: function ( format, separator ) {
		if (Object.isUndefined(format)){
			format	= this._dateFormat[0];
		}
		if (Object.isUndefined(separator)){
			separator	= this._dateFormat[1];
		}
		this._dateFormat	= [ format, separator ];
	},
	setPosition	: function ( t, l ) {
		var h_pos	= { 'top' : '0px', 'left' : '0px' };
		if (!Object.isUndefined(t)){
			h_pos['top']	= Number(t)+this._topOffset+'px';
		}
		if (!Object.isUndefined(l)){
			h_pos['left']= Number(l)+this._leftOffset+'px';
		}
		$(this._id_datepicker).setStyle(h_pos);
		this._isPositionned	= true;
	},
	_buildCalendar		: function () {
		var _self	= this;
		var tbody	= $(this._id_datepicker+'-tbody');
		try {
			while ( tbody.hasChildNodes() )
			tbody.removeChild(tbody.childNodes[0]);
		} catch ( e ) {};
		var trDay	= new Element('tr');
		this._language_day.get(this._language).each(function(item){var td = new Element('td'); td.innerHTML = item; td.className = 'wday'; trDay.appendChild( td );});
		tbody.appendChild(trDay);
		var a_d	= [[ 0, 0, 0, 0, 0, 0, 0 ],[ 0, 0, 0, 0, 0, 0, 0 ],[ 0, 0, 0, 0, 0, 0, 0 ],[ 0, 0, 0, 0, 0, 0, 0 ],[ 0, 0, 0, 0, 0, 0, 0 ],[ 0, 0, 0, 0, 0, 0, 0 ]];
		var currentMonth	= this._currentMonth;
		var currentYear	= this._currentYear;
		var d = new Date(currentYear, currentMonth, 1, 12);
		var startIndex	= (d.getDay() + 6) % 7;
		var nbDaysInMonth	= DatePickerUtils.getMonthDays(currentYear, currentMonth);
		var daysIndex		= 1;
		var badDates = (this._dateFilter.badDates) ? this._dateFilter.badDates(currentYear, currentMonth) : [];
		for ( var j = startIndex; j < 7; j++ ){
			a_d[0][j]	= { 
				d : daysIndex
				,m : currentMonth
				,y : currentYear 
				,b : badDates[daysIndex]
			};
			daysIndex++;
		}
		var a_prevMY	= this._prevMonthYear();
		var nbDaysInMonthPrev	= DatePickerUtils.getMonthDays(a_prevMY[1], a_prevMY[0]);
		for ( var j = 0; j < startIndex; j++ ) {
			a_d[0][j]	= { 
				d : Number(nbDaysInMonthPrev - startIndex + j + 1) 
				,m : Number(a_prevMY[0])
				,y : a_prevMY[1]
				,c : 'outbound'
				,b : true
			};
		}
		var switchNextMonth	= false;
		for ( var i = 1; i < 6; i++ ) {
			for ( var j = 0; j < 7; j++ ) {
				a_d[i][j]	= { 
					d : daysIndex
					,m : currentMonth
					,y : currentYear
					,c : ( switchNextMonth )
					? 'outbound' : (((daysIndex == this._todayDate.getDate()) && (currentMonth  == this._todayDate.getMonth()) && (currentYear == this._todayDate.getFullYear())) ? 'today' : null)
					,b : switchNextMonth || badDates[daysIndex]
				};
				daysIndex++;
				if (daysIndex > nbDaysInMonth ) {
					daysIndex	= 1;
					switchNextMonth = true;
					if (this._currentMonth + 1 > 11 ) {
						currentMonth = 0;
						currentYear += 1;
					} else {
						currentMonth += 1;
					}
				}
			}
		}
		for ( var i = 0; i < 6; i++ ) {
			var tr	= new Element('tr');
			for ( var j = 0; j < 7; j++ ) {
				var h_ij = a_d[i][j];
				var td	= new Element('td');
				var id	= $A([
					this._relative,
					this._df.dateToString(h_ij["y"], h_ij["m"]+1, h_ij["d"], '-')
					]).join('-');
				td.setAttribute('id', id);
				if (h_ij["c"]){
					td.className	= h_ij["c"];
				}
				this._bindCellOnClick( td, h_ij["b"], h_ij["c"] );
				td.innerHTML= h_ij["d"];
				tr.appendChild( td );
			}
			tbody.appendChild( tr );
		}
		return	tbody;
	},
	_bindCellOnClick	: function ( td, badDateP, cellClass ) {
		if ( badDateP ) {
			td.className= ( cellClass ) ? 'nclick_' + cellClass : 'nclick';
		} else {
			var _self	= this;
			td.onclick	= function () { 
				$(_self._relative).value = String($(this).readAttribute('id')).replace(_self._relative+'-','').replace(/-/g, _self._df.separator);
				if (_self._cellCallback){
					_self._cellCallback(this);
				}
				_self.close(); 
			};
		}
	},
	_nextMonthYear	: function () {
		var c_mon	= this._currentMonth;
		var c_year	= this._currentYear;
		if (c_mon + 1 > 11) {
			c_mon	= 0;
			c_year	+= 1;
		} else {
			c_mon	+= 1;
		}
		return	[ c_mon, c_year ];
	},
	nextMonth	: function () {
		this._maybeRedrawMonth(this._nextMonthYear());
	},
	_prevMonthYear	: function () {
		var c_mon	= this._currentMonth;
		var c_year	= this._currentYear;
		if (c_mon - 1 < 0) {
			c_mon	= 11;
			c_year	-= 1;
		} else {
			c_mon	-= 1;
		}
		return	[ c_mon, c_year ];
	},
	prevMonth	: function () {
		this._maybeRedrawMonth(this._prevMonthYear());
	},
	_maybeRedrawMonth : function(a_new) {
		var _newMon = a_new[0];
		var _newYear = a_new[1];
		if (!this._dateFilter.validMonthP || this._dateFilter.validMonthP(_newYear, _newMon)) {
			this._currentMonth	= _newMon;
			this._currentYear 	= _newYear;
			this._redrawCalendar();
		}
	},
	_redrawCalendar	: function () {
		this._setLocaleHdr(); this._buildCalendar();
	},
	_setLocaleHdr	: function () {
		var a_next	= this._nextMonthYear();
		$(this._id_datepicker_next).setAttribute('title', this.getMonthLocale(a_next[0])+' '+a_next[1]);
		var a_prev	= this._prevMonthYear();
		$(this._id_datepicker_prev).setAttribute('title', this.getMonthLocale(a_prev[0])+' '+a_prev[1]);
		$(this._id_datepicker_hdr).update('&nbsp;&nbsp;&nbsp;'+this.getMonthLocale(this._currentMonth)+'&nbsp;'+this._currentYear+'&nbsp;&nbsp;&nbsp;');
	}
};
