//	2010 jun 24 added xSplit to replace split in order to be crossbrowser functional
//	some idiot at M$ didn't understand how split should work and didn't bother to look into it, making sure to go home at five while giving a million+ developers headaches
	String.prototype.xSplit = function(_regEx)
	{
	//	Most browsers can do this properly, so let them -- they'll do it faster
		if('a~b'.split(/(~)/).length===3){return this.split(_regEx);}
		if(!_regEx.global){_regEx=new RegExp(_regEx.source,'g'+(_regEx.ignoreCase ?'i':''));}
	//	IE (and any other browser that can't capture the delimiter)
	//	will, unfortunately, have to be slowed down
		var m, s='', a=[];
		var i, l=this.length;
		for(i=0;i<l;i++)
		{
			s+=this.charAt(i);
			m=s.match(_regEx);
			if(m)
			{
				a.push(s.replace(m[0], ''));
				a.push(m[0]);
				s = '';
			}
		}
		if(s!='') a.push(s);
		return a;
	}

//	CLASS FORM ----------------------------------------------------------------------------------------------------

var myForm = new Class({
//	use the some other mootools classes
	Implements:[Options,Events],
	options:{
		checkbox:{0:{}},
		datetime:{0:{}},
		input:{0:{}},
		password:{0:{}},
		radio:{0:{}},
		reset:{0:{}},
		select:{0:{}},
		submit:{0:{}},
		textarea:{0:{}}
	},
//	the constructor
	initialize: function(form, options){
	//	load the elements and the options
		this.form = document.id(form);
		this.fields = this.form.getElements('input,select,textarea');
		this.setOptions(options);
	//	add objects to each field
		this.fields.each(function(field,i){
			switch(field.get('tag')+field.get('type'))
			{
				case'inputtext':
					if(this.options.datetime[field.get('id')])
						this.fields[i] = new myDateTime(field,this.options.datetime[field.get('id')]);
					else
						this.fields[i] = new myInput(field,this.options.input[field.get('id')]);
				break;
				case'inputpassword':
					this.fields[i] = new myPassword(field,this.options.password[field.get('id')]);
				break;
				case'inputcheckbox':
					this.fields[i] = new myCheckbox(field,this.options.checkbox[field.get('id')]);
				break;
				case'inputradio':
					this.fields[i] = new myRadio(field,this.options.radio[field.get('id')]);
				break;
				case'inputsubmit':
				case'inputimage':
					this.fields[i] = new mySubmit(field,this.options.submit[field.get('id')]);
				break;
				case'inputreset':
					this.fields[i] = new myReset(field,this.options.reset[field.get('id')]);
				break;
				case'selectselect-one':
				case'selectselect-multiple':
					this.fields[i] = new mySelect(field,this.options.select[field.get('id')]);
				break;
				case'textareatextarea':
					this.fields[i] = new myTextarea(field,this.options.textarea[field.get('id')]);
				break;
			}
		},this);
	//	add some events to the form itself
		this.form.addEvents({
			'change':this.toggleSubmit.bind(this)
		},this);
		this.toggleSubmit();
	},

	toggleSubmit:function(){
	return true;
	//	make sure the submit buttons are available if the form status is not explicitly set to FALSE
		this.status = true;
		this.fields.each(function(field,i){
			if(field.status == true || field.status == false)
				this.status &= field.status;
		},this);
		this.form.getElements('input[type=submit],input[type=image]').set('disabled',!this.status);
	}
});

//	CLASS INPUT ----------------------------------------------------------------------------------------------------

var myInput = new Class({
	Implements:[Options,Events],
	options:{
		limit:0,
		format:'text',
		toggle:true,
		required:false,
		value:''
	},
	netnumbers: ["010","0111","0113","0114","0115","0117","0118","013","015","0161","0162","0164","0165","0166","0167","0168","0172","0174","0180","0181","0182","0183","0184","0186","0187",
				"020","0222","0223","0224","0226","0227","0228","0229","023","024","0251","0252","0255","026","0294","0297","0299",
				"030","0313","0314","0315","0316","0317","0318","0320","0321","033","0341","0342","0343","0344","0345","0346","0347","0348","035","036","038",
				"040","0411","0412","0413","0416","0418","043","045","046","0475","0478","0481","0485","0486","0487","0488","0492","0493","0495","0497","0499",
				"050","0511","0512","0513","0514","0515","0516","0517","0518","0519","0521","0522","0523","0524","0525","0527","0528","0529","053","0541","0543","0544","0545","0546","0547","0548",
				"055","0561","0562","0566","0570","0571","0572","0573","0575","0577","0578","058","0591","0592","0593","0594","0595","0596","0597","0598","0599",
				"070","071","072","073","074","075","076","077","078","079","088"],
	initialize:function(input,options){
		this.el = document.id(input);
		this.setOptions(options);
	//	add the events to the input object
		if(this.options.limit > 0)		{this.el.addEvent('keydown',this.limit.bind(this));}
// 2010 jun 28 text will no longer be formatted on keyupdate, as this prooved to be too invasive. Now the format is applied onBlur.
		if(this.options.format != '')	{
			this.el.addEvent('blur',this.format.bind(this));
			if(this.options.format != 'text' && this.options.format != '513') {
				this.el.addEvent('keyup',this.format.bind(this));
			}
		}
		if(this.options.toggle != 0)	{this.el.addEvents({
			'focus':function(){
				this.el.removeClass('inactive');
				this.el.addClass('active');
				if(this.options.value && this.el.value.toLowerCase() == this.options.value) this.el.value = '';
			}.bind(this),
			'blur':function(){
				this.el.removeClass('active');
				this.el.addClass('inactive');
				if(this.options.value && this.el.value == '') this.el.value = this.options.value;
			}.bind(this)
		})}
		this.setStatus(true);
	},
//	set the status to true if the format is correct, the field is not required or the field is required and filled out properly
	setStatus:function(format){
		this.status = (format && (!this.options.required || (this.el.value && this.el.value != this.options.value)))?true:false;
		return this.status;
	},
//	limit the number of characters
	limit:function()
	{
		if(this.options.limit && this.el.value.length > this.options.limit){this.el.value=this.el.value.substring(0,this.options.limit);}
	},
//	check if the entered content has the right format
	format:function(e)
	{
		format = true;
		switch(this.options.format){
			case'257':
			case'integer':
				this.el.value = (this.el.value.replace(/[^0-9]/g,"")*1).toInt();
				if(this.options.max && this.el.value > this.options.max) this.el.value = this.options.max;
				else if(this.options.min && this.el.value != '' && this.el.value < this.options.min) this.el.value = this.options.min;
				this.el.addClass('valid').removeClass('error');
			break;
			case'float':
				this.el.value = this.el.value.replace(",",".").replace(/[^0-9\.]/g,"");
				if(this.options.max && this.el.value.toFloat() > this.options.max) this.el.value = this.options.max.toFixed(this.options.decimals);
				else if(this.options.min && this.el.value.toFloat() < this.options.min) this.el.value = this.options.min.toFixed(this.options.decimals);
				if(this.el.value != this.el.value.toFloat().round(this.options.decimals)) this.el.value = this.el.value.toFloat().toFixed(this.options.decimals);
				if(this.el.value == 'NaN') this.el.value = 0;
			break;
			case'phone':
			//	prevent all but listed characters from being entered
				if(	["-","+","(",")","space","1","2","3","4","5","6","7","8","9","0","backspace","delete","left","right","tab"].contains(e.key) == false &&
					[96,97,98,99,100,101,102,103,104,105,107,109].contains(e.code.toInt()) == false) {
						//alert(e.key+' '+e.code);
						e.preventDefault();
				}
			//	update the format of the phone number
				if(["-","+","(",")","space","backspace","delete","left","right"].contains(e.key) == false){
				//	strip the string of all non-numeric characters, source:http://www.27seconds.com/kb/article_view.aspx?id=31
					var t = this.el.value.replace(/[^0-9]/g,"");
				//	format 06-numbers as (06) 11 11 11 11
					if(t.substr(0,2) == "06"){
						this.el.value = "(06) "+t.substr(2,2)+" "+t.substr(4,2)+" "+t.substr(6,2)+" "+t.substr(8,2);
					}
				//	format 0800 and 0900 numbers as (0800) 1111 11
					else if(["0800","0900"].contains(t.substr(0,4))){
						this.el.value = "("+t.substr(0,4)+") "+t.substr(4,4)+" "+t.substr(8,2);
					}
				//	format three-digit netnumbers as (333) 111 11 11
					else if(this.netnumbers.contains(t.substr(0,3))){
						this.el.value = "("+t.substr(0,3)+") "+t.substr(3,3)+" "+t.substr(6,2)+" "+t.substr(8,2);
					}
				//	format four-digit netnumbers as (4444) 11 11 11
					else if(this.netnumbers.contains(t.substr(0,4))){
						this.el.value = "("+t.substr(0,4)+") "+t.substr(4,2)+" "+t.substr(6,2)+" "+t.substr(8,2);
					}
					else{
						this.el.value = t;
					}
					this.el.value = this.el.value.trim();
				}
			break;
			case'zipcode':
			//	nog te bouwen switch oid op een komma gescheiden format string(s)
			//	source: http://en.wikipedia.org/wiki/List_of_postal_codes
				var t = this.el.value.substr(0,4).replace(/[^0-9]/g,"");
				if(this.el.value.length > 4){
					t = t + " " + this.el.value.substr(4,this.el.value.length).replace(/[^a-zA-Z]/g,"").substr(0,2).toUpperCase();
				}
				this.el.value = t;
				format = (this.el.value.length == 7);
			break;
			case'274':
			case'email':
				this.el.value = this.el.value.stripTags().tidy();
				if(!this.result) {this.result = new Element('span',{'class':'result'}).inject(this.el,'after');}
				format = (/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i).test(this.el.value);
				if(format)
				{
					this.el.addClass('valid').removeClass('error');
					this.result.addClass('valid').removeClass('error');
				}
				else
				{
					this.el.addClass('error').removeClass('valid');
					this.result.addClass('error').removeClass('valid');
				}
			break;
			case'513':
			case'text':
			default:
			//	strip all posible HTML tags. Only BB-code will be accepted
//				this.el.value = this.el.value.stripTags().tidy();
				this.el.set('value',this.el.get('value').stripTags().tidy());
				this.el.addClass('valid').removeClass('error');
			break;
		}
		this.setStatus(format);
		this.el.form.fireEvent('change');
		return format;
	}
});

//	CLASS CHECKBOX ----------------------------------------------------------------------------------------------------

var myCheckbox = new Class({
	Extends:myInput,
	initialize:function(input,options){
	//	no functional ideas for checkboxes just yet ...
		this.parent(input,options);
	},
	setStatus:function(format){
		this.status = true;
	},
	toggleRow:function(){},
	toggleCol:function(){},
	toggleAll:function(){}
});

//	CLASS PASSWORD ----------------------------------------------------------------------------------------------------

var myPassword = new Class({
	Extends:myInput,
	options:{
		type:'normal',
		showEntries:true,
		showStrength:false
	},
	initialize:function(input,options){
		this.parent(input,options);
		if(this.options.showEntries) {this.drawEntries()};
		if(this.options.showStrength) {this.drawStrength()};
	},
	drawEntries:function()
	{
		this.container = new Element('span',{'class':'password_container'}).setStyles({
			'position':'absolute',
			'display':'none',
			'width':'20px',
			'height':'20px',
			'margin-top':'-20px',
			'overflow':'hidden'
		}).inject(this.el,'before');
		this.text = new Element('span',{'class':'password_text','html':this.el.value}).setStyles({
			'position':'absolute',
			'display':'block',
			'font-family':'monospace',
			'font-size':this.el.getStyle('font-size'),
			'padding-left':'6px'
		}).inject(this.container);
		this.el.addEvents({
			'keyup':function(e){this.text.set('html',this.el.value)}.bind(this),
			'mouseover':function(e){this.container.show()}.bind(this),
			'mouseout':function(e){this.container.hide()}.bind(this),
			'mousemove':function(e){
				this.container.setPosition({x:(e.page.x-10)});
				this.text.setPosition({x:(this.el.getPosition().x - e.page.x + 10)});
			}.bind(this)
		});
		return true;
	},
	drawStrength:function(){
		this.strength = new Element('span',{'class':'password_strength'}).inject(this.el,'after');
		this.el.addEvents({
			'keyup':function(){this.strength.set('html',this.calcStrength(this.el.value));}.bind(this)
		});
	},
	calcStrength:function(p){
	//	source: http://www.wilderssecurity.com/archive/index.php/t-16174.html
	//	A maximum of 10 points for any given password ( i.e A strong password gets 10 points )
	//	more on RegEx: http://www.consideropen.com/blog/2008/08/30-days-of-mootools-12-tutorials-day-13-regular-expressions/
		var s = 0;
	//	Minimum of 2 points for any passwords.
		if(p.length > 0) {
			s=s+2;
		//	If the password contains both letters and numbers it gets 2 more points.
			if(p.test("[a-z]","i") && p.test("[0-9]")) {s=s+2;}
		//	If the password contains combination of lower case and upper case it gets 2 more points.
			if(p.test("[a-z]") && p.test("[A-Z]")) {s=s+2;}
		//	If the password contains Special chars it gets 2 more points.
			if(p.test("[^A-Za-z0-9]")) {s=s+2;}
		//	If the length of the password is greater than 8 chrs it gets 2 more points.
			if(p.length > 8) {s=s+2;}
		}
		return s;
	}
});

//	CLASS RADIO ----------------------------------------------------------------------------------------------------

var myRadio = new Class({
	Implements:[Options,Events],
	options:{},
	initialize:function(input,options){
	//	no functional ideas for select boxes just yet ...
		this.el = document.id(input);
		this.setOptions(options);
		this.status = true;
	},
	setStatus:function(format){
		this.status = true;
	}
});

//	CLASS RESET ----------------------------------------------------------------------------------------------------

var myReset = new Class({
	Implements:[Options,Events],
	options:{
		unreset:false,
		inputs:[],
		selects:[],
		textareas:[]
	},
	initialize:function(input,options){
		this.el = document.id(input);
		this.setOptions(options);
		if(this.options.unreset) {this.el.addEvent('click',this.drawUnreset.bind(this));}
		this.status = true;
alert(this.options.limit);
	},
	setStatus:function(format){
		this.status = true;
	},
	drawUnreset:function()
	{
		if(!this.unreset){
		//	update the form contents
			this.el.form.getElements('input').each(function(e,i){
				if(['text','password'].contains(e.get('type'))) {this.options.inputs[i] = e.value;}
				if(['radio','checkbox'].contains(e.get('type'))) {this.options.inputs[i] = e.checked;}
			}.bind(this));
			this.el.form.getElements("select").each(function(e,i){this.options.selects[i] = e.value;}.bind(this));
			this.el.form.getElements("textarea").each(function(e,i){this.options.textareas[i] = e.value;}.bind(this));
		//	draw the unreset button
			this.unreset = new Element('input',{'type':'button','value':'oops!'}).inject(this.el,'after');
			this.unreset.addEvent('click',function(e){
				this.el.form.getElements("input").each(function(e,i){
					if(['text','password'].contains(e.get('type'))) {e.value = this.options.inputs[i];}
					if(['radio','checkbox'].contains(e.get('type'))) {e.checked = this.options.inputs[i];}
				}.bind(this));
				this.el.form.getElements("select").each(function(e,i){e.value = this.options.selects[i];}.bind(this));
				this.el.form.getElements("textarea").each(function(e,i){e.value = this.options.textareas[i];}.bind(this));
				this.unreset.destroy();
				this.unreset = false;
			}.bind(this));
		}
	}
});

//	CLASS SELECT ----------------------------------------------------------------------------------------------------

var mySelect = new Class({
	Implements:[Options,Events,Slider],
	options:{
		format:'radio',
		snap:false,
		offset:0,
		range:false,
		wheel:false,
		steps:100,
		mode:'horizontal',
		initialStep:0,
		'min':0,
		'max':0
	},
	initialize:function(input,options){
		this.el = document.id(input);
		this.setOptions(options);
		if(this.options.format == 'slider') {this.drawSlider();}
		this.status = true;
	},
	setStatus:function(format){
		this.status = true;
	},
	drawSlider:function(){
//alert('drawSlider');
//alert(this.el.getChildren().length);
//alert(this.el.getFirst('option').value);
		this.options.range = [];
		this.el.getChildren('option').each(function(e,i){
			this.options.range.extend([e.value]);
			if(e.selected) {this.options.initialStep = i+1};
		}.bind(this));
//alert(this.options.range);
//alert(this.options.initialStep);
//alert(this.options.range.length);
	//	convert the selectbox to a hidden field
		var hidden = new Element('input',{
			type:'hidden',
			name:this.el.get('name'),
			id:this.el.get('id')
		}).inject(this.el,'after');
	//	create the slider
		this.slider = new Element('div',{'class':'slider'}).inject(this.el,'before');
		this.knob = new Element('div',{'class':'knob'}).inject(this.slider,'bottom');
		var mySlider = new Slider(this.slider, this.knob, {
			snap:this.options.snap,
			offset:this.options.offset,
			range:this.options.range,
			wheel:this.options.wheel,
			steps:this.options.range.length,
			mode:this.options.mode,
			initialStep:this.options.initialStep,
			onChange: function(value){hidden.value = value;}
		});
		this.el.destroy();
	}
});

//	CLASS SUBMIT ----------------------------------------------------------------------------------------------------

var mySubmit = new Class({
	Extends:myInput,
	initialize:function(input,options){
		this.parent(input,options);
	//	no functional ideas for submit buttons just yet ...
	//	make submit button available only when all required form fields are filled and filled form fields meet their required formatting restrictions
	//	this requires each form field to have a status and the form itself should have an overall status
		if(this.el.get('type') == 'image')
		{
//alert(this.el.get('src'));
			this.src = this.el.get('src').substr(0,this.el.get('src').length-4);
			this.srcExt = this.el.get('src').substr(this.el.get('src').length-4);
//alert(this.src+' '+this.srcExt);
			this.el.addEvent('change',this.updateSrc.bind(this));
		}
	},
	setStatus:function(format){
		this.status = true;
	},
	updateSrc:function(){
//alert(this.el.get('disabled'));
		this.el.set('src',this.src+(this.el.get('disabled')?'_dis':'')+this.srcExt);
	}
});

//	CLASS TEXTAREA ----------------------------------------------------------------------------------------------------

var myTextarea = new Class({
//	use the some other mootools classes
	Extends:myInput,
//	the options
	options: {
		limit:0,	// maximum number of characters 0 is unlimited
		resize:true,		// grow or shrink the height of the textarea depending on the content (boolean)
		useBBcode:false,		// create links to easily insert BB Code
		BBlinks:['bold','italic','underline','strike','sub','sup','small','quote','link','h1','h2','h3','h4','h5','h6'],
		BBtexts:['Voer omschrijving in:','Voer de URL in:'],
		aniDuration:200,
		aniTransition:'linear',
		useLineNumbers:false,
		useTab:false,
		useMaximize:false,
		MaximizeContainer:null
	},
//	the constructor
	initialize: function(input,options){
		this.parent(input,options);
		if(this.options.resize){
			this.el.setStyle("overflow","hidden");
			this.vertPadding=this.el.getStyle("padding-top").toInt()+this.el.getStyle("padding-bottom").toInt()+this.el.getStyle("border-top").toInt()+this.el.getStyle("border-bottom").toInt();
			this.resizer=new Fx.Tween(this.el,{duration:this.options.aniDuration,transition:this.options.aniTransition});
			this.el.addEvents({
				keyup:this.resize.bind(this),
				change:this.resize.bind(this),
				click:this.resize.bind(this)
			});
			this.resize();
		}
		if(this.options.useBBcode){this.drawBBlinks()}
		if(this.options.useLineNumbers){this.drawLineNumbers()}
		if(this.options.useMaximize){this.drawMinMax()}
		if(this.options.useTab){
			this.el.addEvent('keydown',function(e){
/*
				if(e.key == 'tab')
				{
					e.stop();
					var p = this.cursorPos
					if(this.selectionStart != 'undefined')
						this.value=this.value.substring(0,this.selectionStart)+'	'+this.value.substring(this.selectionEnd);
					else
						this.value = this.value+'	';
					this.focus();
				}
*/
			});
		}
	},
	drawMinMax:function()
	{
		this.MaximizeContainer = $(this.options.MaximizeContainer) || this.el.getParent('div');
		this.MaximizeStyles = this.MaximizeContainer.getStyles('position','width','height','top','right','bottom','left','z-index','padding','padding-top','padding-right','padding-bottom','padding-left','background');
		this.minmax = new Element('a',{html:'maximize','class':'maximize'}).addEvent('click',function(){this.toggleMinMax()}.bind(this)).inject(this.el,'after');
	},
	toggleMinMax:function()
	{
		if(this.maximized)
		{
			this.MaximizeContainer.morph({
				top:this.MaximizeStyles.top,
				right:this.MaximizeStyles.right,
				bottom:this.MaximizeStyles.bottom,
				left:this.MaximizeStyles.left,
				//'z-index':this.MaximizeStyles.get('z-index'),
				background:this.MaximizeStyles.background,
//				'padding-top':this.MaximizeStyles.get('padding-top'),
//				'padding-right':this.MaximizeStyles.get('padding-right'),
//				'padding-bottom':this.MaximizeStyles.get('padding-bottom'),
//				'padding-left':this.MaximizeStyles.get('padding-left'),
				padding:this.MaximizeStyles.padding,
				position:this.MaximizeStyles.position
				
			});
			this.maximized = false;
		}
		else
		{
			this.MaximizeContainer.setStyle('height','auto').morph({
				'top':0,
				'right':0,
				'bottom':0,
				'left':0,
				'z-index':10,
				'background':'url(http://slab.elicit.nl/css/img/transparent_dark.png)',
				'padding-top':20,
				'padding-right':20,
				'padding-bottom':20,
				'padding-left':55,
				'position':'absolute'
			});
			this.maximized = true;
		}
	},
//	draw the BB Code links
	drawBBlinks:function()
	{
	//	draw a div around the the textarea which will contain the textarea and the BB links
		var BBdiv = new Element('div',{'class':'BBcontainer'}).wraps(this.el);
		var BBlinks = new Element('div',{'class':'BBlinks'}).inject(BBdiv,'bottom');
		var BBclear = new Element('div',{'style':'clear:both'}).inject(BBdiv,'bottom');
	//	add the links to the div
		this.options.BBlinks.each(function(BB,i){
			var a = new Element('a',{'html':BB+'<span><!-- --></span>','class':'BB_'+BB}
								).addEvent('click',function(){this.updateBBcode(BB)}.bind(this)
								).inject(BBlinks,'bottom');
		}.bind(this));
		return this;
	},
//	the BB update call linked to the BB code links
	updateBBcode:function(type){
	//	for normal browsers
		if(this.el.selectionStart != 'undefined'){
			this.el.value=this.el.value.substring(0,this.el.selectionStart)+this.replaceBBCode(type,this.el.value.substring(this.el.selectionStart,this.el.selectionEnd))+this.el.value.substring(this.el.selectionEnd);
	//	for internet explorers
		}else if(document.selection.createRange() != 'undefined'){
			this.el.focus();
			var cursorPos = document.selection.createRange().duplicate();
			this.el.cursorPos.text = replaceBBCode(type,this.el.cursorPos.text);
	//	for unselected or empty targets
		}else{
			this.el.value+=replaceBBCode(type,'');
		}
		return true;
	},
//	add the selected BB code to the selected text
	replaceBBCode:function(type,text)
	{
	//	add the proper BB code
		switch(type){
			case'plain':break;
			case'h1':case'h2':case'h3':case'h4':case'h5':case'h6':text='['+type+']'+text+'[/'+type+']';break;
			case'bold':text='[b]'+text+'[/b]';break;
			case'italic':text='[i]'+text+'[/i]';break;
			case'underline':text='[u]'+text+'[/u]';break;
			case'strike':text='[s]'+text+'[/s]';break;
			case'sub':text='[sub]'+text+'[/sub]';break;
			case'sup':text='[sup]'+text+'[/sup]';break;
			case'small':text='[small]'+text+'[/small]';break;
			case'list_bullet':text='[list]\r\n[li]'+(text.xSplit(/\r?\n/).join('[/li]\r\n[li]'))+'[/li]\r\n[/list]';break;
			case'link':
				var val='';
				if(/^(http:\/\/|www\.)/i.test(text)){
					if((val=prompt(this.options.BBtexts[0],text)))
						text='[url="'+text.replace(/(["\\])/g,'\\$1')+'"]'+val+'[/url]'
				}else{
					val=prompt(this.options.BBtexts[1],'http:\/\/');
					if(val&&val!='http:\/\/')
						if(text==''){
							text='[url]'+val+'[/url]'
						}else 
							text='[url="'+val.replace(/(["\\])/g,'\\$1')+'"]'+text+'[/url]'
				};
				break;
			case'quote':text='[quote]\r\n'+text+'\r\n[/quote]';break;
		};
		return text;
	},
//	grow or shrink the textarea depending on the content
	resize:function()
	{
		var S=this.el.getSize();
		var SS=this.el.getScrollSize();
		if(navigator.userAgent.toLowerCase().indexOf("chrome")>-1 || navigator.userAgent.toLowerCase().indexOf("safari")>-1){
			if(SS.y > S.y )
			{
				this.resizer.start("height",SS.y);
			}
		} else if((SS.y+this.vertPadding) > S.y){
			this.resizer.start("height",SS.y);
		}
		return this;
	},
//	draw a div with line numbers, matching the textarea size, also the current line can be highlighted.
	drawLineNumbers:function()
	{
		var string = '';
		for(var no=1;no<300;no++){
			if(string.length>0)string += '<br>';
				string += no;
		}
		this.LineNumberContainer = new Element('div',{
			'html':string
		}).setStyles({
			'position':'absolute',
			'height':this.el.getStyle('height'),
			'font-size':this.el.getStyle('font-size'),
			'line-height':this.el.getStyle('line-height'),
			'padding-top':3,
			'padding-left':5,
			'padding-right':5,
			'width':25,
			'overflow':'hidden',
			'text-align':'right',
			'background-color':'#333333',
			'color':'#BBBBBB',
			'margin-left':-35
		}).inject(this.el,'before');
		this.el.addEvents({
			'keyup':function(){this.updateLineNumbers()}.bind(this),
			'mousedown':function(){this.updateLineNumbers()}.bind(this),
			'scroll':function(){this.updateLineNumbers()}.bind(this),
			'blur':function(){this.updateLineNumbers()}.bind(this),
			'focus':function(){this.updateLineNumbers()}.bind(this),
			'mouseover':function(){this.updateLineNumbers()}.bind(this),
			'mouseup':function(){this.updateLineNumbers()}.bind(this)
		});
	},
	updateLineNumbers:function()
	{
		this.LineNumberContainer.setStyle('height',this.el.getStyle('height')).scrollTo(0,this.el.getScroll().y);
	}
});

//	CLASS DATETIME ----------------------------------------------------------------------------------------------------

var myDateTime = 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:00',				// minimum selectable time of the day
		maxTime:'23:59: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 datetime when clicked outside the input box and datetime element
		$(document.body).addEvent('click',this.hide.bind(this));
		this.status = true;
	},
	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();
// 2010 jun 22 e.target aangepast naar ele = $(e.target) omdat IE e.target niet als element herkent, is ook logisch, vreemd dat de andere browsers het wel snappen.
		var ele = $(e.target);
	//	handle all the click events on the container
		if(ele.hasClass('inactive')){
			return;
		}else if(ele.hasClass('next')){
			this.datetime.increment(this.options.sequence[Math.max(0,this.options.sequence.indexOf(this.options.type)-1)], 1);
		}else if(ele.hasClass('prev')){
			this.datetime.increment(this.options.sequence[Math.max(0,this.options.sequence.indexOf(this.options.type)-1)],-1);
		}else if(this.select[ele.get('class')]){
			this.options.type = ele.get('class');
		}else if(ele.get('datetime') && ele.hasClass('DT'+this.options.type)){
			this.datetime.setTime(ele.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(ele.get('datetime')){
			this.datetime.setTime(ele.get('datetime'));
			input.set('value',this.datetime.format(this.options.format));
			this.hide();
		}else {
			return this.drawError();
		}
// 2010 feb 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 apr 28 aangepast om via de verschillende datum velden direct naar het keuze scherm te switchen ipv steeds 1 "grotere" datum omhoog
// 2010 jun 22 split vervangen door xSplit (zie regel 1) omdat IE het weer eens niet begrijpt ...
		var html = '';
	//	split the format in order to create a link per data item
		var a = this.options.format.xSplit(/([^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);}
// 2010 jun 22 slashes toegevoegd zodat IE het ook kan parsen .... ow en ook de default secondes toegevoegs aan de minTime en maxTime options
				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;
	}
});

