var CalendarPopup = new Class({
//	use the some other mootools classes
	Implements: [Options,Events],
//	make sure to catch the following options server-sided as well!
	options: {
		format:"%d %b %Y | %H:%M",		// set the format according mootools datetime formatting
		type:'day',
		firstDayOfWeek:1,				// set the first day of the week (monday = 1)
		rows:{'year':3,'quarter':2,'month':4,'week':8,'day':5,'hour':4,'minute':6,'second':10,'milisecond':10},
		cols:{'year':3,'quarter':2,'month':3,'week':7,'day':7,'hour':6,'minute':10,'second':6,'milisecond':10},
		tdFormats:{'year':'%Y','month':'%b','day':'%d','hour':'%H','minute':'%M'},
		sequence:['year','month','day','hour','minute','second'],
		minDate:'01 jan 0001',			// minimum selectable date
		maxDate:'31 dec 9999',			// maximum selectable date
		minTime:'00:00',				// minimum selectable time of the day
		maxTime:'23:59',				// maximum selectable time of the day
		selectWeekends:true,			// boolean to be able to select datetimes in the weekend
		displayWeekNumbers:true,		// boolean if the rows for day selection should show the ISO weeknumber
		displayDayNames:true,			// boolean if table header shows the names of the days
		errorMessage:'ongeldige datum'	// displayed error message for unselectable datetimes
	},
//	set the array to store the selected time
	select:[],
//	the constructor
	initialize: function(input, options){
		this.setOptions(options);
	//	make sure all formatting will be parsed as output and input
		Date.defineParser(this.options.format);

	//	define which DateTime types should be available
		this.select['year']=this.options.format.contains('Y') || this.options.format.contains('%y') || this.options.format.contains('%x') || this.options.format.contains('%c');
		this.select['month']=this.options.format.contains('m') || this.options.format.contains('%b') || this.options.format.contains('%B') || this.options.format.contains('%j') || this.options.format.contains('%x') || this.options.format.contains('%c');
		this.select['week']=this.options.format.contains('%U');
		this.select['day']=this.options.format.contains('d') || this.options.format.contains('%a') || this.options.format.contains('%A') || this.options.format.contains('%j') || this.options.format.contains('%w') || this.options.format.contains('%o') || this.options.format.contains('%x') || this.options.format.contains('%c');
		this.select['hour']=this.options.format.contains('%H') || this.options.format.contains('%I') || this.options.format.contains('%p') || this.options.format.contains('%T') || this.options.format.contains('%Z') || this.options.format.contains('%c');
		this.select['minute']=this.options.format.contains('%M') || this.options.format.contains('%X') || this.options.format.contains('%p') || this.options.format.contains('%T') || this.options.format.contains('%Z') || this.options.format.contains('%c');
		this.select['second']=this.options.format.contains('%S') || this.options.format.contains('%X') || this.options.format.contains('%c');
		this.select['miliSecond']=this.options.format.contains('%ms');
	//	define the starting DateTime type and the minimum and maximum dates and times
		this.options.type = this.selectMinute?'minute':(this.selectMiliSecond?'milisecond':(this.selectDay?'day':this.options.type));
		this.options.type = this.select['day']?'day':(this.select['hour']?'hour':this.options.type);
//alert('day: '+this.select['day']+' hour: '+this.select['hour']+' minute: '+this.select['minute']+' second: '+this.select['second']);
	//	create the date object and set other variables
		this.today = new Date();
		this.minTime = new Date();
		this.maxTime = new Date();
		this.datetime = new Date();
		if($(input).value) this.datetime.parse($(input).value);
		if(!this.dtsId) this.dtsId = "DateTimeSelector"+this.today.getTime();
	//	add the events to the input
		if($(input)) this.inputs = $H({start: $(input)});
		this.inputs.each(function(input) {
			this.drawDateTimeSelector(input);
			input.addEvents({
				'focus':this.show.bind(this),
				'click':this.show.bind(this),
				'keydown':function(e){
					if(e.key == 'tab') this.hide();
				}.bind(this)
			});
			this.container.addEvent('click',function(e){this.clickContainer(e,input);}.bind(this));
		},this);
	//	hide the calendar when clicked outside the input box and calendar element
		$(document.body).addEvent('click',this.hide.bind(this));
	},

	show: function(e){
		e.stop();
		this.container.reveal();
		return this;
	},

	hide: function(e){
		this.container.dissolve();
		return this;
	},

	toggle: function(){
		this.container.toggle();
		return this;
	},

	clickContainer: function(e,input) {
	//	stop the other click events from bubbling up (body.click hides the container ...)
		e.stop();
	//	handle all the click events on the container
		if(e.target.hasClass('inactive')){
			return;
		}else if(e.target.hasClass('next')){
			this.datetime.increment(this.options.sequence[Math.max(0,this.options.sequence.indexOf(this.options.type)-1)], 1);
		}else if(e.target.hasClass('prev')){
			this.datetime.increment(this.options.sequence[Math.max(0,this.options.sequence.indexOf(this.options.type)-1)],-1);
		}else if(this.select[e.target.get('class')]){
			this.options.type = e.target.get('class');
		}else if(e.target.get('datetime') && e.target.hasClass('DT'+this.options.type)){
			this.datetime.setTime(e.target.get('datetime'));
			if(this.select[this.options.sequence[this.options.sequence.indexOf(this.options.type)+1]]){
				this.options.type = this.options.sequence[this.options.sequence.indexOf(this.options.type)+1];
			}else{
				input.set('value',this.datetime.format(this.options.format));
				this.hide();
			}
		}else if(e.target.get('datetime')){
			this.datetime.setTime(e.target.get('datetime'));
			input.set('value',this.datetime.format(this.options.format));
			this.hide();
		}else {
			return this.drawError();
		}
// 2009 02 25 toegevoegd om direct de datum aan te passen wanneer er bijvoorbeeld van maand of jaar gewisseld wordt
input.set('value',this.datetime.format(this.options.format));
		return this.drawDateTimeSelector();
	},

	drawDateTimeSelector: function(input){
	//	set the datetime, and set the correct start value
		datetime = new Date(this.datetime);
		if(this.options.type=='year'){
			datetime.set('year',datetime.format('%Y')-4);
		}else if(this.options.type=='month'){
			datetime.set('month',0);
		}else if(this.options.type=='day'){
			datetime.set('date',1);
			datetime.decrement('day',datetime.decrement('day',this.options.firstDayOfWeek).getDay()-this.options.firstDayOfWeek);
		}else{
			datetime.set(this.options.type+'s',0);
		}
	//	draw the actual container div, make sure the z-index 1 higher that the item that triggers the selector
		if(!this.container) {
			this.container = new Element('div',{
				'id': this.options.dtsId || '',
				'class':'DateTimeSelector'
			}).setStyles({'display':'none'}).inject(input,'after');
			if(input.getStyle('z-index')!='auto'){this.container.setStyle('z-index',input.getStyle('z-index').toInt()+1);}
		}
	//	draw the table, start with the header navigation
		var table = new Element('table');
// 2010 04 28 aangepast om via de verschillende datum velden direct naar het keuze scherm te switchen ipv steeds 1 "grotere" datum omhoog
		var html = '';
	//	split the format in order to create a link per data item
		var a = this.options.format.split(/([^a-z\d%])/i);
		a.each(function(e,i){
			switch(e){
				case'%d':case'%a':case'%A':	html += '<a href="#" class="day">'+this.datetime.format(e)+'</a>';break;
				case'%m':case'%b':case'%B':	html += '<a href="#" class="month">'+this.datetime.format(e)+'</a>';break;
				case'%Y':case'%y':				html += '<a href="#" class="year">'+this.datetime.format(e)+'</a>';break;
				case'%H':						html += '<a href="#" class="hour">'+this.datetime.format(e)+'</a>';break;
				case'%M':						html += '<a href="#" class="minute">'+this.datetime.format(e)+'</a>';break;
				default:						html += e;break;
			}
		}.bind(this));
		var thead = new Element('thead').adopt(
			new Element('tr').adopt(
				new Element('td').adopt(new Element('a',{'html':'&lt;<span class="prev"></span>','class':'prev'})),
				new Element('td',{'html':html,'colspan':this.options.cols[this.options.type]+(this.options.type=='day'&&this.options.displayWeekNumbers)-2}),
				new Element('td').adopt(new Element('a',{'html':'&gt;<span class="next"></span>','class':'next'}))
			)
		).inject(table);
	//	draw the table body
		var tbody = new Element('tbody').inject(table);
		if(this.options.type=='day' && this.options.displayDayNames){
			var hrow = new Element('tr').adopt(new Element('th')).inject(tbody);var updateHrow = true;
		}
		(this.options.rows[this.options.type]).times(function(i){
			var row = new Element('tr').inject(tbody);
			if(this.options.type=='day'&&this.options.displayWeekNumbers){var th = new Element('th',{'html':datetime.format('%U'),'class':'week'}).inject(row);}
			(this.options.cols[this.options.type]).times(function(i){
				if(updateHrow){var th = new Element('th',{'html':datetime.format('%a')}).inject(hrow);}
				this.minTime.parse(datetime.getMonth()+' '+datetime.getDate()+' '+datetime.getYear()+' '+this.options.minTime);
				this.maxTime.parse(datetime.getMonth()+' '+datetime.getDate()+' '+datetime.getYear()+' '+this.options.maxTime);
				var td = new Element('td',{
					'class':(	(this.options.type == 'year' && datetime.get('year')==this.datetime.get('year')) ||
								(this.options.type == 'month' && datetime.format('%Y%m')==this.datetime.format('%Y%m')) ||
								(this.options.type == 'day' && datetime.format('%Y%m%d')==this.datetime.format('%Y%m%d')) ||
								(this.options.type == 'hour' && datetime.format('%Y%m%d')==this.datetime.format('%Y%m%d') && datetime.get('hr')==this.datetime.get('hr')) ||
								(this.options.type == 'minute' && datetime.format('%Y%m%d')==this.datetime.format('%Y%m%d') && datetime.get('hr')==this.datetime.get('hr') && datetime.get('min')==this.datetime.get('min')
							)?'selected':(
								(	(this.options.type == 'year' && datetime.get('year')==this.today.get('year')) ||
									(this.options.type == 'month' && datetime.format('%Y%m')==this.today.format('%Y%m')) ||
									(this.options.type == 'day' && datetime.format('%Y%m%d')==this.today.format('%Y%m%d')) ||
									(this.options.type == 'hour' && datetime.format('%Y%m%d')==this.today.format('%Y%m%d') && datetime.get('hr')==this.today.get('hr')) ||
									(this.options.type == 'minute' && datetime.format('%Y%m%d')==this.today.format('%Y%m%d') && datetime.get('hr')==this.today.get('hr') && datetime.get('min')==this.today.get('min'))
								)?'now':(
									(this.options.type=='day'&&(datetime.getDay()==0||datetime.getDay()==6))?'weekend':''
							)))
				}).addClass(this.options.type == 'day'?(
								datetime.getMonth() == this.datetime.getMonth() ? 'curMonth':(
									datetime.getMonth() < this.datetime.getMonth() ? (datetime.getYear()<=this.datetime.getYear()?'prevMonth':'nextMonth'):'nextMonth')
							):''
				).adopt(
					new Element('span',{
						'html':datetime.format(this.options.tdFormats[this.options.type]),
						'class':(
									(datetime.diff(this.options.minDate,'day')<=0 && datetime.diff(this.options.maxDate,'day')>=0)?(
										(this.options.type=='hour' || this.options.type=='minute')?(
											(this.minTime.get('hr') <= datetime.get('hr') && datetime.get('hr') <= this.maxTime.get('hr'))?(
												(this.options.type=='minute')?(
													(datetime.get('hr') == this.minTime.get('hr'))?(
														(this.minTime.get('min') <= datetime.get('min') && (datetime.get('hr') <= this.maxTime.get('hr') || this.maxTime.get('min') >= datetime.get('min')))?(
															('DT'+this.options.type)
														):'inactive'
													):(
														(datetime.get('hr') < this.maxTime.get('hr') || this.maxTime.get('min') >= datetime.get('min'))?(
															('DT'+this.options.type)
														):'inactive'
													)
												):('DT'+this.options.type)
											):'inactive'
										):('DT'+this.options.type)
									):'inactive'
								),
						'datetime':datetime.getTime()
					})
				).inject(row);
				datetime.increment(this.options.type,1);
			}.bind(this));
			updateHrow=false;
		}.bind(this));
	//	draw the table footer with the current date and the error messages
		var tfoot = new Element('tfoot').adopt(
			new Element('tr').adopt(
				new Element('td',{'colspan':this.options.cols[this.options.type]+(this.options.type=='day'&&this.options.displayWeekNumbers)}).adopt(
					new Element('a',{'html':this.today.format(this.options.format),'class':'today','datetime':((datetime.diff(this.options.minDate)<=0&&datetime.diff(this.options.maxDate)>=0)?this.today.getTime():null)})
				)
			)
		).inject(table);
		this.error = new Element('tr').adopt(
			new Element('th',{'colspan':this.options.cols[this.options.type]+this.options.displayWeekNumbers})
		).inject(tfoot);
	//	update the container
		this.container.empty();
		this.container.grab(table);
		return this.container;
	},

	drawError:function(message){
		this.error.empty();
		var th = new Element('th',{
			'html':message||this.options.errorMessage,
			'class':'error',
			'colspan':this.options.cols[this.options.type]+this.options.displayWeekNumbers
		}).inject(this.error);
		return;
	}
});

