/**	
 * @copyright 	Copyright (C) 2009-2010 Rhinofly, www.rhinofly.nl
 * @author		Klaas Landsman - klandsman@rhinofly.nl
 *
 * @description Below you'll find the Rijks JS Object, an object with a bunch of js-functions which are used on the new Rijks-websites.
 *
 *
 *	0.0 The following functionalities are part of the Rijks-object:
 *		- 1.0 Widgets
 *		- 2.0 Delete links
 *		- 3.0 Form validation
 *		- 4.0 Input counters
 *		- 5.0 Input help messages (form-related)
 *		
 *		
 *	1.0 Widgets
 *		
 *		1.1 What does it do?
 *		It toggles the visibility of toggle-able elements.
 *		
 *		1.2 How to use it?
 *		It's pretty easy to make an element toggle-able, just use the following structure:
 *		
 *			<div class="widget">
 *				<h4>title of the togglebox, this title is clickable and always visible</h4>
 *				<div class="widget-inner">
 *					Here's the content which can be toggled
 *				</div>
 *			</div>
 *		
 *		1.3 Remember the status with a cookie
 *		If you want the browser to remember the open/close state of a widget, give the containing div
 *		(with classname "widget") an (unique) ID. Thats all.
 *		
 *		1.4 close on page-load
 *		Normally, the widgets are always opened. If you want them to collapse immediatly after page-load,
 *		add the classname "closed" to the containing div with classname "widget" (resulting in "widget closed")
 *		
 *	
 *	
 *	2.0 Delete buttons/links
 *		
 *		2.1 What does it do?
 *		This little function scans the DOM for elements with classname "del" which indicates that the action behind
 *		that link/button/etc will delete something. This functions comes with a confirm-message if you really want to continue
 *		the action.
 *		
 *		2.2 How to use it?
 *		Give the element the classname "del" and optionally a title-attribute. This title will be the question which
 *		is asked in the confirm-box. If the title-attribute is not entered, it will show the following message:
 *		"Weet u zeker dat u deze actie wilt uitvoeren?"
 *		
 *	
 *	
 *	3.0 Form validation
 *	
 *		3.1 What does it do?
 *			A lot. It validates the form om multiple kind of values like phone-, zip-, email- and date-values.
 *			Also, it gives visual feedback through given classnames.
 *		
 *		3.2 How to use it?
 *			Three things are important for the structure of the form.
 *			First, the form needs the classname "rijks-validation", the required inputs obtain the class "rijks-required".
 *			Second, every label and corresponding input-element need the same parentNode, as that node will
 *			receive a classname if an error occured.
 *			Third, an extra fieldset at the beginning of the form is needed for showing a list of possibly errors.
 *		
 *		3.3 The form-structure...
 *			...could, for example, look like this:
 *			
 *			<form class="rijks-validation">
 *				
 *				(	the errorset fieldset is deprecated now. The script will check if the fieldset exist and build one
 *					itself if it's not found. The scripts always puts this fieldset at the top of the form, so you could still
 *					use the following errorset-fieldset to position the errorfieldset yourself.
 *				
 * 					<fieldset class="errorset">
 *						<h2>An error occured</h2>
 *						<p>Take a look at the following errors:</p>
 *						<ul class="errorlist"><li></li></ul>
 *					</fieldset>
 *				
 *				// end of errorset fieldset	)
 *
 *				<fieldset>
 *					<label>Name</label>
 *					<input type="text" name="name" />
 *				</fieldset>
 *				
 *				<fieldset>
 *					<label>surname</label>
 *					<input type="text" class="rijks-required" name="surname" />
 *				</fieldset>
 *				
 *				<fieldset>
 *					<label>E-mail address</label>
 *					<input type="text" class="rijks-required rijks-email" name="email" />
 *				</fieldset>
 *				
 *				<fieldset>
 *					<label>Phone</label>
 *					<input type="text" class="rijks-required rijks-phone" name="phone" />
 *				</fieldset>
 *				
 *				<fieldset>
 *					<label>Message</label>
 *					<textarea class="rijks-required" name="message" cols="40" rows="4"></textarea>
 *				</fieldset>
 *				
 *				<p><input type="submit" class="submit">Submit this darn form.</submit></p> 
 * 				(The input inside a paragraph is an idea of the Rijks-starterskit, don't blame me. Thanks.)
 *			</form>
 *		
 *			In this case, if an error occured, the fieldset containing the error will receive the className "err"
 *			So styling the error inputs is easy with css, for example: form fieldset.err input {border:1px solid red;}
 *			
 *		3.4 Special validation
 *			As you may have noticed in the example above, there are some extra classnames. These classnames are for special validation.
 *			The following special validations are available:
 *				- e-mail validation		class="rijks-required rijks-email"
 *				- phone validation		class="rijks-required rijks-phone"
 *				- zip-code validation	class="rijks-required rijks-zip"
 *				- date validation		class="rijks-required rijks-date" // validates dutch, german and belgian zipcodes
 *			
 *			The e-mail validation validates, well.. yeah, e-mailaddresses.
 *			The phone validation validates both dutch as foreign numbers.
 *			The zip-code validation validates dutch zip-codes.
 *			The date validation validates dates like this: dd-mm-yyyy / dd.mm.yyyy (source: http://regexlib.com/REDetails.aspx?regexp_id=762)
 *		
 *		3.4 The errorlist
 *			for extra visual feedback you can (optionally) add an extra fieldset at the beginning of the form (as shown in the example above)
 *			The errormessages are based on the title attributes of the failed input-elements. The messages will appear in the ul.errorlist
 *			
 *			new functionality: when there's no title-attribute found, it will used the innerHTML of the associated <Label />
 *	
 *	
 *	
 *	4. Input counters
 *		
 *		4.1 What does it do?
 *			This js-code limits the amount of characters of input-/textarea-elements, etc.
 *		
 *		4.2 How to use it?
 *			Easy, just add the class "maxlength_xxx" to the corresponding element, where 'xxx' is the maximum amount of characters.
 *		
 *		4.2 Which results in..
 *			.. an element like this: <p class="counter">295 characters left</p>, which is inserted right after the character-limited element.
 *	
 *	
 *	
 *	5. Input help messages
 *	
 *		5.1 What does it do?
 *			it shows a 'help-balloon' when clicked on a mark.
 *			The script searches for elements with the classname "formhelp". When you click on it, the script will insert an element after the
 *			formhelp-element, with classname "formhelpbox" which contains the contents of the title-attribute of the formhelp-element.
 *			
 *		5.2 How to use it?
 *			Just make, for example, an a-element with classname "formhelp" and title-attribute with the description for the help-balloon.
 *	
 */

var Dom = YAHOO.util.Dom;
var Anim = YAHOO.util.Anim;
var Event = YAHOO.util.Event;
var Cookie = YAHOO.util.Cookie;
var isIE = /*@cc_on!@*/false;
var isIE6 = /msie|MSIE 6/.test(navigator.userAgent);

var rijks = new Object();

	rijks.init = function()
	{
		rijks.print.init();
		rijks.blankWindows.init();
		rijks.widget.init();
		rijks.delBtns.init();
		rijks.form.help.init();
		rijks.form.counter.init();
		rijks.form.validate.init();
		rijks.form.tillCheckbox.init();
	};
	
	Event.onDOMReady(rijks.init);
	
	rijks.print =
	{
		init : function()
		{
			var els = Dom.getElementsByClassName("ico-vac-print");
			Event.on(els,"click",this.run);
		},
		
		run : function()
		{
			window.print();
		}
	};
	
	rijks.blankWindows = 
	{
		init : function()
		{
			var els = Dom.getElementsByClassName("blank");
			for(var i=0; i<els.length; i++) els[i].target = "_blank";
		}
	};
	
	rijks.widget = 
	{
		init : function()
		{
			var widgets = Dom.getElementsByClassName("widget");
			for(var i=0; i<widgets.length; i++){	

				var toggler = widgets[i].getElementsByTagName("h4")[0];
				var content = Dom.getElementsByClassName("widget-inner",null,widgets[i])[0];

				Event.on(toggler,"click",function(){rijks.widget.run(this.parentNode)});
				
				// if IE6, add this style to the toggler, otherwise only the text is clickable instead of the entire toggle-element
				if(isIE6) Dom.setStyle(toggler,"display","inline-block");
				
				var display   = (Dom.hasClass(widgets[i],"closed")) ? "none" : "block";
				var classname = (Dom.hasClass(widgets[i],"closed")) ? ""	 : "open";
				
				if(widgets[i].id && Cookie.getSubs(widgets[i].id) && !Dom.hasClass(widgets[i],"closed")) display = Cookie.get(widgets[i].id);
				if(widgets[i].id && Cookie.get(widgets[i].id) == "none" && !Dom.hasClass(widgets[i],"closed")) classname = "closed";
				
				Dom.setStyle(content,"display",display);
				Dom.addClass(widgets[i],classname);
			};
		},
		
		run : function(o,action)
		{
			var content = Dom.getElementsByClassName("widget-inner",null,o)[0];
			
			if(action)
			{
				var display = (action == "close") ? "none" : "block";
			
				var classes = (action == "close" && Dom.hasClass(content.parentNode,"open") ) ? ["open","closed"] : null;
				var classes = (action == "open" && Dom.hasClass(content.parentNode,"closed")) ? ["closed","open"] : null;
				
			}else
			{
				var display = (Dom.getStyle(content,"display") == "block") ? "none" : "block";			
				var classes = (Dom.hasClass(content.parentNode,"open")) ? ["open","closed"] : ["closed","open"];
			};
			
			Dom.setStyle(content,"display",display);
			if(classes != null) Dom.replaceClass(content.parentNode,classes[0],classes[1]);
			if(o.id) Cookie.set(o.id,display,{expires: new Date("January 12, 2025")});
		}
	};
	
	rijks.delBtns = 
	{
		init : function()
		{
			var del = Dom.getElementsByClassName("del","a");
			Event.on(del,"click",this.run);
		},
		
		
		run : function(e)
		{
			var msg = (this.title) ? this.title : "Weet u zeker dat u deze actie wilt uitvoeren?";
			if(!confirm(msg)) Event.preventDefault(e);
		}
	};

	rijks.form = new Object();
	rijks.form.help = 
	{
		init : function()
		{
			var els = Dom.getElementsByClassName("formhelp");
			if(!els[0]) return false;
			
			for(var i=0; i<els.length; i++)
			{
				Event.on(els[i],"click",this.run);
				els[i].message = els[i].title;
				els[i].title = els[i].title.replace(/(<([^>]+)>)/g,"");
			}
			
			rijks.form.help.box = document.createElement("div");
			rijks.form.help.box.className = "formhelpbox";
			rijks.form.help.box.style.display = "none";
		},
		
		run : function(e)
		{
			Event.preventDefault(e);

			var del = document.createElement("a");
				del.className = "hidebox";
			
			var txt = document.createElement("p");
				txt.innerHTML = this.message;
				
			rijks.form.help.box.innerHTML = "";
			rijks.form.help.box.appendChild(del);
			rijks.form.help.box.appendChild(txt);
			
			Dom.insertAfter(rijks.form.help.box,this)
			Event.on(del,"click",rijks.form.help.toggle);
			rijks.form.help.toggle(null,this);
		},
		
		toggle : function(e,o)
		{
			if(e) Event.preventDefault(e);
			if(!o) var o = rijks.form.help.box.current;
			
			if(Dom.getStyle(rijks.form.help.box,"display") == "none")
			{
				Dom.setStyle(rijks.form.help.box,"display","block");
			
				var anim = new Anim(rijks.form.help.box,{opacity:{to:1},top:{from:-5,to:0}}, .2, YAHOO.util.Easing.easeOutStrong);
					anim.animate();
				
				var anim2 = new Anim("content-tertiary",{opacity:{to:.2}}, .2, YAHOO.util.Easing.easeOutStrong);
					anim2.animate();
					
			}else if(o == rijks.form.help.box.current)
			{
				var anim = new Anim(rijks.form.help.box,{opacity:{to:0},top:{from:0,to:5}}, .2, YAHOO.util.Easing.easeOutStrong);
					anim.onComplete.subscribe(function(){
						Dom.setStyle(rijks.form.help.box,"display","none");
						rijks.form.help.box.current = "";
					});
					anim.animate();
					
				var anim2 = new Anim("content-tertiary",{opacity:{to:1}}, .2, YAHOO.util.Easing.easeOutStrong);
					anim2.animate();
			}
			rijks.form.help.box.current = o;
		}
	};

	rijks.form.counter = 
	{
		init : function()
		{
			var els = document.getElementsByTagName("textarea");
			for(var i=0; i<els.length; i++)
			{
				if(els[i].className.search(/maxlength/) == -1) continue;
				els[i].maxLength = parseInt(els[i].className.split('_')[1]);
				Event.on(els[i],"keyup",rijks.form.counter.run);
				this.addCounter(els[i]);
			}
		},
		
		addCounter : function(el)
		{		
			var holder = document.createElement("p");
				holder.className = "counter";
				holder.innerHTML = (el.maxLength-el.value.length) + " tekens resterend";
			
			el.counter = holder;
			Dom.insertAfter(holder,el);
		},
		
		run : function(e)
		{
			if (this.value.length > this.maxLength)
			{
				var scrollTop = this.scrollTop;
				this.value = this.value.substr(0, this.maxLength);
				this.scrollTop = scrollTop;
			}
			
			this.counter.innerHTML = (this.maxLength-this.value.length) + " tekens resterend";
		}
	};
	
	rijks.form.tillCheckbox = 
	{
		init : function()
		{
			var dateBoxes = Dom.getElementsByClassName("date-now");
			Event.on(dateBoxes,"click",this.run);
			Event.on(dateBoxes,"change",this.run);
			for(var i=0; i<dateBoxes.length; i++) this.run(null,dateBoxes[i]);
		},
		
		run : function(e,o)
		{
			var el = (e != null) ? this : o;
			var status = el.checked;
			
			var prefix = el.id.substr(0,3);
			var nr = el.id.replace(/\D/g,"");
			
			var maand = Dom.get(prefix + "_einddatum_maand_" + nr);
			var jaar  = Dom.get(prefix + "_einddatum_jaar_" + nr);
			
			maand.disabled = (status) ? "disabled" : "";
			jaar.disabled  = (status) ? "disabled" : "";
		}
	};
	
	rijks.form.validate = 
	{
		init : function()
		{
			rijks.form.validate.forms = Dom.getElementsByClassName("rijks-validate");
			if(!rijks.form.validate.forms[0]) return false;
			
			Event.on(rijks.form.validate.forms,"submit",rijks.form.validate.run);
			for(var i=0; i<this.forms.length; i++) this.buildErrorfield(this.forms[i]);
			
			this.gotoNextStep();
		},
		
		gotoNextStep : function()
		{
			var els = Dom.getElementsByClassName("gotoNextStep");
			Event.on(els,"click",function(){ rijks.form.validate.parentForm(this).skipValidation = 1; });
		},
		
		buildErrorfield : function(form)
		{
			if(!Dom.getElementsByClassName("errorset","fieldset",form)[0])
			{
				var fieldset = document.createElement("fieldset");
				var h2 = document.createElement("h2");
				var p = document.createElement("p");
				var ul = document.createElement("ul");
				
				fieldset.className = "errorset message_err";
				h2.innerHTML = "Er is een probleem opgetreden bij het verwerken van je gegevens.";
				p.innerHTML = "Je invoer is niet geaccepteerd omdat de volgende gegevens missen:";
				ul.className = "errorlist";
				
				fieldset.appendChild(h2);
				fieldset.appendChild(p);
				fieldset.appendChild(ul);
				this.buildErrorfield.structure = fieldset;
				
				var firstChild = Dom.getChildren(form)[0];				
				Dom.insertBefore(this.buildErrorfield.structure,firstChild);
			};
		},
		
		parentForm : function(el)
		{
			var curEl = "Dom.get(el";
			for(var i=0; i<20; i++)
			{
				var parent = eval((curEl += ".parentNode")+")");
				if(parent.tagName == "FORM") return parent;
			}
		},
		
		run : function(e,o)
		{
			var form = (typeof(o) == "undefined") ? this : o;
			
			form.validationActivated = 1;
			
			if(form.skipValidation == 1)
			{
				form.submit();
				return false;
			};
			
			if(typeof(tinyMCE) != "undefined") tinyMCE.triggerSave();

			if(e.type == "submit") Event.preventDefault(e);
			
			var els = new Array();
			var rqClass = Dom.getElementsByClassName("rijks-required",null,form);
			var adClass = Dom.getElementsByClassName("rijks-additional",null,form);
			
			for(var i=0; i<rqClass.length; i++) if(!Dom.hasClass(rqClass[i],"rijks-additional")) els.push(rqClass[i]);
			for(var i=0; i<adClass.length; i++) els.push(adClass[i]);
			
			var acceptedEls = 0;
			
			if(typeof(form.errorList) == "undefined") form.errorList = Dom.getElementsByClassName("errorlist","ul",form)[0];
			
			if(e.type == "submit") form.errorList.innerHTML = "";

			for(var i=0; i<els.length; i++)
			{
				if(rijks.form.validate.getResult(els[i]) == true)
				{
					Dom.removeClass(els[i].parentNode,"err");
					acceptedEls += 1;
				}else
				{
					Dom.addClass(els[i].parentNode,"err");
					if(e.type == "submit") rijks.form.validate.showError(els[i]);
					
					Event.removeListener(form,"keyup");
					Event.removeListener(form,"change");
					Event.on(form,"keyup", rijks.form.validate.run);
					Event.on(form,"change",rijks.form.validate.run);
				};
				
				// anti IE6 render bug, force to render the form again if validation (and so the errorlist if there are errors) is completed
				if (isIE6 && i==els.length-1 && e.type=="submit") 
				{
					Dom.setStyle(form,"display","inline");
					Dom.setStyle(form,"display","block");
				}
			}
			
			if(e.type == "submit" && acceptedEls == els.length) {Dom.setStyle(form.errorList.parentNode,"display","none"); form.submit();}
		},
		
		showError : function(el)
		{
			var currentForm = this.parentForm(el);
			
			// if no title attrbute is found, use the associated label's inner html
			if(!el.title)
			{
				var labels = this.parentForm(el).getElementsByTagName("label");
				for(var i=0; i<labels.length; i++)
				{
					if(labels[i].htmlFor == el.id) el.title = labels[i].innerHTML;
				}
			};
			
			if(typeof(currentForm.errorList) != "undefined")
			{
				if(el.title != "")
				{
					var newNodeLi = document.createElement("li");
					var newNodeA = document.createElement("a");
									
					newNodeA.innerHTML = el.title;
					newNodeA.href = "javascript:rijks.form.validate.setFocus('"+el.id+"');";
					newNodeLi.appendChild(newNodeA);
					currentForm.errorList.appendChild(newNodeLi);
				}
				
				Dom.setStyle(currentForm.errorList.parentNode,"display","block");
				currentForm.errorList.parentNode.scrollIntoView();
			}else 
			{
				el.scrollIntoView();
			}
		},
		
		setFocus : function(id)
		{
			location.hash = id;
			var el = Dom.get(id);
			if(el.tagName == "SELECT") el.focus();
			else el.select();
		},
		
		getResult : function(el)
		{
			if(Dom.hasClass(el,"rijks-additional")) return this.parentForm(el).additional(el);
			
			if(Dom.hasClass(el,"rijks-optional") && el.value.length >= 1) return this.getOptional(el);
			else if(Dom.hasClass(el,"rijks-optional") && el.value.length == 0) return true;
			
			
			if(el.type == "checkbox" || el.type == "radio" || el.tagName == "select") return this.isUgly(el);
			
			// class-specific items validation
				 if(Dom.hasClass(el,"rijks-phone")		&& this.testRegex("rijks-phone",el.value)	)	return true;
			else if(Dom.hasClass(el,"rijks-email")		&& this.testRegex("rijks-email",el.value)	)	return true;
			else if(Dom.hasClass(el,"rijks-zip")		&& this.testRegex("rijks-zip",el.value)	 	)	return true;
			else if(Dom.hasClass(el,"rijks-date")		&& this.testRegex("rijks-date",el.value) 	)	return true;
			else if(Dom.hasClass(el,"rijks-number")		&& this.testRegex("rijks-number",el.value)	)	return true;
			else if(el.type == "radio" 					&& this.testRadio(el) 					 	)	return true;
			else if(!Dom.hasClass(el,"rijks-phone")		&&
					!Dom.hasClass(el,"rijks-email")		&&
					!Dom.hasClass(el,"rijks-zip")		&&
					!Dom.hasClass(el,"rijks-date")		&& rijks.form.validate.testRegex("default",el.value)	) return true;
			else return false;		
		},
		
		getOptional : function(el)
		{
			// class-specific items validation
				 if(Dom.hasClass(el,"rijks-phone")		&& this.testRegex("rijks-phone",el.value)	) 	return true;
			else if(Dom.hasClass(el,"rijks-email")		&& this.testRegex("rijks-email",el.value)	) 	return true;
			else if(Dom.hasClass(el,"rijks-zip"  )		&& this.testRegex("rijks-zip",el.value)	 	) 	return true;
			else if(Dom.hasClass(el,"rijks-date")		&& this.testRegex("rijks-date",el.value) 	) 	return true;
			else if(Dom.hasClass(el,"rijks-number")		&& this.testRegex("rijks-number",el.value)	)	return true;
			else return false;
		},
		
		isUgly : function(el)
		{
			if(el.type == "radio")
			{
				var group = document.getElementsByName(el.name);
				var cnt = -1;
				for (var i=group.length-1; i > -1; i--) {
					
					if (group[i].checked) {cnt = i; i = -1;}
				}
				if (cnt > -1) return true;
				else return false;				
			}
			
			// select items validation
			if(el.tagName == "SELECT" && el.value != "") return true;
			else if(el.tagName == "SELECT" && el.value == "") return false;
			
			// checkbox items validation
			if(el.type == "checkbox" && el.checked) return true;
			else if(el.type == "checkbox" && !el.checked) return false;
		},
		
		testRegex : function(type,val)
		{
			switch(type)
			{
				case "rijks-phone":
					if(val.match(this.regex.phone)) return true;
					else return false;
					break;
				
				case "rijks-email":
					if(val.match(this.regex.email)) return true;
					else return false;
					break;
					
				case "rijks-zip":
					if(val.match(this.regex.zipNL)) return true;
					else if(val.match(this.regex.zipDE)) return true;
					else if(val.match(this.regex.zipBE)) return true;
					else return false;
					break;
				
				case "rijks-date":
					if(val.match(this.regex.date)) return true;
					else return false;
					break;
				
				case "rijks-number":
					if(!isNaN(val)) return true;
					else return false;
					break;
				
				default:
					if(val.length >= 1) return true;
					else return false;
					break;
			};
					
		},
		testRadio : function(el)
		{
			var radio = document.getElementsByName(el.name);
			for(var i=0; i<radio.length; i++){ if(radio[i].checked) return true;}
			return false;
		},
		regex : 
		{
			// you can test the following regular expressions at http://regexlib.com/RESilverlight.aspx
			// validates any e-mail address 
				email	: /^[^@\s<&>]+@([-a-z0-9]+\.)+[a-z]{2,}$/i,
			//validates phone numbers like this: 06 123 456 78 / 0612345678 / 0118 - 123456 / 0101234567 / 030 1234567 / and more
				phone	: /^([\+]{1}|[0]{1}[6]{1}[-\s]*[1-9]{1}[\s]*([0-9]{1}[\s]*){7})|([0]{1}[1-9]{1}[0-9]{1}[0-9]{1}[-\s]*[1-9]{1}[\s]*([0-9]{1}[\s]*){5})|([0]{1}[1-9]{1}[0-9]{1}[-\s]*[1-9]{1}[\s]*([0-9]{1}[\s]*){6})$/,
			//validates zipcodes
				zipNL	: /^([0-9]{4}\s*[a-zA-Z]{2})$/,
				zipDE	: /^([0124678][0-9]{4})$/,
				zipBE	: /^[1-9]{1}[0-9]{3}$/,
			// validates dates like this: dd-mm-yyyy / dd.mm.yyyy (source: http://regexlib.com/REDetails.aspx?regexp_id=762)
				date	: /^(?=\d)(?:(?!(?:(?:0?[5-9]|1[0-4])(?:\.|-|\/)10(?:\.|-|\/)(?:1582))|(?:(?:0?[3-9]|1[0-3])(?:\.|-|\/)0?9(?:\.|-|\/)(?:1752)))(31(?!(?:\.|-|\/)(?:0?[2469]|11))|30(?!(?:\.|-|\/)0?2)|(?:29(?:(?!(?:\.|-|\/)0?2(?:\.|-|\/))|(?=\D0?2\D(?:(?!000[04]|(?:(?:1[^0-6]|[2468][^048]|[3579][^26])00))(?:(?:(?:\d\d)(?:[02468][048]|[13579][26])(?!\x20BC))|(?:00(?:42|3[0369]|2[147]|1[258]|09)\x20BC))))))|2[0-8]|1\d|0?[1-9])([-.\/])(1[012]|(?:0?[1-9]))\2((?=(?:00(?:4[0-5]|[0-3]?\d)\x20BC)|(?:\d{4}(?:$|(?=\x20\d)\x20)))\d{4}(?:\x20BC)?)(?:$|(?=\x20\d)\x20))?((?:(?:0?[1-9]|1[012])(?::[0-5]\d){0,2}(?:\x20[aApP][mM]))|(?:[01]\d|2[0-3])(?::[0-5]\d){1,2})?$/
		}
	};
