/**
 * DatePicker widget using Prototype and Scriptaculous.
 * (c) 2007 Mathieu Jondet <mathieu@eulerian.com>
 * Eulerian Technologies
 *
 * DatePicker is freely distributable under the same terms as Prototype.
 *
 */

/**
 * DatePickerFormatter class for matching and stringifying dates.
 *
 * By Arturas Slajus <x11@arturaz.net>.
 */
var DatePickerFormatter = Class.create();
DatePickerFormatter.prototype =
{	
    /**
     * Create a DatePickerFormatter.
     *
     * format: specify a format by passing 3 value array consisting of
     *   "yyyy", "mm", "dd". Default: ["yyyy", "mm", "dd"].
     *
     * separator: string for splitting the values. Default: "-".
     *
     * Use it like this:
     *   var df = new DatePickerFormatter(["dd", "mm", "yyyy"], "/");
     *   df.current_date();
     *   df.match("7/7/2007");
     */
    initialize: function(format, separator)
    {	
        if (Object.isUndefined(format))
        	format = ["yyyy", "mm", "dd"];
        if (Object.isUndefined(separator))
        	separator = "-";

        this._format 	= format;
        this.separator	= separator;
                
        this._format_year_index	= format.indexOf("yyyy");
        this._format_month_index= format.indexOf("mm");
        this._format_day_index	= format.indexOf("dd");
                
        this._year_regexp	= /^\d{4}$/;
        this._month_regexp 	= /^0\d|1[012]|\d$/;
        this._day_regexp 	= /^0\d|[12]\d|3[01]|\d$/;
    },
    
    /**
     * Match a string against date format.
     * Returns: [year, month, day]
     */
    match: function(str)
    {	
        var d = str.split(this.separator);
        
        if (d.length < 3)
        	return false;
        
        var year = d[this._format_year_index].match(this._year_regexp);
        
        if (year)
        {	year = year[0];
        }
        else
        { 	return false;
        }
        
        var month = d[this._format_month_index].match(this._month_regexp);
        
        if (month)
        {	month = month[0];
        }
        else
        {	return false;
        }
        
        var day = d[this._format_day_index].match(this._day_regexp);
        
        if (day)
        {	day = day[0];
        }
        else
        {	return false;
        }
        
        return [year, month, day];
    },
    
    /**
     * Return current date according to format.
     */
    current_date: function()
    {	var d = new Date;
        
    	return this.date_to_string(d.getFullYear(), d.getMonth() + 1, d.getDate() );
    },
    
    /**
     * Return a stringified date according to format.
     */
    date_to_string: function(year, month, day, separator)
    {	
        if (Object.isUndefined(separator))
        	separator = this.separator;

        var a = [0, 0, 0];
        
        a[this._format_year_index]	= year;
        a[this._format_month_index] 	= month.toPaddedString(2);
        a[this._format_day_index] 	= day.toPaddedString(2);
        
        return a.join(separator);
    }
}; 


/**
 * DatePicker
 */

var DatePicker	= Class.create();

DatePicker.prototype =
{	Version	: '0.9.4',
	_relative	: null,
	_div		: null,
	_zindex	: 1,
	_keepFieldEmpty: false,
	_daysInMonth	: [31,28,31,30,31,30,31,31,30,31,30,31],
	_dateFormat	: [ ["dd", "mm", "yyyy"], "/" ],
	
	/* language */
	_language	: 'fr',
	
	_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'	: [ 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So' ],
			 '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'
			}),

	/* date manipulation */
	_todayDate		: new Date(),
	_current_date		: null,
	_clickCallback		: Prototype.emptyFunction,
	_cellCallback		: Prototype.emptyFunction,
	_id_datepicker		: null,
	_disablePastDate	: false,
	_disableFutureDate	: true,
	// added by HM: show current date if not a date is set
	_showToday 			: true,
	_oneDayInMs			: 24 * 3600 * 1000,
 
	/* positionning */
	_topOffset			: 30,
	_leftOffset			: 0,
	_isPositionned		: false,
	_relativePosition 	: true,
	_setPositionTop 	: 0,
	_setPositionLeft	: 0,
	_bodyAppend			: false,

	/* Effects Adjustment */
	_showEffect		: "appear", 
	_showDuration		: 1,
	_enableShowEffect 	: true,
	_closeEffect		: "fade", // see function "close"
	_closeEffectDuration: 0.3,
	_enableCloseEffect 	: true,
	_closeTimer		: null,
	_enableCloseOnBlur	: false,
	/* afterClose : called when the close function is executed */
	_afterClose	: Prototype.emptyFunction,
	
	/* return the name of current month in appropriate language */
	getMonthLocale	: function ( month )
	{	return	this._language_month.get(this._language)[month];
	},
	
	getLocaleClose	: function ()
	{	return this._language_close.get(this._language);
	},
 
	_initCurrentDate : function ()
	{	/* Create the DateFormatter */
		this._df = new DatePickerFormatter(this._dateFormat[0], this._dateFormat[1]);
		
		/* check if value in field is proper, if not set to today */
		this._current_date = $F(this._relative);
		
		if (! this._df.match(this._current_date))
		{	this._current_date = this._df.current_date();
   
			/* set the field value ? */
			if (!this._keepFieldEmpty)
				$(this._relative).value = this._current_date;
		};
  
		var a_date = this._df.match(this._current_date);  
		this._current_year 	= Number(a_date[0]);
		this._current_mon	= Number(a_date[1]) - 1;
		this._current_day	= Number(a_date[2]);
  
		// ADDED by: mail@jens-zastrow.de to set the "actual selected day" not the "current day".
		if (this._showToday)
		{	this._todayDate = new Date(this._current_year, this._current_mon, this._current_day);
		}
	},
 
	// init
	initialize	: function ( h_p )
	{	/* arguments */
		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["disablePastDate"]) && h_p["disablePastDate"])
			this._disablePastDate	= true;
  
		if (!Object.isUndefined(h_p["disableFutureDate"]) && !h_p["disableFutureDate"])
			this._disableFutureDate	= false;
  
  		if (Object.isUndefined(h_p["showToday"]))
  		{	this._showToday = true;  		
  		}
  			
  
  		this._id_datepicker	 = 'datepicker-' + this._relative;
  		
  		this._id_datepicker_prev = this._id_datepicker + '-prev';
  		this._id_datepicker_prevYear = this._id_datepicker + '-prevYear';
  		
  		this._id_datepicker_next = this._id_datepicker + '-next';
  		this._id_datepicker_nextYear = this._id_datepicker + '-nextYear';
  		
  		this._id_datepicker_hdr = this._id_datepicker + '-header';
  		this._id_datepicker_ftr = this._id_datepicker + '-footer';

  		/* build up calendar html */
  		this._div = new Element('div'
  							, {	id : this._id_datepicker
  								, className : 'datepicker'
  								, style : 'display: none; z-index:'+this._zindex
  							});
  
  		this._div.innerHTML = '<table>'
  								/////// HEADER
  								+ '<thead><tr>'
  								// last year
  								+ '<th id="' + this._id_datepicker_prevYear + '" style="cursor: pointer;">&lt;&lt;</th>'
  								// last month
  								+ '<th id="' + this._id_datepicker_prev + '" style="cursor: pointer;">&lt;</th>'
  								// ???
  								+ '<th id="' + this._id_datepicker_hdr + '" colspan="3"></th>'
  								// next month
  								+ '<th id="' + this._id_datepicker_next + '" style="cursor: pointer;">&gt;</th>'
  								// next year
  								+ '<th id="' + this._id_datepicker_nextYear + '" style="cursor: pointer;">&gt;&gt;</th>'
  								// end header
  								+ '</tr></thead>'
  								
  								// the actual calendar
  								+ '<tbody id="' + this._id_datepicker + '-tbody"></tbody>'
  								
  								// the footer (close)
  								+ '<tfoot><td colspan="7" id="' + this._id_datepicker_ftr + '"></td></tfoot>'
  								+ '</table>'
  								;
  		
  		// finally declare the event listener on input field
  		Event.observe(this._relative
  					, 'click'
  					, this.click.bindAsEventListener(this)
  					, false);
  
  		// need to append on body when doc is loaded for IE
  		document.observe('dom:loaded'
  					, this.load.bindAsEventListener(this)
  					, false);
  		
  		// automatically close when blur event is triggered
  		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; 
  								} 
  							}
  						);
  		}
	}, // init
 
	// onload
	load : function ()
	{	// if externalControl defined set the observer on it
		if (this._externalControl)
		{	Event.observe(this._externalControl
						, 'click'
						, this.click.bindAsEventListener(this)
						, false);
		}
		
		// append to page
		if (this._relativeAppend)
		{	
			// append to parent node
			if ($(this._relative).parentNode)
			{	this._div.innerHTML = this._wrap_in_iframe(this._div.innerHTML);
				$(this._relative).parentNode.appendChild( this._div );
			}
		}
		// append to body
		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);
			}
		}

		// init the date in field if needed
		this._initCurrentDate();

		// set the close locale content
		$(this._id_datepicker_ftr).innerHTML = this.getLocaleClose();
  
		// declare the observers for UI control
		// next/last month
		Event.observe($(this._id_datepicker_prev)
						, 'click'
						, this.prevMonth.bindAsEventListener(this)
						, false);
		Event.observe($(this._id_datepicker_next),
						'click'
						, this.nextMonth.bindAsEventListener(this)
						, false);
		// current day ??
		Event.observe($(this._id_datepicker_ftr)
						, 'click'
						, this.close.bindAsEventListener(this)
						, false);
		// next/last year
		Event.observe($(this._id_datepicker_nextYear),
						'click'
						, this.nextYear.bindAsEventListener(this)
						, false);
		Event.observe($(this._id_datepicker_prevYear),
						'click'
						, this.prevYear.bindAsEventListener(this)
						, false);
	}, // end load
	
	// hack for buggy form elements layering in IE
	_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;
	},

	// calendar is visible ?
	visible	: function ()
	{	return $(this._id_datepicker).visible();
	},
	
	// onclick
	click : function ()
	{	// init the datepicker if it doesn't exists
		if ( $(this._id_datepicker) == null )
			this.load();
  
		if (! this._isPositionned && this._relativePosition)
		{	// position the datepicker relatively to element
			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();
		}
		
		// eval the clickCallback function
		eval(this._clickCallback());
		
		// Effect toggle to fade-in - fade-out the datepicker
		if ( this._enableShowEffect )
		{	new Effect.toggle(
					this._id_datepicker
					, this._showEffect
					, { duration: this._showDuration }
				);
		}
		else
		{	$(this._id_datepicker).show();
		}
	}, // end onclick

	// close calendar
	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());
	}, // close
	
	// setDateFormat
	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	: set the position of the datepicker.
	setPosition	: function ( top, left )
	{	var h_pos = { 'top' : '0px', 'left' : '0px' };
	
		if (!Object.isUndefined(top))
			h_pos['top'] = Number(top) + this._topOffset + 'px';
  
		if (!Object.isUndefined(left))
			h_pos['left'] = Number(left) + this._leftOffset + 'px';
  
		$(this._id_datepicker).setStyle(h_pos);
		
		this._isPositionned	= true;
	},
	
	// get the number of days for given year and month
	_getMonthDays : function ( year, month )
	{	if (((0 == (year % 4)) && ( (0 != (year % 100)) || (0 == (year % 400)))) && (month == 1))
			return 29;
	
		return this._daysInMonth[month];
	},

	// draw the days array for current date
	_buildCalendar : function ()
	{	var _self = this;
		var tbody = $(this._id_datepicker + '-tbody');
  
		try
		{	while ( tbody.hasChildNodes() )
				tbody.removeChild(tbody.childNodes[0]);
		}
		catch ( e ) {};
  
		// generate day headers
		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 );
  
		// generate the content of days
		// days matrix 
		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 ]
				  ];
  
		// set date at beginning of month to display
		var d = new Date(this._current_year, this._current_mon, 1, 12);
  
		// start the day list on monday
		var startIndex = ( !d.getDay() ) ? 6 : d.getDay() - 1;
		var nbDaysInMonth = this._getMonthDays( this._current_year, this._current_mon);
		var daysIndex = 1;
		
		for ( var j = startIndex; j < 7; j++ )
		{	a_d[0][j] = { d : daysIndex
						 , m : this._current_mon
						 , y : this._current_year
						 // commented by HM: wouldn't be hard to write it in a human readable from by using a variable before setting this never ending construct 
						 // ADDED by: mail@jens-zastrow.de to whoe the "actual selected day" in the first calendar line too.
						 , c : ( switchNextMonth ) ? 
								 'outbound'
								 : ( ((daysIndex == this._todayDate.getDate())
										 			&& (this._current_mon  == this._todayDate.getMonth()) && (this._current_year == this._todayDate.getFullYear()))
										? 'today' : null
									)
						};
		
			daysIndex++;
		}
		
		var a_prevMY = this._prevMonthYear();
		var nbDaysInMonthPrev = this._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'     
						};
		}
		
		var switchNextMonth	= false;
		var currentMonth = this._current_mon;
		var currentYear	= this._current_year;
		
		for ( var i = 1; i < 6; i++ )
		{	for ( var j = 0; j < 7; j++ )
			{	a_d[i][j] = { d : daysIndex
							 , m : currentMonth
							 , y : currentYear
							// commented by HM: wouldn't be hard to write it in a human readable from by using a variable before setting this never ending construct
							 , c : ( switchNextMonth ) ? 
									 'outbound' 
									 : ( ((daysIndex == this._todayDate.getDate()) 
											 && (this._current_mon  == this._todayDate.getMonth()) && (this._current_year == this._todayDate.getFullYear())
										 ) ? 'today' : null
									 	)
							};
				daysIndex++;
    
				// if at the end of the month : reset counter
				if (daysIndex > nbDaysInMonth )
				{	daysIndex = 1;
					switchNextMonth = true;
				
					if (this._current_mon + 1 > 11 )
					{	currentMonth = 0;
						currentYear += 1;
					}
					else
					{	currentMonth += 1;
					}
				}
			}
		}
		
		// generate days for current date
		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');
				
				// id is : datepicker-day-mon-year or depending on language other way
				// don't forget to add 1 on month for proper formatting
    
				var id	= $A([ this._relative
				      	       , this._df.date_to_string(h_ij["y"], h_ij["m"] + 1, h_ij["d"], '-')
				      	       ]
				      	     ).join('-');
				
				// set id and classname for cell if exists
				td.setAttribute('id', id);
    
				if (h_ij["c"])
					td.className = h_ij["c"];
    
				// onclick : rebuild date value from id of current cell
				var _curDate = new Date();
    
				_curDate.setFullYear(h_ij["y"], h_ij["m"], h_ij["d"]);
    
				if ( this._disablePastDate || this._disableFutureDate )
				{	
					if ( this._disablePastDate )
					{	var _res = ( _curDate >= this._todayDate ) ? true : false;
      
						this._bindCellOnClick( td, true, _res, h_ij["c"] );
					}
					
					if ( this._disableFutureDate )
					{	var _res = ( this._todayDate.getTime() + this._oneDayInMs > _curDate.getTime() ) ? true : false;
      
						this._bindCellOnClick( td, true, _res,  h_ij["c"] );
					}
				}
				else
				{	this._bindCellOnClick( td, false );
				}
				
				td.innerHTML = h_ij["d"];
				tr.appendChild( td );
			}
		
			tbody.appendChild( tr );
		}
		
		return tbody;
	}, // _buildCalendar
	
	// bind the cell onclick depending on status.
	_bindCellOnClick : function ( td, wcompare, compareresult, h_ij_c )
	{	var doBind = false;
  
		if ( wcompare )
		{	if ( compareresult )
			{	doBind	= true;
			}
			else
			{	td.className = ( h_ij_c ) ? 'nclick_outbound' : 'nclick';
			}
		}
		else
		{	doBind = true;
		}
		
		if ( doBind )
		{	var _self = this;
   
			td.onclick	= function ()
						{	$(_self._relative).value = String($(this).readAttribute('id') )
															 .replace(_self._relative+'-','')
															 .replace(/-/g, _self._df.separator);
			    
						// if there is a cellCallback defined call it and pass it the cell */
						if (_self._cellCallback)
							_self._cellCallback(this);
						
						_self.close(); 
						};
		}
	}, // _bindCellOnClick
 
	// redraw the calendar content for next month.

	_nextMonthYear	: function ()
	{	var c_mon = this._current_mon;
		var c_year = this._current_year;
		
		if (c_mon + 1 > 11)
		{   c_mon = 0;
			c_year	+= 1;
		}
		else
		{	c_mon	+= 1;
		}
  
		return [ c_mon, c_year ];
	},
	
	nextMonth : function ()
	{	var a_next = this._nextMonthYear();
		var _nextMon	= a_next[0];
		var _nextYear	= a_next[1];
		var _curDate	= new Date();
		
		_curDate.setFullYear(_nextYear, _nextMon, 1);
		
		var _res = ( this._todayDate.getTime() + this._oneDayInMs > _curDate.getTime() ) ? true : false;
  
		if ( this._disableFutureDate && !_res )
			return;
  
		this._current_mon = _nextMon;
		this._current_year = _nextYear;
  
		this._redrawCalendar();
	},
 
	// redraw the calendar content for previous month.
	_prevMonthYear : function ()
	{	var c_mon = this._current_mon;
		var c_year = this._current_year;
		
		if (c_mon - 1 < 0)
		{	c_mon = 11;
			c_year -= 1;
		}
		else
		{	c_mon -= 1;
		}
  
		return [ c_mon, c_year ];
	},
	
	prevMonth : function ()
	{	var a_prev = this._prevMonthYear();
		var _prevMon = a_prev[0];
		var _prevYear = a_prev[1];
		var _curDate = new Date();
		
		_curDate.setFullYear(_prevYear, _prevMon, 1);
		var _res = ( _curDate >= this._todayDate ) ? true : false;
  
		if ( this._disablePastDate && !_res )
			return;
  
		this._current_mon = _prevMon;
		this._current_year = _prevYear;
  
		this._redrawCalendar();
	},
 
	nextYear : function ()
	{	this._current_year += 1;
		this._redrawCalendar();
	},
	
	prevYear : function ()
	{	this._current_year -= 1;
		this._redrawCalendar();
	},
	
	_redrawCalendar	: function ()
	{	this._setLocaleHdr();
		this._buildCalendar();
	},
 
	_setLocaleHdr : function ()
	{	// next link
		var a_next= this._nextMonthYear();
		$(this._id_datepicker_next).setAttribute('title', this.getMonthLocale(a_next[0]) + ' '+ a_next[1]);
		
		// prev link
		var a_prev = this._prevMonthYear();
		$(this._id_datepicker_prev).setAttribute('title', this.getMonthLocale(a_prev[0]) + ' ' + a_prev[1]);
		
		// next/ last year
		$(this._id_datepicker_nextYear).setAttribute('title', this._current_year + 1);
		$(this._id_datepicker_prevYear).setAttribute('title', this._current_year - 1);
  
		// header
		$(this._id_datepicker_hdr)
			.update(this.getMonthLocale(this._current_mon)
					+ '&nbsp;'
					+ this._current_year);
	}
};
