/*
 * DatePicker
 * @author Bram Gerritsen
 * @modified by Robert (Vini vidi Fietsie Foetsie) Fokken
 * @modified by Freek Gruntjes
 * @version 1.0
 * @classDescription A date picker object. Created with the help of MooTools v1.2
 * MIT-style License.

 * see examples.html for usage

 * 01-5-2009  - BG Use Mootools.lang for date and monthnames
 * 01-5-2009  - BG Use Mootools 1.2.2 format and parse function to support date formatting
 * 11-5-2009  - BG Fixed bug with iMonthRange to draw right number of months
 * 11-5-2009  - BG Open calender in current month by default
 * 15-6-2009  - BG StartDate added
 * 16-6-2009  - BG Custom parser added
 * 16-6-2009  - BG Fixed calculation of yearRange based on monthRange
 * 13-7-2009  - RF veranderd getRemoteDayData dat active maand en active jaar wordt gebruikt. Ook day uit data service verwijderd.
 * 19-8-2009  - BG changeYear function added. restrictions added with manual yearinput
 * 19-8-2009  - BG dp_disabled style added for days which cannot be selected
 * 21-9-2009  - BG title option added
 * 09-10-2009 - BG Added yearLabel option (always show year in plaintext behind monthSelect)
 * 14-10-2009 - BG Added support for endDates
 * 14-10-2009 - BG Optimized some code
 * 14-10-2009 - BG Auto closing datepickers if you have multiple on one page
 * 16-11-2009 - RF Language file fix als deze niet aanwezig is op line 115
 * 27-11-2009 - BG Dynamicaly set maxlength of input box. to limit manual input
 * 11-12-2009 - FG add today class not overwriting other classes
 * 21-12-2009 - BG Fixed bug , Input box was cleared when you selected 31 december
 *
 */
var DatePicker = new Class(
{
	Implements: [Events, Options],

	options: {
		dayChars    : 1,
		dayNames    : ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
		daysInMonth : [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
		aMonthNames : ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
		format      : '',
		startDay    : 1, // 1 = week starts on Monday, 7 = week starts on Sunday
		yearOrder   : 'asc',
		oStartDate  : null,
		oEndDate    : null,
		sStartDate  : '',
		sEndDate    : '',
		yearStart   : null,
		yearRange   : null,
		iMonthStart	: null, //1=january - 12=december
		iMonthRange	: null,
		bOnlyFuture : false,
		bOnlyHistory: false,
		calImage    : '/imagelib/icons/calendar.gif',
		iconSep     : true, //Put selector outside input box
		showFlat    : false,
		bManualInput : false,
		sLanguage   : 'en-US',
		title       : '',
		sDataServiceURL: '',
		sDataServiceProcedure: '',
		aDataServiceParms: {},
		aDays: {},
		bSeperateYearSelect: false,
		bYearInput: false,
		bYearLabel: true,
		oDependantObject: $empty,
		onDateClick : Class.empty,
		onRemoteDataInit: Class.empty,
		onRemoteDataComplete: Class.empty,
		onCalenderComplete: Class.empty
	},

	initialize: function(vInputElement, options)
	{
		this.oInput = $(vInputElement);

		if (!this.oInput)
		{
			alert('You tried to init a new DatePicker object on a non existing input field');
			return false;
		}

		this.oDatePicker = {};
		this.bLoading = false; // timer remote data fetch complete
		this.bFireCalComplete = true;
		this.bValidDateSelected = true;
		this.sMysqlDate = '';

		//Reset Date objects
		this.oCurrentDate = new Date();
		this.oCurrentDate.clearTime();
		this.oSelectedDate = new Date();

		this.oContainer = false;
		this.oCalendar  = false;
		this.oInterval  = null;
		this.bActive    = false;

		//Overwrite default datepicker options
		this.setOptions(options);

		//Pull the rest of the options from the alt attr
		if(this.oInput.get('alt') && this.oInput.get('alt') != '')
		{
			aAltoptions = JSON.decode(this.oInput.get('alt'));
			this.setOptions(aAltoptions);
		}

		//Determine Locale to use
		if (this.options.sLanguage.contains('_'))
		{
			this.options.sLanguage = this.options.sLanguage.replace('_', '-');
		}
		// Uitzondering bijgemaakt als het EN-US is dan mogen er geen language file data worden opgehaald.
		// Omdat dit standaard geset wordt in deze calander (WAAROM>?????)
		if (!MooTools.lang.list().contains(this.options.sLanguage))
		{
			//alert("Language file for " + this.options.sLanguage + " not found, or lang not supported, using en-US");
			this.options.sLanguage = "en-US";
		}
		else
		{
			MooTools.lang.setLanguage(this.options.sLanguage);
			this.options.aMonthNames = MooTools.lang.get('Date', 'months');
			this.options.dayNames    = MooTools.lang.get('Date', 'days');
			if (this.options.format.length == 0)
			{
				this.options.format = MooTools.lang.get('Date', 'shortDate');
			}
		}

		if (this.options.format.length == 0)
		{
			this.options.format = '%d/%m/%Y';
		}

		//Determine max input length
		this.oInput.set('maxlength', this.oCurrentDate.format(this.options.format).length);

		//Direct draw datepicker to screen if input field is hidden
		if (this.oInput.type == 'hidden')
			this.options.showFlat = true;

		if (this.options.bYearInput)
		{
			this.options.bSeperateYearSelect = true;
		}

		//Copy ID to name attribute if name attribute is not set yet
		if (this.oInput.get('name') == null)
		{
			this.oInput.set('name', this.oInput.get('id'));
		}

		//Copy name to ID if ID is not set
		if (this.oInput.get('id') && this.oInput.get('id').length == 0)
			this.oInput.set('id', this.oInput.get('name'));

		//Create hidden input to contain Mysql representation of selected date. You can easily extract it out your form this way
		if (this.oInput.get('name') != null && this.oInput.get('name').test(".*\\[.*\\]")) //datepicker[edat] becomes datepicker[edat_mysql]
		{
			sMysqlInputName = this.oInput.get('name').replace(/(.*)\[(.*)\]/g, "$1[$2_mysql]");
		}
		else
		{
			sMysqlInputName = this.oInput.get('name')+'_mysql';
		}

		this.oMysqlInput = new Element('input', {'type' : 'hidden', 'id' : sMysqlInputName, 'name' : sMysqlInputName}).inject(this.oInput, 'after');

		// Format date when typed manually
		if (this.options.bManualInput)
		{
			this.oInput.addEvent('blur', function()
			{
				if (this.extractDateFromInput())
				{
					this.writeDateToInput();
				}
			}.bind(this));
		}

		//Determine startDate
		if (this.options.oStartDate != null)
		{
			this.oStartDate = this.options.oStartDate;
		}
		else if (this.options.sStartDate.length > 0)
		{
			this.oStartDate = this.parseDate(this.options.sStartDate);
		}
		else if (this.options.bOnlyFuture)
		{
			this.oStartDate = this.oCurrentDate;
		}
		else
		{
			//Backward support monthstart and yearstart
			this.oStartDate = new Date();
			if (this.options.iMonthStart != null)
			{
				this.oStartDate.setMonth(this.options.iMonthStart-1);
			}
			else
			{
				//this.oStartDate.setMonth(this.oCurrentDate.getMonth()); //Start at current month when no options are given
				this.oStartDate.setMonth(0); //Start at january when no options are given
			}
			if (this.options.yearStart != null)
			{
				this.oStartDate.setFullYear(this.options.yearStart);
			}
			else
			{
				this.oStartDate.setFullYear(this.oCurrentDate.getFullYear()); //Start with current year if no options are given
			}
			this.oStartDate.setDate(1); //Default day to 1
		}
		this.oStartDate.setHours(0);
		this.oStartDate.setMinutes(0);
		this.oStartDate.setSeconds(0);
		this.oStartDate.setMilliseconds(0);

		//Determine endDate
		if (this.options.oEndDate != null)
		{
			this.oEndDate = this.options.oEndDate;
		}
		else if (this.options.sEndDate.length > 0)
		{
			this.oEndDate = this.parseDate(this.options.sEndDate);
		}
		else if (this.options.bOnlyHistory)
		{
			this.oEndDate = this.oCurrentDate;
		}
		else
		{
			//Backward support monthrange and yearrange
			this.oEndDate = new Date(this.oStartDate.getFullYear(), this.oStartDate.getMonth(), this.oStartDate.getDate());
			if (this.options.iMonthRange > 0)
			{
				this.oEndDate.setMonth(this.oStartDate.getMonth() + this.options.iMonthRange);
			}
			else if (this.options.yearRange > 0)
			{
				this.oEndDate.setFullYear(this.oStartDate.getFullYear() + this.options.yearRange);
				this.oEndDate.setDate(this.oStartDate.getDate() - 1);
				//this.oEndDate.setMonth(this.oStartDate.getMonth() - 1);
			}
			else
			{
				this.oEndDate.setFullYear(this.oStartDate.getFullYear() + 2);
			}
		}
		this.oEndDate.setHours(0);
		this.oEndDate.setMinutes(0);
		this.oEndDate.setSeconds(0);
		this.oEndDate.setMilliseconds(0);

		//Determine default selected date
		if (this.oCurrentDate >= this.oStartDate && this.oCurrentDate <= this.oEndDate) //Check if currentDate is inside date range
		{
			this.iActiveYear  = this.oCurrentDate.getFullYear(); //Year which is selected in calender
			this.iActiveMonth = this.oCurrentDate.getMonth(); //Month which is selected in calender
		}
		else
		{
			this.iActiveYear  = this.oStartDate.getFullYear();
			this.iActiveMonth = this.oStartDate.getMonth();
		}

		/*console.log('id = ' + this.oInput.id);
		console.log('startdate = ' + this.oStartDate);
		console.log('enddate = ' + this.oEndDate);*/

		//Calculate years to draw
		var i = 0;
		this.aYears = [];
		//Year select sorted DESC
		if (this.options.yearOrder == 'desc')
		{
			for (var y = this.oEndDate.getFullYear(); y >= this.oStartDate.getFullYear(); y--)
			{
				this.aYears[i] = y;
				i++;
			}
		}
		//Year select sorted ASC
		else
		{
			for (var y = this.oStartDate.getFullYear(); y <= this.oEndDate.getFullYear(); y++)
			{
				this.aYears[i] = y;
				i++;
			}
		}

		//Calculate months to draw per Year
		this.aMonthRangePerYear = new Hash();
		this.aYears.each(function(iYear)
		{
			iMonthStart = (this.oStartDate.getFullYear() == iYear) ? this.oStartDate.getMonth() : 0;
			iMonthEnd = (this.oEndDate.getFullYear() == iYear) ? this.oEndDate.getMonth() : 11;
  		this.aMonthRangePerYear[iYear] = {'start' : iMonthStart, 'end' : iMonthEnd};
		}.bind(this));

		//Extracts date from input and fills selectedDate
		if (this.extractDateFromInput())
		{
			this.writeDateToInput(); //Overwrite input value and hidden mysql input
		}

		this.getInputCoords();

		if (this.options.showFlat)
		{
			this.create(this.oInput);
		}
		else
		{
			if (this.options.iconSep) //Add onclick handler to calendar icon
			{
				oNextSibling = this.oInput.getNext();
				if (oNextSibling && oNextSibling.hasClass('dp_calbtn')) { //Icon is al een keer toegevoegd, eerst verwijderen
					oNextSibling.dispose();
				}
				this.addIcon();
			}
			else
			{
				this.oInput.addClass('icon');
			}
			if (!this.options.bManualInput)
			{
				this.oInput.setProperty('readonly', true);
				this.oInput.setStyle('cursor', 'pointer');
				this.oInput.addEvents({
					'click': function(event) { this.create(this.oInput); }.bind(this)
				});
			}
		}
	},

	extractDateFromInput: function()
	{
		// Finds the date entered in the input box
		var sInputValue = this.oInput.get('value');
		if(sInputValue != '') //Maand is niet veranderd
		{
			this.setSelectedDate(this.parseDate(sInputValue));
			return true;
		}
		else
			return false;
	},

	/* Format the returning date value according to the selected formation */
	writeDateToInput: function()
	{
		if (this.bValidDateSelected)
		{
			sFormattedDate = this.oSelectedDate.format(this.options.format);
			if (sFormattedDate != this.oInput.get('value')) //Date changed
			{
				this.oInput.set('value', sFormattedDate);
			}
		}
		else //Date is not inside date range, or date is invalid format
		{
			this.oInput.set('value', '');
		}
	},

	setSelectedDate: function(oDate)
	{
		//console.log('setSelectedDate = '+oDate);
		if (oDate >= this.oStartDate && oDate <= this.oEndDate) //Check if range is valid in datepicker range 15-6-2009 15:14
		{
			this.bValidDateSelected = true;
			this.oSelectedDate = oDate;
			this.iActiveYear  = oDate.getFullYear();
			this.iActiveMonth = oDate.getMonth();
			this.oMysqlInput.set('value', this.oSelectedDate.format("%Y-%m-%d"));
		}
		else
		{
			this.bValidDateSelected = false;
		}

		this.writeDateToInput();
	},

	getSelectedDate: function()
	{
		return this.oSelectedDate;
	},

	addIcon: function()
	{
		var sCalImage = this.options.calImage;
		var oImage = new Element('img', {'src' : sCalImage, 'class' : 'dp_calbtn'});

		this.aCalPos.left += 20;
		this.aCalPos.top += 0;

		this.oInput.setStyle('float', 'left');
 		oImage.injectAfter(this.oInput);

 		oImage.addEvents({
			'click': function(event) { this.create(this.oInput); }.bind(this)
		});
	},

	getInputCoords: function()
	{
		this.oInputCoords = this.oInput.getCoordinates();
		iLeft = this.oInputCoords.left + this.oInputCoords.width + 1;
		iTop  = this.oInputCoords.top;
		this.aCalPos = {
			'top' : iTop,
			'left' : iLeft,
			'bottom' : (iTop + 160),
			'right' : (iLeft + 200)
		};
	},

	reposition: function()
	{
		this.getInputCoords();

		if (this.oContainer.getStyle('position') == 'absolute')
		{
			iPageBottom = window.getScrollHeight();

			if (this.aCalPos.bottom > iPageBottom) //Datepicker outside screen boundaries
			{
				this.aCalPos.top = iPageBottom - (this.oContainer.getHeight() * 2);
			}

			this.oContainer.setStyles({
				'left' : this.aCalPos.left,
				'top' : this.aCalPos.top
			});
		}

		// Hide select boxes while calendar is up
		// maybe use iFrameShim
		//if(window.ie6){
		$$('select').each(function(oSelect)
		{
			if (oSelect.getStyle('display') != 'none')
			{
				this.oSelectCoords = oSelect.getCoordinates();
				iSelectLeft = this.oSelectCoords.left;
				iSelectTop  = this.oSelectCoords.top;
				iSelectRight = this.oSelectCoords.right;
				iSelectBottom = this.oSelectCoords.bottom;

				if (
				  iSelectLeft <= this.aCalPos.right &&
				  iSelectRight >= this.aCalPos.left &&
				  iSelectTop <= this.aCalPos.bottom &&
				  iSelectBottom >= this.aCalPos.top
				) //Calendar overlaps selectbox
				{
					oSelect.addClass('dp_hide');
				}
			}
		}.bind(this));
	},


	setDependantObject: function(oObject)
	{
		this.oDependantObject = oObject;
	},

	showLoadingScreen: function()
	{
		// create the outer container
		var oLoading = new Element('div', {'class' : 'dp_loading', 'id' : 'loading_' + this.oInput.id});

		if (this.options.showFlat)
		{
			oLoading.injectAfter(this.oInput);
			oLoading.setStyle('position', 'relative');
			oLoading.innerHTML = '<span class="cal_loading_label">' + MooTools.lang.get('Date', 'loadingCalendar') + '</span>';  //; De kalender wordt geladen...
		}

		this.oLoadingScreen = oLoading;
	},

	removeLoadingScreen: function()
	{
		this.oLoadingScreen.dispose();
		this.oLoadingScreen = false;
	},

	// Remote procedure for manipulation of days in calendar
	getRemoteDayData: function()
	{
		this.options.aDataServiceParms['iMonth'] = this.iActiveMonth;
		this.options.aDataServiceParms['iYear']  = this.iActiveYear;
		this.options.aDataServiceParms['procedure'] = this.options.sDataServiceProcedure;

		var aReturnedDays = new Array();

		// Initiate dataservice
		var jSonRequest = new Request.JSON({url: this.options.sDataServiceURL,
			  async: true,
			  onFailure: function()
				{
					alert('Error in dataservice');
				},
				onSuccess: function(oJson)
				{
			 		if (oJson.error != null && oJson.error.length > 0)
					{
						alert(oJson.error);
					}
					else if (oJson.aDays)
					{
						this.options.aDays = oJson.aDays;
						$each(oJson.aDays, function (oDay,sKey)
						{
							if (typeof(this.options.aDays[oDay.iYear]) == 'undefined')
							{
								this.options.aDays[oDay.iYear] = new Array();
							}

							if (typeof(this.options.aDays[oDay.iYear][oDay.iMonth]) == 'undefined')
							{
								this.options.aDays[oDay.iYear][oDay.iMonth] = new Array();
							}

							this.options.aDays[oDay.iYear][oDay.iMonth][oDay.iDay] = oDay;
						}.bind(this));

						this.removeLoadingScreen();
						this.bLoading = false;

						// Generate Calendar
						this.makeCalendar();

						this.fireEvent('onRemoteDataComplete');
					}
				}.bind(this)
		}).send("data="+JSON.encode(this.options.aDataServiceParms) );
	},

	// create the month select box
	getMonthSelect: function()
	{
		var oMonthSelect = new Element('select', {'id':this.oInput.id + '_monthSelect'});

		if (!this.options.bSeperateYearSelect)
		{
			this.aYears.each(function(iYear, iIndex)
			{
				var oYearOption = new Element('optgroup', {'label':iYear}).inject(oMonthSelect);
				this.drawMonthOptions(oYearOption, iYear);
			}.bind(this));
		}
		else
		{
			this.drawMonthOptions(oMonthSelect, this.iActiveYear);
		}

		/* set the onchange event for the month & year select boxes */
		oMonthSelect.addEvents(
		{
			'focus': function()
			{
				this.bActive = true;
			}.bind(this),

			'change':function()
			{

				aMonthValues = oMonthSelect.value.split("_");
				this.iActiveYear  = parseInt(aMonthValues[0], 10);
				this.iActiveMonth = parseInt(aMonthValues[1], 10);
				if (this.options.bYearLabel && this.oYearLabel != null)
				{
					this.oYearLabel.set('text', this.iActiveYear);
				}

				this.remove();
				this.create();

			}.bind(this)
		});

		return oMonthSelect;
	},

	drawMonthOptions: function(oInjectInside, iYear)
	{
		iMonthStart = this.aMonthRangePerYear[iYear].start;
		iMonthEnd   = this.aMonthRangePerYear[iYear].end;
		for (var iMonth=iMonthStart; iMonth<=iMonthEnd; iMonth++)
		{
			var oMonthOption = new Element('option', {'value':iYear+'_'+iMonth, 'text':this.options.aMonthNames[iMonth]}).inject(oInjectInside);
			if (this.iActiveMonth == iMonth && this.iActiveYear == iYear)
			{
				oMonthOption.setProperty('selected', true);
			}
		}
	},

	getYearSelect: function()
	{
		if(this.options.bYearInput) //Create manual date input
		{
			this.oYearSelect = new Element('input', {
				'id':this.oInput.id + '_yearSelect',
				'type': 'text',
				'class': 'dp_yearInput',
				'maxlength': 4,
				'value': this.iActiveYear
			});

			this.oYearSelect.addEvents({
				'focus': function()
				{
					this.bActive = true;
				}.bind(this),

				'keydown': function(event)
				{
					var iYearValue = this.oYearSelect.get('value').toInt();

					//Check keys to accept as input and minimum length
					if(
						!(['0','1','2','3','4','5','6','7','8','9','up','down','left','right','backspace'].contains(event.key))
					)
					{
						event.stop();
						return;
					}
					else if (['up', 'down'].contains(event.key))
					{
						//Handle arrow keys
						switch(event.key)
						{
							case 'up':
								iYearValue++;
								break;
							case 'down':
								iYearValue--;
								break;
						}
						this.changeYear(iYearValue);
					}
					else //Manual input
					{
						//This can be implemented with new mootools version
						//this.iLastCaretPos = this.oYearSelect.getCaretPosition(); //Save caret position
					}
				}.bind(this),
				'keyup': function(event)
				{
					this.changeYear(this.oYearSelect.get('value').toInt());
				}.bind(this)
			});
		}
		else //Create year dropdown
		{
			this.oYearSelect = new Element('select', {'id':this.oInput.id + '_yearSelect'});
			this.aYears.each(function(iYear, iIndex)
			{
				var oOption = new Element('option', {'value':iYear, 'text':iYear}).inject(this.oYearSelect);
				if (this.iActiveYear == iYear)
				{
					oOption.setProperty('selected', true);
				}
			}.bind(this));

			this.oYearSelect.addEvents({
				'focus': function()
				{
					this.bActive = true;
				}.bind(this),

				'change': function()
				{
					this.changeYear(this.oYearSelect.value.toInt());
				}.bind(this)
			});
		}
		return this.oYearSelect;
	},

	changeYear: function(iNewYearValue)
	{
		if (iNewYearValue > 0 && this.iActiveYear != iNewYearValue && this.aYears.contains(iNewYearValue))
		{
			this.iActiveYear = iNewYearValue;
			this.remove();
			this.create();
			this.oYearSelect.focus();
			return true;
		}
		return false;
	},

	makeCalendar: function()
	{
		// create the outer container
		this.oContainer = new Element('div', {'class' : 'dp_container', 'id' : 'cal_' + this.oInput.id});

		if (this.options.showFlat)
		{
			this.oContainer.injectAfter(this.oInput);
			this.oContainer.addClass('flat');
			this.oContainer.setStyle('position', 'relative');
		}
		else
		{
			this.oContainer.inject(document.body);
			this.reposition();

			// create timers
			this.oContainer.addEvents({
				'mouseover' : function()
				{
					$clear(this.oInterval);
				}.bind(this),
				'mouseout' : function()
				{
					this.oInterval = function(){
						if (!this.bActive) this.remove();
					}.bind(this).delay(3000);
				}.bind(this)
			});
		}

		iYear = this.iActiveYear;

		var oDate = new Date(iYear, this.iActiveMonth, 1);

		// Leap year exeception
		this.oSelectedDate.getFullYear() % 4 == 0 ? this.options.daysInMonth[1] = 29 : this.options.daysInMonth[1] = 28;

		// set the day to first of the month
		var iDay = (1-(7+oDate.getDay()-this.options.startDay)%7);

		// Create the calendar wrapper
		this.oCalendar = new Element('div', {'class':'dp_cal'}).injectInside(this.oContainer);

		// start creating calendar
		calTable = new Element('table');
		calTableThead = new Element('thead');

		// Add title label on top of calendar
		if (this.options.title.length > 0)
		{
			calTitleRow = new Element('tr').injectInside(calTableThead);
			calTitleCell = new Element('th', {'colspan' : '7', 'class' : 'title', 'html' : this.options.title}).injectInside(calTitleRow);
		}

		// Create row for year/month togglers
		calSelRow = new Element('tr');
		calSelCell = new Element('th', {'colspan':'7'});

		oMonthSelect = this.getMonthSelect();
		oMonthSelect.injectInside(calSelCell);
		if (this.options.bSeperateYearSelect)
		{
			this.getYearSelect();
			this.oYearSelect.inject(calSelCell);

			//Create year toggler
			if (this.options.bYearInput)
			{
				var oYearSpinner = new Element('div', {
					'class' : 'dp_yearToggler'
				}).inject(this.oYearSelect, 'after');

				oYearSpinner.addEvent('mousedown', function(event)
				{
					event.stop();
					iYearValue = this.oYearSelect.get('value');
					oSpinnerCoords = oYearSpinner.getCoordinates();
					iMouseY = event.page.y - oSpinnerCoords.top;
					if (iMouseY < 9)
					{
						iYearValue++;
					}
					else
					{
						iYearValue--;
					}
					this.changeYear(iYearValue);
				}.bind(this));
			}
		}
		else if (this.options.bYearLabel)
		{
			this.oYearLabel = new Element('div', {'text' : this.iActiveYear, 'class' : 'dp_yearLabel' }).inject(oMonthSelect, 'after');
		}

		// When calender showed in flat mode don't show
		// close button
		if (!this.options.showFlat)
		{
			closeButton = new Element('a', {'class': 'btn_close'}).set('text', 'x');
			closeButton.setStyle('cursor', 'pointer');
			closeButton.inject(calSelCell);
		}

		calSelCell.injectInside(calSelRow);
		calSelRow.injectInside(calTableThead);
		calTableTbody = new Element('tbody');

		// create day names
		calDayNameRow = new Element('tr');
		for (var i = 0; i < this.options.dayNames.length; i++) {
			calDayNameCell = new Element('th');
			calDayNameCell.appendText(this.options.dayNames[(this.options.startDay+i)%7].substr(0, this.options.dayChars));
			calDayNameCell.inject(calDayNameRow);
		}
		calDayNameRow.inject(calTableTbody);

		/* create the day cells */
		while (iDay <= this.options.daysInMonth[this.iActiveMonth])
		{
			calDayRow = new Element('tr');

			for (i = 0; i < 7; i++)
			{
				oDay = null;
				sClassName = 'dp_default';
				bClickAble = false; // Is the day clickable

				if (this.options.aDays.length > 0
						&& typeof(this.options.aDays[this.iActiveYear]) != 'undefined'
						&& typeof(this.options.aDays[this.iActiveYear][this.iActiveMonth]) != 'undefined'
						&& typeof(this.options.aDays[this.iActiveYear][this.iActiveMonth][iDay]) != 'undefined'
					 )
				{
					oDay = this.options.aDays[this.iActiveYear][this.iActiveMonth][iDay];
					sClassName += " " + oDay.sClassName;
					bClickAble = oDay.bClickable;
				}
				else if (typeof(this.options.aDays.length) == 'undefined') // Geen beschikbaarheid
				{
					if (this.oStartDate != null &&
					    this.iActiveYear == this.oStartDate.getFullYear() &&
					    this.iActiveMonth == this.oStartDate.getMonth() &&
					    iDay < this.oStartDate.getDate()
					   )
					{
						bClickable = false;
						sClassName = 'dp_disabled';
					}
					else if (this.oEndDate != null &&
					    this.iActiveYear == this.oEndDate.getFullYear() &&
					    this.iActiveMonth == this.oEndDate.getMonth() &&
					    iDay > this.oEndDate.getDate()
					   )
					{
						bClickable = false;
						sClassName = 'dp_disabled';
					}
					else
					{
						bClickAble = true; // Every day clickable
					}
				}
				else // Wel beschikbaarheid maar niet voor alle dagen van het jaar
				{
					sClassName = 'cal_unavailable';
				}

				if ((iDay <= this.options.daysInMonth[this.iActiveMonth]) && (iDay > 0))
				{
					this.calDayCell = new Element('td', {
						'class': sClassName,
						'axis':iYear+'|'+(this.iActiveMonth + 1) + '|' + iDay
					});

					if (bClickAble)
					{
						this.calDayCell.addEvents(
						{
							'click': function(e)
							{
								var oItem = (e.target == null) ? e.srcElement : e.target;

								if (!this.bLoading)
								{
									ds = oItem.axis.split('|');

									this.setSelectedDate(new Date(ds[0], ds[1]-1, ds[2]));



									if (this.options.showFlat)
									{
										if (this.oSelectedCell)
										{
											this.oSelectedCell.removeClass('dp_selected');
											this.oSelectedCell.removeClass('dp_selected_wrong');
										}
										this.bValidDateSelected = true;
										oItem.addClass('dp_selected');
										this.oSelectedCell = oItem;
									}
									else
									{
										this.remove();
									}

									this.fireEvent('onDateClick', [this, this.oSelectedDate]);
								}
							}.bind(this),
							'mouseenter':function()
							{
								this.addClass('dp_roll');
							},
							'mouseleave':function()
							{
								this.removeClass('dp_roll');
							}
						});
					}

					this.calDayCell.appendText(iDay).injectInside(calDayRow);

				}
				else
				{
					this.calDayCell = new Element('td', {'class' : 'dp_empty'}).appendText(' ').injectInside(calDayRow);
				}

				if (iDay == this.oSelectedDate.getDate() && this.iActiveMonth == this.oSelectedDate.getMonth() && this.iActiveYear == this.oSelectedDate.getFullYear())
				{
					//
					// Geselecteerd datum is niet clickable!!
					//
					if (bClickAble)
					{
						this.calDayCell.addClass('dp_selected');
						this.bValidDateSelected = true;
					}
					else
					{
						this.calDayCell.addClass('dp_selected_wrong');
						this.bValidDateSelected = false;
					}

					this.oSelectedCell = this.calDayCell;
				}

				// Show today
				if (iDay == this.oCurrentDate.getDate() && this.iActiveMonth == this.oCurrentDate.getMonth() && this.iActiveYear == this.oCurrentDate.getFullYear())
				{
					this.calDayCell.addClass('dp_today');
				}

				iDay++;
			}

			calDayRow.injectInside(calTableTbody);
		}


		/* table into the calendar div */
		calTableThead.injectInside(calTable);
		calTableTbody.injectInside(calTable);
		calTable.injectInside(this.oCalendar);

		if (!this.options.showFlat)
		{
			closeButton.addEvent('click', function () {
				if (!this.options.showFlat)
					this.remove(this.oInput);
			}.bind(this));
		}
	},

	// create the calendar
	create: function()
	{
		//Hide other datepicker instances first
		$$('.dp_container').each(function(el) {
			if(!el.hasClass('flat'))
			{
				el.hide();
			}
		});

		if (this.bLoading || this.oInput.get('disabled') == 'disabled')
		{
			return false;
		}

		// Calendar without availibility
		if (this.options.sDataServiceURL == '')
		{
			this.makeCalendar();
		}
		// Calendar with availibility, makecalender is called oncomplete
		else
		{
			this.fireEvent('onRemoteDataInit');
			this.showLoadingScreen();
			this.bLoading = true;
			this.getRemoteDayData();
		}
		this.fireEvent('onCalenderComplete', [this, this.oSelectedDate]);
	},

	/* Remove the calendar from the page */
	remove: function()
	{
		$clear(this.oInterval);
		this.bActive = false;
		// Possibility that the elements where removed some other way (element.destroy for example).
		if(this.oContainer != undefined && this.oContainer != null)
		{
			this.oContainer.destroy();
		}
		this.oCalendar = false;
		this.oContainer = false;
		$$('select.dp_hide').removeClass('dp_hide');
	},

	getOptions: function()
	{
		return this.options;
	},

	parseDate: function(sDateString)
	{
		if (this.options.format == '%Y-%m-%d' || sDateString.match('^[0-9]{4}-[0-9]{2}-[0-9]{2}$')) //Use mootools date parser for Mysql format
		{
			return new Date().parse(sDateString)
		}

		//Custom dateparser
		var d = new Date();
		d.setHours(0);
		d.setMinutes(0);
		d.setSeconds(0);
		d.setMilliseconds(0);
		d.setDate(1);

		var a = {};
		var c, m;
		var iDayNumber = 0;
		for (var i = 0; i < this.options.format.length; i++) {
			c = this.options.format.substring(i, i+2);
			switch(c) {
				case '%y': r = '[0-9]{2}'; break;
				case '%Y': r = '[0-9]{4}'; break;
				case '%m': r = '0[1-9]|1[012]'; break;
				case '%n': r = '[1-9]|1[012]'; break;
				//case '%M': r = '[A-Za-z]{'+this.options.monthShort+'}'; break;
				case '%F': r = '[A-Za-z]+'; break;
				case '%d': r = '0[1-9]|[12][0-9]|3[01]'; break;
				case '%j': r = '[1-9]|[12][0-9]|3[01]'; break;
				//case '%D': r = '[A-Za-z]{'+this.options.dayShort+'}'; break;
				case '%l': r = '[A-Za-z]+'; break;
				case '%G':
				case '%H':
				case '%g':
				case '%h': r = '[0-9]{1,2}'; break;
				case '%a': r = '(am|pm)'; break;
				case '%A': r = '(AM|PM)'; break;
				case '%i':
				case '%s': r = '[012345][0-9]'; break;
				case '%U': r = '-?[0-9]+$'; break;
				default:  r = null;
			}

			if ($chk(r))
			{
				r = '(' + r + ')';

				if (i > 0)
				{
					r = '.{'+i+'}' + r;
				}
				m = sDateString.match('^'+r);
				if ($chk(m))
				{
					a[c] = m[1];
				}
				else
				{
					if (this.options.debug) alert("Fatal Error in DatePicker\n\nUnexpected format at: '"+t+"' expected format character '"+c+"' (pattern '"+r+"')");
				}
			}
		}

		for (c in a) {
			var v = a[c];
			switch(c) {
				case '%y': d.setFullYear(v < 30 ? 2000 + v.toInt() : 1900 + v.toInt()); break; // assume between 1930 - 2029
				case '%Y': d.setFullYear(v); break;
				case '%m': d.setMonth(v.toInt() - 1); break;
				//case '%F': d.setMonth(this.options.months.indexOf(v)); break;
				case '%d': iDayNumber = v; break;
				case '%G':
				case '%H': d.setHours(v.toInt()); break;
				case '%g':
				case '%h': if (a['a'] == 'pm' || a['A'] == 'PM') { d.setHours(v == 12 ? 0 : v.toInt() + 12); } else { d.setHours(v); } break;
				case '%i': d.setMinutes(v); break;
				case '%s': d.setSeconds(v); break;
				case '%U': d = new Date(v.toInt() * 1000); break;
			}
		}
		if (iDayNumber > 0)
		{
			d.setDate(iDayNumber);
		}

		return d;
	}
});