/* -----------------------------------------------------------------
// Online Services
//
// Form handling for MKB Online Services
// Generic scripts with dependency on TNT Post framework/scripts
// Make sure the Page object has loaded first or this will fail.
//
// Copyright 2006, TNT Post
----------------------------------------------------------------- */
//FROM GLOBAL
// Dynamic classname handling for objects
// Functions to calculate the position of objects

calculateLeft = function(object) {
	if (object) return object.offsetLeft + calculateLeft(object.offsetParent); 
	else return 0;
}
calculateTop = function(object) {
	if (object) return object.offsetTop + calculateTop(object.offsetParent); 
	else return 0;
}

addClass = function(obj, cName) { 
	if (obj) {
		removeClass(obj,cName); 
		return obj.className += (obj.className.length > 0 ? " " : "") + cName; 
	}
}
removeClass = function(obj, cName) {
	if (obj) {
		return obj.className = obj.className.replace(new RegExp("^" + cName+"\\b\\s*|\\s*\\b" + cName+"\\b",'g'),''); 
	}
}

// Function to fetch objects by classname
getElementsByClassName = function(cName, baseElement) {
	var results = new Array;
	var objs = document.getElementsByTagName("*").length > 0 ? baseElement.getElementsByTagName("*") : baseElement.all;
	if(!objs) objs = baseElement.all;
	for(var i = 0; i < objs.length; i++){
		if(objs[i].className.match(cName)) results[results.length] = objs[i]
	}
	return results;
}

// Tickle the browser to display correctly
tickle = function(){
	addClass(document.getElementsByTagName("body")[0], "tickle");
}

// Function to add event listeners
addEvent = function(obj, evType, fn, ieonly) { 
	if (obj.addEventListener && !ieonly){ /* Mozilla & others */
		obj.addEventListener(evType, fn, false); 
		return true; 
	} else if (obj.attachEvent){ /* IE */
		var r = obj.attachEvent("on"+evType, fn); 
		return r; 
	} else { 
		return false; 
	} 
}

//\FROM GLOBAL

// Set event listeners
addEvent(window, "load", function(){
	window.osform = new OSForm();
});

addEvent(window, "unload", function(){
	if (window.osform) { window.osform.destroy(); }
});

/* -----------------------------------------------------------------
// Main osform object
----------------------------------------------------------------- */

OSForm = function() {
	
	this.sForm = "formMain"; // The name of the form
	this.sAdresXpressUri = "/includes/controls/postcode.aspx";
	
	this.createWarning(); // Init warning message
	this.validationInit(); // Init form validation
	this.fixInfoBoxes(); // Fix infoboxes on IE
	
	var frm = document.getElementById(this.sForm);
	if(frm != null){
		arrOptionalFieldList = getElementsByClassName("os-optional", frm);
		for(i = arrOptionalFieldList.length - 1; i >= 0; i--){
			obj = arrOptionalFieldList[i];
			obj.animator = new Animator(obj);
		}
	}

}

// Helper function to clean up the osform object
OSForm.prototype.destroy = function() {
	
	// Kill objects to prevent memory leaks due to closures. - TODO!

}

/* -----------------------------------------------------------------
// OS form helpers/methods/properties/...
----------------------------------------------------------------- */

OSForm.prototype.goToStep = function(leap){
	this.sForm.NxtPage.value = Number(form.CurPage.value) + leap;
   	button = document.getElementById("btnVerstuur");
  	if(button){
		button.disabled = true;
  	}
	if(leap > 0){
		this.sForm.submitCatcher();
	}else{
		this.sForm.submit();
	}
	return false;
}
		
// Function to fix the mouseover of the infoboxes in IE
OSForm.prototype.fixInfoBoxes = function() {
	var i, aInfobox = getElementsByClassName("popupbox", document);
	if (aInfobox) {
		this.createInfoBox(); // Create a separate infobox
		for (i=0; i<(aInfobox.length); i++) {
			aInfobox[i].onmouseover = function() {
				addClass(this, "popupboxhover");
				osform.showInfoBox(this);
				tickle();
			}
			aInfobox[i].onmouseout=function() {
				removeClass(this, "popupboxhover");
				osform.hideInfoBox();
				tickle();
			}
		}
	}
}
// Infobox div
OSForm.prototype.createInfoBox = function() {
	var oBody = document.getElementsByTagName("body")[0];
	var oInfoBox = document.createElement("div");
	oInfoBox.id = "os-form-popupbox";
	var oInfoBoxMsg = document.createElement("div");
	oInfoBoxMsg.id = "os-form-popupbox-msg";
	oInfoBox.appendChild(oInfoBoxMsg);
	if(document.all){ // IE only iframe
		var oInfoBoxIFrame = document.createElement("iframe");
		oInfoBoxIFrame.id = "os-form-popupbox-iframe";	
		oInfoBoxIFrame.frameBorder = 0;
		oInfoBoxIFrame.scrolling = "no";
		oInfoBoxIFrame.src = "about:blank";
		oInfoBox.appendChild(oInfoBoxIFrame);		
	}
	// Append to body
	oBody.appendChild(oInfoBox);
}
OSForm.prototype.showInfoBox = function(obj) {
	var oInfoBox = document.getElementById("os-form-popupbox");
	if (oInfoBox) {
		var oInfoBoxMsg = document.getElementById("os-form-popupbox-msg");
		var oObjDD = obj.getElementsByTagName("dd")[0];
		var oInfoBoxX = calculateLeft(oObjDD), oInfoBoxY = calculateTop(oObjDD);
		oInfoBox.style.left = oInfoBoxX+"px";
		oInfoBox.style.top  = oInfoBoxY+"px";
		oInfoBoxMsg.innerHTML = oObjDD.innerHTML;
		oInfoBox.style.display = "block";
		oObjDD.style.visibility = "hidden";
	}
}
OSForm.prototype.hideInfoBox = function() {
	var oInfoBox = document.getElementById("os-form-popupbox");
	if (oInfoBox) {
		oInfoBox.style.display = "none";
	}
}

// Function to toggle optional fields on or off.
// Inputargs: 'show/hide', 'field1', ..., 'fieldn'
OSForm.prototype.toggleOptional = function() {
	this.nowarn();
	var i, obj, bstatus, args = this.toggleOptional.arguments;
	if (args[0]) { bstatus = args[0]; }
  	for (i=1; i<(args.length); i++) {
		obj = document.getElementById(args[i]);
		this.container = obj;
		
		if (obj && bstatus == "show") {
			obj.animator.open();
			removeClass(obj, "os-optional");
		}
		else if (obj && bstatus == "hide") {
			obj.animator.close();
			addClass(obj, "os-optional");
		}
		
	}
	// Nudge the browser to display properly
	tickle();
}
OSForm.prototype.optionalFade = function(x) {
	this.container.style.backgroundColor = "rgb("+x+", 236, 240)";
}
OSForm.prototype.optionalFadeDone = function(x) {
	//this.container.style.backgroundColor = "rgb(224, 236, 240)";
}

// Validate a single field (realtime)
OSForm.prototype.validateField = function(obj) {

	if (!window.fieldValues) { return; }
	
	if (window.fieldValues[obj.id]) {
		if (window.fieldValues[obj.id].match("isDate")) { // Check for date
			var msg = eval("this."+window.fieldValues[obj.id]);
		}
		else if (window.fieldValues[obj.id].match("is2FieldPhone")) { // Check for alternate telephonecheck with 2 fields
			var msg = eval("this."+window.fieldValues[obj.id]);
		}
		else if (window.fieldValues[obj.id].match("is2FieldPhoneOptional")) { // Check for alternate telephonecheck with 2 fields
			var msg = eval("this."+window.fieldValues[obj.id]);
		}
		else if (window.fieldValues[obj.id].match("isValidPeriod")) { // Check for alternate telephonecheck with 2 fields
			var msg = eval("this."+window.fieldValues[obj.id]);
		}
		else if (window.fieldValues[obj.id].match("isValidPeriodOptional")) { // Check for alternate telephonecheck with 2 fields
			var msg = eval("this."+window.fieldValues[obj.id]);
		}
		else if (window.fieldValues[obj.id].match("isValidDate")) { // Check for alternate telephonecheck with 2 fields
			var msg = eval("this."+window.fieldValues[obj.id]);
		}
		else if (window.fieldValues[obj.id].match("isVacationPeriod")) { // Check for alternate telephonecheck with 2 fields
			var msg = eval("this."+window.fieldValues[obj.id]);
		}
		else if (window.fieldValues[obj.id].match("isValidVacationPeriod")) { // Check for alternate telephonecheck with 2 fields
			var msg = eval("this."+window.fieldValues[obj.id]);
		}
		else if (window.fieldValues[obj.id].match("isVacationPeriodOptional")) { // Check for alternate telephonecheck with 2 fields
			var msg = eval("this."+window.fieldValues[obj.id]);
		}
		else if (window.fieldValues[obj.id].match("isValidVacationPeriodOptional")) { // Check for alternate telephonecheck with 2 fields
			var msg = eval("this."+window.fieldValues[obj.id]);
		}
		else if (window.fieldValues[obj.id].match("isValidBirthdate")) { // Check for alternate telephonecheck with 2 fields
			var msg = eval("this."+window.fieldValues[obj.id]);
		}
				else if (window.fieldValues[obj.id].match("isValidBirthdate16")) { // Check for alternate telephonecheck with 2 fields
			var msg = eval("this."+window.fieldValues[obj.id]);
		}
		else if (window.fieldValues[obj.id].match("isCheckboxChecked")) { // Check for alternate telephonecheck with 2 fields
			var msg = eval("this."+window.fieldValues[obj.id]);
		}
		else if (window.fieldValues[obj.id].match("is2FieldPhone2FieldOption")) { // Check for alternate telephonecheck with 2 fields
			var msg = eval("this."+window.fieldValues[obj.id]);
		}
		else if (window.fieldValues[obj.id].match("is2FieldPhoneReallyOptional")) { // Check for alternate telephonecheck with 2 fields
			var msg = eval("this."+window.fieldValues[obj.id]);
		}
		else if (window.fieldValues[obj.id].match("checkNVSPWeek")) { // Check for alternate telephonecheck with 2 fields
		            var msg = eval("this." + window.fieldValues[obj.id]);
		}
		else if (window.fieldValues[obj.id].match("isValidDateHistory")) { // Check for alternate telephonecheck with 2 fields
		            var msg = eval("this." + window.fieldValues[obj.id]);
		}
	//	else if (window.fieldValues[obj.id].match("isBankaccountOptional")) { // Check for alternate telephonecheck with 2 fields
	//		var msg = eval("this."+window.fieldValues[obj.id]);
	//	}
		else { // Validate expression
			var msg = eval("this."+window.fieldValues[obj.id]+"(obj)");
		}
		if (msg) {
			this.warn(obj, msg);
		}
		else {
			this.nowarn();
		}
	}
}

OSForm.prototype.isRequired = function(obj) { // Required field
	if (obj.type != "checkbox") {
		if (obj.value.length < 1) { return "Dit is een verplicht veld."; }
	}
	else if (obj.type == "checkbox") {
		if (!obj.checked) { return "Geef aan dat u akkoord gaat met de voorwaarden."; }
	}
}
OSForm.prototype.isNumeric = function(obj) { // Numeric field
	if (!obj.value.match(/^\d+$/)) { 
		return "Vul een getal in."; 
	}
}
OSForm.prototype.isBezorgNr = function(obj) { // Numeric field
	if (!obj.value.match(/^[0-9]{8}$/)) { 
		return "Vul een bezorgersnummer in van 8 cijfers."; 
	}
}
OSForm.prototype.isKvKnr = function(obj) { // KvK number field (8 digit)
	if (!obj.value.match(/^[0-9]{8}$/)) { 
		return "Vul een KvK-nummer van minimaal 8 cijfers in."; 
	}
}
OSForm.prototype.isPostcode = function(obj) { // Postcode field
	if (!obj.value.match(/^[1-9]{1}[0-9]{3} ?[A-Za-z]{2}$/)) { 
		return "Vul een postcode van 4 cijfers en 2 letters in."; 
	}
}
OSForm.prototype.isStreetname = function(obj) { // Streetname field
	if (obj.value.length < 1 || obj.value.match(/automatisch/)) { 
		return "Vul een geldige straatnaam in."; 
	}
}
OSForm.prototype.isCityname = function(obj) { // Cityname field
	if (obj.value.length < 1 || obj.value.match(/automatisch/)) { 
		return "Vul een geldige plaatsnaam in.";
	}
}
OSForm.prototype.isPhone = function(obj) { // Phone field
	if (!obj.value.match(/([0]{1}[6]{1}[-\s]*([0-9]{1}[\s]*){8})|([0]{1}[1-9]{1}[0-9]{2}[-\s]*([0-9]{1}[\s]*){6})|([0]{1}[1-9]{1}[0-9]{1}[-\s]*([0-9]{1}[\s]*){7})/)) { 
		return "Vul een telefoonnummer van minimaal 10 cijfers in."; 
	}
}
OSForm.prototype.checkNVSPWeek = function(obj) {
    var sMessage;
    var oDate;
    var d = new Date();
    var dDate = new Date()
    var datefield = document.getElementById("cgdatum").value
    var temp = parseInt(datefield.substring(3,5))
    dDate.setFullYear(datefield.substring(6,10), temp-1 , datefield.substring(0,2)) 
    
    sMessage = "";
    var opType = document.getElementById("opsoort").value;
    if (opType == "A" || opType == "B" || opType == "C") {
        if (obj.value == "") {
            sMessage = "Dit is een verplicht veld";
        } else if (dDate.getDay() >0 && dDate.getDay() < 4 && obj.value == "Pakket van deze week") {
            sMessage = "Bezorging is gaande";
        }
    }
    return sMessage;
}
OSForm.prototype.checkNVSPDatum = function(obj) {
    var sMessage;
    var oDate;
    sMessage = "";
    var opType = document.getElementById("opsoort").value;
    if (opType == "B" || opType == "C") {

        if (obj.value == "") {
            sMessage = "Dit is een verplicht veld";
        } else {
            var aDate = obj.value.split('-');
            if (aDate.length != 3) {
                sMessage = "Dit is een ongeldige datum";
            } else {
                if (aDate[0] > 31 || aDate[0] < 1 || aDate[1] > 12 || aDate[1] < 1 || aDate[2].length != 4) {
                    sMessage = "Dit is een ongeldige datum";
                } else {
                    var d = new Date();
                    oDate = new Date(aDate[2], aDate[1] - 1, aDate[0]);
                    if (oDate > d) {
                        sMessage = "Datum kan niet in de toekomst liggen";
                    } else {
                        var sWeek
                        sWeek = document.getElementById("cgweek").value;
                        if (sWeek == "") {
                            sMessage = "Kies een week";
                        }
                        else if (opType == "B") { //te laat bezorgd
                            if (sWeek == "Pakket van deze week") {
                            }
                            else {
                            }



                            var dMin
                            var dMax
                            if (sWeek == "Pakket van deze week") {
                                //Alleen do~zo van deze week mag als invoer mits het in het verleden ligt
                                //Datum van vandaag - Dag van de week = begin van de week - 4 is woensdag
                                //is de datum een donderdag ~ zondag
                                if (oDate.getDay() < 4 && oDate.getDay() != 0) {
                                    sMessage = "Dit is een ongeldige datum (do~wo)";
                                } else {
                                    d = new Date();
                                    dMin = new Date(d.setDate(d.getDate() - parseInt(d.getDay()) + 3));

                                    d = new Date();
                                    dMax = new Date(d.setDate(d.getDate() - parseInt(d.getDay()) + 7));
                                      //alert ("Min:"+dMin);
                                      //alert ("Max:"+dMax);
                                    if (!(dMin < oDate && dMax > oDate)) {
                                        sMessage = "Dit is een ongeldige datum (do~wo van deze week)";
                                    }
                                }
                            }
                            else {
                                // 7 dagen vanaf vorige woensdag
                                d = new Date();
                                dMin = new Date(d.setDate(d.getDate() - parseInt(d.getDay()) - 4));
                                d = new Date();
                                dMax = new Date(d.setDate(d.getDate() - parseInt(d.getDay()) + 3));

                                if (!(dMin < oDate && dMax > oDate)) {
                                    sMessage = "Dit is een ongeldige datum (do~wo)";
                                }
                            }
                            /*var dMin
                            var dMax
                            var d = new Date();


                            dMin = new Date(d.setDate(d.getDate() - d.getDay()));
                            dMax = new Date();
                            dMax.setDate(dMin.getDate() + 7);

                            //is de datum van deze week                         
                            if (dMin > oDate || dMax < oDate) {
                            sMessage = "Dit is een ongeldige datum (mag alleen in huidige week vallen)";
                            }
                            */

                        }

                        //Te vroeg bezorgd
                        if (opType == "C") {


                            //is de datum een donderdag ~ zondag
                            if (oDate.getDay() < 4 && oDate.getDay() != 0) {
                                sMessage = "Dit is een ongeldige datum (do~zo)";
                            } else { //is de datum van deze week
                                var dMin
                                var dMax
                                if (sWeek == "Pakket van deze week") {
                                    //Alleen do~zo van vorige week mag als invoer

                                    //Datum van vandaag - Dag van de week = begin van de week - 4 is woensdag
                                    d = new Date();
                                    dMin = new Date(d.setDate(d.getDate() - parseInt(d.getDay()) - 4));

                                    d = new Date();
                                    dMax = new Date(d.setDate(d.getDate() - parseInt(d.getDay())));

                                    if (!(dMin < oDate && dMax > oDate)) {
                                        sMessage = "Dit is een ongeldige datum (do~zo van vorige week)";
                                    }
                                }
                                else {
                                    // Alleen do~zo van 2 weken geleden mag als invoer
                                    dMin = new Date(d.setDate(d.getDate() - parseInt(d.getDay()) - 11));
                                    var d = new Date();
                                    dMax = new Date(d.setDate(d.getDate() - parseInt(d.getDay())) - 7);

                                    //alert(dMin);
                                    //alert(dMax);

                                    if (!(dMin < oDate && dMax > oDate)) {
                                        sMessage = "Dit is een ongeldige datum (do~zo van 2 weken geleden)";
                                    }
                                }

                                /*
                                //is de datum van deze week                         
                                if (dMin > oDate || dMax < oDate) {
                                sMessage = "Dit is een ongeldige datum (mag alleen in vorige week vallen)";
                                }*/
                            }
                        }
                    }

                    /*var xDate = oDate
                    var d = new Date();
                    xDate = new Date(d.setDate(d.getDate() - 7 - d.getDay()));
                    if (xDate > oDate) {
                    sMessage = "Deze datum is ongeldig!";
                    }*/
                }
            }
        }



    }
    return sMessage;
}
OSForm.prototype.checkNVSPSticker = function(obj) {
    var sMessage;
    sMessage = "";
    var opType = document.getElementById("opsoort").value;
    if (opType == "K") {
        if (obj.value == "") {
            sMessage = "Dit is een verplicht veld";
        }
    }
    return sMessage;
}		
OSForm.prototype.is2FieldPhone = function(sZoneNumber, sTelephoneNumber) { // Phone field
	var oZoneNumber = document.getElementById(sZoneNumber);
	var oTelephoneNumber = document.getElementById(sTelephoneNumber);
	var telnr = oZoneNumber.value + oTelephoneNumber.value + "";
	if (telnr.length != 10 || !telnr.match(/([0]{1}[6]{1}[-\s]*([0-9]{1}[\s]*){8})|([0]{1}[1-9]{1}[0-9]{2}[-\s]*([0-9]{1}[\s]*){6})|([0]{1}[1-9]{1}[0-9]{1}[-\s]*([0-9]{1}[\s]*){7})/)) { 
		return "Vul een telefoonnummer van 10 cijfers in."; 
	}
}
OSForm.prototype.is2FieldPhoneOptional = function(sZoneNumber, sTelephoneNumber) { // Phone field
	var oZoneNumber = document.getElementById(sZoneNumber);
	var oTelephoneNumber = document.getElementById(sTelephoneNumber);
	var telnr = oZoneNumber.value + oTelephoneNumber.value + "";
	if ((telnr.length != 10 || !telnr.match(/([0]{1}[6]{1}[-\s]*([0-9]{1}[\s]*){8})|([0]{1}[1-9]{1}[0-9]{2}[-\s]*([0-9]{1}[\s]*){6})|([0]{1}[1-9]{1}[0-9]{1}[-\s]*([0-9]{1}[\s]*){7})/))) { 
		if(document.getElementById('pimobile_nr').value==""){
		      return "Vul een telefoonnummer van 10 cijfers in."; 
		}
	}
}
OSForm.prototype.is2FieldPhoneReallyOptional = function(sZoneNumber, sTelephoneNumber) { // Phone field
	var oZoneNumber = document.getElementById(sZoneNumber);
	var oTelephoneNumber = document.getElementById(sTelephoneNumber);
	var telnr = oZoneNumber.value + oTelephoneNumber.value + "";
	if (telnr.length >0 && (telnr.length != 10 || !telnr.match(/([0]{1}[6]{1}[-\s]*([0-9]{1}[\s]*){8})|([0]{1}[1-9]{1}[0-9]{2}[-\s]*([0-9]{1}[\s]*){6})|([0]{1}[1-9]{1}[0-9]{1}[-\s]*([0-9]{1}[\s]*){7})/))) { 
		return "Vul een telefoonnummer van 10 cijfers in."; 
	}
}
OSForm.prototype.is2FieldPhone2FieldOption = function(sZoneNumber, sTelephoneNumber, sZoneNumber2, sTelephoneNumber2) { // Phone field
	var bValid = true;
	var oZoneNumber = document.getElementById(sZoneNumber);
	var oTelephoneNumber = document.getElementById(sTelephoneNumber);
	var oZoneNumber2 = document.getElementById(sZoneNumber2);
	var oTelephoneNumber2 = document.getElementById(sTelephoneNumber2);
	var telnr = oZoneNumber.value + oTelephoneNumber.value + "";
	var telnr2 = oZoneNumber2.value + oTelephoneNumber2.value + "";
	if ((telnr.length != 10 || !telnr.match(/([0]{1}[6]{1}[-\s]*([0-9]{1}[\s]*){8})|([0]{1}[1-9]{1}[0-9]{2}[-\s]*([0-9]{1}[\s]*){6})|([0]{1}[1-9]{1}[0-9]{1}[-\s]*([0-9]{1}[\s]*){7})/)) && (telnr2.length != 10 || (oTelephoneNumber2.value.length > 0 && !telnr2.match(/([0]{1}[6]{1}[-\s]*([0-9]{1}[\s]*){8})|([0]{1}[1-9]{1}[0-9]{2}[-\s]*([0-9]{1}[\s]*){6})|([0]{1}[1-9]{1}[0-9]{1}[-\s]*([0-9]{1}[\s]*){7})/)))) { 
		bValid = false;
	}
	if (!bValid) {
		return "Vul minimaal 1 geldig telefoonnummer in."; 
	}
}
OSForm.prototype.isFax = function(obj) { // Fax field
	if (!obj.value.match(/([0]{1}[6]{1}[-\s]*([0-9]{1}[\s]*){8})|([0]{1}[1-9]{1}[0-9]{2}[-\s]*([0-9]{1}[\s]*){6})|([0]{1}[1-9]{1}[0-9]{1}[-\s]*([0-9]{1}[\s]*){7})/)) {
		return "Vul een faxnummer van minimaal 10 cijfers in."; 
	}
}
OSForm.prototype.isEmail = function(obj) { // Email field
	if (!obj.value.match(/^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/)) {
		return "Vul een geldig e-mailadres in."; 
	}
}
OSForm.prototype.isEmailOptional = function(obj) { // Email field
	if (obj.value.length > 0 && !obj.value.match(/^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/)) {
		return "Vul een geldig e-mailadres in."; 
	}
}
OSForm.prototype.isBankaccount = function(obj) { // Bank or Giro field
	var bValid = false, nVal = obj.value.replace(/\D/g, "");
	if (nVal > 0 && nVal < 100000000) { // Giro (below 100.000.000)
		bValid = true;
	}
	else if (nVal.length < 11 && nVal > 100000000) { // Bank (11-proef)
		var nSum = 0;
		for (var i = 0; i < nVal.length; i++) {
			nSum += nVal.charAt(i) * (nVal.length-i);
		}
		if (nSum % 11 == 0) {
			bValid = true;
		}
	}
	if (!bValid) { 
		return "Vul een geldig rekeningnummer in."; 
	}
}
OSForm.prototype.isBankaccountOptional = function(obj) { // Bank or Giro field
	    var bValid = false, nLength = obj.value.length, nVal = obj.value.replace(/\D/g, "");
	    if (!nLength > 0) {
	        bValid = true;
	    }
	    else if (nVal > 0 && nVal < 100000000) { // Giro (below 100.000.000)
		    bValid = true;
	    }
	    else if (nVal.length < 11 && nVal > 100000000) { // Bank (11-proef)
		    var nSum = 0;
		    for (var i = 0; i < nVal.length; i++) {
			    nSum += nVal.charAt(i) * (nVal.length-i);
		    }
		    if (nSum % 11 == 0) {
			    bValid = true;
		    }
	    }
	
	if (!bValid) { 
	    return "Vul een geldig rekeningnummer in."; 
	}
}
OSForm.prototype.isDate = function(sDay, sMonth, sYear, bFuture, aFutureDate) { // Is it a valid (future) date?
	var bValid = false;
	var oDay   = document.getElementById(sDay);
	var oMonth = document.getElementById(sMonth);
	var oYear  = document.getElementById(sYear);
	if ((!isNaN(oDay.value) && oDay.value > 0 && oDay.value <= 31)
		&& (!isNaN(oMonth.value) && oMonth.value > 0 && oMonth.value <= 12) 
		&& (!isNaN(oYear.value) && oYear.value.length > 3)) {
		var dToday = new Date(), dDate = new Date();
		dDate.setFullYear(oYear.value, oMonth.value-1, oDay.value);
		if (aFutureDate) { dToday.setFullYear(aFutureDate[0], aFutureDate[1]-1, aFutureDate[2]); }
		// Date is valid?
		if (oDay.value == dDate.getDate()
			&& oMonth.value == dDate.getMonth()+1
			&& oYear.value == dDate.getFullYear()) {
			bValid = true;
		}
		// Date is valid future?
		if (bFuture && dToday >= dDate) {
			bValid = false;
		}
	}
	if (bFuture && !bValid) {
		return "Vul een geldige datum, 3 weken in de toekomst, in. Neem anders contact op met NetwerkVSP.";
	}
	else if (!bValid) {
		return "Vul een geldige datum in.";
	}
}
OSForm.prototype.isValidBirthdate = function(sDate, sMinimumDate){
	var oDate   = document.getElementById(sDate);
    if(!oDate.value.match(/^[0-9]{1,2}[-\s]{1}[0-9]{1,2}[-\s]{1}[0-9]{2,4}$/)){
        return "Vul een geldige geboortedatum in dd-mm-jjjj";
    }
	var sMessage = this.isValidDate(sDate, sMinimumDate);
	if(sMessage.length > 0){
		sMessage = "Als bezorger of vervanger moet je minimaal 13 jaar oud zijn.";
	}
	return sMessage;
}
OSForm.prototype.isValidBirthdate16 = function(sDate, sMinimumDate){
	var oDate   = document.getElementById(sDate);
     if(!oDate.value.match(/^[0-9]{1,2}[-\s]{1}[0-9]{1,2}[-\s]{1}[0-9]{2,4}$/)){
        return "Vul een geldige geboortedatum in dd-mm-jjjj";
    }
    else {
	    var sMessage = this.isValidDate(sDate, sMinimumDate);
	    if(sMessage.length > 0){
		    sMessage = "Als bezorger of vervanger moet u minimaal 16 jaar oud zijn.";
	    }
	    return sMessage;
    }
}
OSForm.prototype.isValidDate = function(sDate, sMinimumDate){
	var sMessage = "";
	var oDate   = document.getElementById(sDate);
	var dDate = this.parseDate(oDate.value);
	var dMinimumDate = this.parseDate(sMinimumDate);
	if(dDate > dMinimumDate){
		sMessage = "U heeft geen geldige datum opgegeven.";
	}
	return sMessage;
	
}

OSForm.prototype.isValidDateOptional = function(sDate, sMinimumDate){
	if(sDate.length > 0){
		sMessage = this.isValidDate(sDate, sMinumumDate);
	}
	return sMessage;
	
}

OSForm.prototype.isDateOptional = function(sDay, sMonth, sYear, bFuture, aFutureDate) { // Is it a valid (future) date? Optionally!
	var oDay   = document.getElementById(sDay);
	var oMonth = document.getElementById(sMonth);
	var oYear  = document.getElementById(sYear);
	if (oDay.value.length > 0 || oMonth.value.length > 0 || oYear.value.length > 0) {
		return this.isDate(sDay, sMonth, sYear, bFuture, aFutureDate);
	}
}

OSForm.prototype.isDateOptionalAfterStartDate = function(sEndDay, sEndMonth, sEndYear, sDay, sMonth, sYear, sDays) { // Is it a valid (future) date? Optionally!
	var sMessage = "";
	var oDay   = document.getElementById(sDay);
	var oMonth = document.getElementById(sMonth);
	var oYear  = document.getElementById(sYear);
	var oEndDay   = document.getElementById(sEndDay);
	var oEndMonth = document.getElementById(sEndMonth);
	var oEndYear  = document.getElementById(sEndYear);
	if (oEndDay.value.length > 0 || oEndMonth.value.length > 0 || oEndYear.value.length > 0) {
		if (oDay.value.length > 0 || oMonth.value.length > 0 || oYear.value.length > 0) {
			var aFutureDate = new Array(oYear.value, oMonth.value, oDay.value);
			sMessage = this.isDate(sEndDay, sEndMonth, sEndYear, true, aFutureDate);
		}else{
			sMessage = "Geen geldige startdatum opgegeven.";
		}
	}
	return sMessage;
}

OSForm.prototype.isDateAfterStartDate = function(sEndDay, sEndMonth, sEndYear, sDay, sMonth, sYear, sDays) { // Is it a valid (future) date? Optionally!
	var sMessage = "";
	var oDay   = document.getElementById(sDay);
	var oMonth = document.getElementById(sMonth);
	var oYear  = document.getElementById(sYear);
	var oEndDay   = document.getElementById(sEndDay);
	var oEndMonth = document.getElementById(sEndMonth);
	var oEndYear  = document.getElementById(sEndYear);
	if (oDay.value.length > 0 || oMonth.value.length > 0 || oYear.value.length > 0) {
		var aFutureDate = new Array(oYear.value, oMonth.value, oDay.value);
		sMessage = this.isDate(sEndDay, sEndMonth, sEndYear, true, aFutureDate);
	}else{
		sMessage = "Geen geldige startdatum opgegeven.";
	}
	return sMessage;
}

OSForm.prototype.isValidPeriod = function(sStartDate, sEndDate, sValidStartDate, sDays) { // Is it a valid (future) period?
	var sMessage = "";
	var oStartDate = document.getElementById(sStartDate);
	var oEndDate = document.getElementById(sEndDate);
	var dStartDate;
	var dEndDate;
	var dValidStartDate = new Date();
	var dValidEndDate;

	if(sDays == null){
		sDays = 0;
	}
	if (sValidStartDate != "") {
		dValidStartDate = this.parseDate(sValidStartDate);
	}
	if(oStartDate.value.match(/^[0-9]{1,2}[-\s]{1}[0-9]{1,2}[-\s]{1}[0-9]{4}$/) && oEndDate.value.match(/^[0-9]{1,2}[-\s]{1}[0-9]{1,2}[-\s]{1}[0-9]{4}$/)){
		if (oStartDate.value.length > 0 && oEndDate.value.length > 0) {
			dStartDate = this.parseDate(oStartDate.value);
			dEndDate = this.parseDate(oEndDate.value);
			if(dStartDate > dValidStartDate){
				dValidEndDate = new Date(dStartDate + (sDays*24*60*60*1000));
				if(dEndDate < dValidEndDate.getTime()){
					sMessage = "Geen geldige einddatum opgegeven.";
				}
			}else{
				sMessage = "Geen geldige startdatum opgegeven.";
			}
		}else{
			sMessage = "Geen geldige datum opgegeven (dd-mm-jjjj).";
		}		
  }else{
    sMessage = "Geen geldige datum opgegeven (dd-mm-jjjj).";
  }
  return sMessage;
}



OSForm.prototype.isValidVacationPeriod = function(sStartDate, sEndDate, sValidStartDateBegin, sValidStartDateEnd, sDays) { // Is it a valid (future) period?
	var sMessage = "";
	var oStartDate = document.getElementById(sStartDate);
	var oEndDate = document.getElementById(sEndDate);
	var dStartDate;
	var dEndDate;
	var dValidStartDate = new Date();
	var dValidEndDate;

	if(sDays == null){
		sDays = 0;
	}
	sDays = sDays + 1;
	if (sValidStartDateBegin != "") {
		dValidStartDateBegin = this.parseDate(sValidStartDateBegin);
	}
	if (sValidStartDateEnd != "") {
		dValidStartDateEnd = this.parseDate(sValidStartDateEnd);
	}
	if (oStartDate.value.length > 0 && oEndDate.value.length > 0) {
		dStartDate = this.parseDate(oStartDate.value);
		dEndDate = this.parseDate(oEndDate.value);
		if(dStartDate < dEndDate){
      if(dStartDate < dValidStartDateEnd ){
        if(dStartDate > dValidStartDateBegin && dEndDate < dValidStartDateEnd ){
          dValidEndDate = new Date(dStartDate + (sDays*24*60*60*1000));
          if(dEndDate > dValidEndDate.getTime()){
            sMessage = "Je gaat langer dan 6 weken op vakantie. Neem telefonisch contact op met Bezorgersservice.";
          }
        }else{
          sMessage = "Geef alleen je plannen door van juni t/m september. Andere plannen? Neem telefonisch contact op met Bezorgersservice.";
        }
      }else{
        sMessage = "Je moet een begindatum opgeven tussen 1 juni en 30 september.";
      }
    }else{
      sMessage = "De einddatum ligt voor de begindatum.";
    }
      
	}else{
		sMessage = "Geen geldige data opgegeven.";
	}
	return sMessage;
}

OSForm.prototype.isValidVacationPeriodOptional = function(sStartDate, sEndDate, sValidStartDateBegin, sValidStartDateEnd, sDays) { // Is it a valid (future) period?
  sMessage = "";
	var oStartDate = document.getElementById(sStartDate);
	var oEndDate = document.getElementById(sEndDate);
	if(oStartDate.value.length > 0 && oEndDate.value.length == 0){
    sMessage = "Geen geldige einddatum";
	} else if(oStartDate.value.length == 0 && oEndDate.value.length > 0){
    sMessage = "Geen geldige begindatum";
	}else if(oStartDate.value.length > 0 && oEndDate.value.length > 0){
    sMessage = this.isValidVacationPeriod(sStartDate, sEndDate, sValidStartDateBegin, sValidStartDateEnd, sDays)
  }
	return sMessage;
}


OSForm.prototype.isVacationPeriod = function(sStartDate, sEndDate){
	var sMessage = "";
	var oStartDate = document.getElementById(sStartDate);
	var oEndDate = document.getElementById(sEndDate);

	if (oStartDate.value != ""){
		if (oEndDate.value != ""){
			var dStartDate = new Date(this.parseDate(oStartDate.value));
			var dEndDate = new Date(this.parseDate(oEndDate.value));
			
			var dToday = new Date();
			if(dStartDate.getYear() != dToday.getYear() || (dStartDate.getMonth() != 6 && dStartDate.getMonth() != 7 && dStartDate.getMonth() != 8)){
				sMessage = "Uw heeft geen geldige startdatum opgegeven. Uw startdatum moet in Juli, Augustus of September voorkomen van " + (dToday.getYear() + 1900);
			}else
			if(dEndDate.getYear() != dToday.getYear() || (dEndDate.getMonth() != 6 && dEndDate.getMonth() != 7 && dEndDate.getMonth() != 8)){
				sMessage = "Uw heeft geen geldige einddatum opgegeven. Uw einddatum moet in Juli, Augustus of September voorkomen van " + (dToday.getYear() + 1900);
			}else
			if(dEndDate < dStartDate){
				sMessage = "Geen geldige einddatum opgegeven. Einddatum moet na startdatum komen.";
			}
		}else{
			sMessage = "Geen geldige einddatum opgegeven.";
		}
	}else{
		sMessage = "Je vakantie begint binnen 3 weken. Je kunt je vakantie alleen nog telefonisch doorgeven."
	}
	return sMessage;
}


OSForm.prototype.isVacationPeriodOptional = function(sStartDate, sEndDate){
	var sMessage = "";
	var oStartDate = document.getElementById(sStartDate);
	var oEndDate = document.getElementById(sEndDate);
	if (oStartDate.value != "" || oEndDate.value != ""){
		sMessage = this.isVacationPeriod(sStartDate, sEndDate);
	}
	return sMessage;
}

OSForm.prototype.parseDate = function(sDate){
	arrDate = sDate.split("-");
	dtReturnDate = new Date();
	dtReturnDate = dtReturnDate.setFullYear(arrDate[2], arrDate[1] - 1, arrDate[0])
	return dtReturnDate;
}


OSForm.prototype.isValidPeriodOptional = function(sStartDate, sEndDate, sValidStartDate, sDays) { // Is it a valid (future) period? Optionally!
	var sMessage = "";
	var oStartDate = document.getElementById(sStartDate);
	var oEndDate = document.getElementById(sEndDate);
	if (oStartDate.value.length > 0 || oEndDate.value.length > 0) {
		sMessage = this.isValidPeriod(sStartDate, sEndDate, sValidStartDate, sDays);
	}
	return sMessage;
}
OSForm.prototype.isRadioChecked = function(obj) { // Radio checked
	var i, bChecked = false;
	for (i=0; i < obj.length; i++) { 
		if (obj[i].checked) { bChecked = true; }
	}
	if (!bChecked) { return "Er is nog geen keuze gemaakt."; }
	
}
OSForm.prototype.isCheckboxChecked = function() { // Checkbox checked
	var args, i, obj, bChecked = false;
	args = this.isCheckboxChecked.arguments;
	for (i=0; i < args.length; i++) { 
		obj = document.getElementById(args[i]);
		if (obj.checked) { bChecked = true; }
	}
	if (!bChecked) { return "Er is nog geen 1 of meer keuzes gemaakt."; }
}
OSForm.prototype.validationInit = function() {

	if (!window.fieldValues) { return; }
	
	var myForm = document.getElementById(this.sForm);

	if (myForm) {
		myForm.submitCatcher = function() { // Custom submit catcher
			
			var sKey, ofield, msg, bDoSubmit = true;
			osform.nowarn();
			
			// Loop through required fields
			for (sKey in window.fieldValues) {
				
				// Check field values
				ofield = document.getElementById(sKey);
				if (ofield 
						&& !ofield.parentNode.style.display.match("none") 
						&& !ofield.parentNode.parentNode.style.display.match("none") 
						&& !ofield.parentNode.parentNode.parentNode.style.display.match("none") 
						&& window.fieldValues[sKey] != "isRadioChecked") {
					if (window.fieldValues[sKey].match("isDate")) { // Check for date
						msg = eval("osform."+window.fieldValues[sKey]);
					} else if (window.fieldValues[sKey].match("isDateOptional")) { // Check for date
						msg = eval("osform."+window.fieldValues[sKey]);
					} else if (window.fieldValues[sKey].match("isDateOptionalAfterStartDate")) { // Check for date
						msg = eval("osform."+window.fieldValues[sKey]);
					} else if (window.fieldValues[sKey].match("isDateAfterStartDate")) { // Check for date
						msg = eval("osform."+window.fieldValues[sKey]);
					} else if (window.fieldValues[sKey].match("isValidPeriod")) { // Check for period
						msg = eval("osform."+window.fieldValues[sKey]);
					} else if (window.fieldValues[sKey].match("isValidPeriodOptional")) { // Check for period
						msg = eval("osform."+window.fieldValues[sKey]);
					} else if (window.fieldValues[sKey].match("isValidDate")) { // Check for date
						msg = eval("osform."+window.fieldValues[sKey]);
					} else if (window.fieldValues[sKey].match("isVacationPeriod")) { // Check for date
						msg = eval("osform."+window.fieldValues[sKey]);
					} else if (window.fieldValues[sKey].match("isVacationPeriodOptional")) { // Check for date
						msg = eval("osform."+window.fieldValues[sKey]);
					} else if (window.fieldValues[sKey].match("isValidVacationPeriod")) { // Check for date
						msg = eval("osform."+window.fieldValues[sKey]);
					} else if (window.fieldValues[sKey].match("isValidVacationPeriodOptional")) { // Check for date
						msg = eval("osform."+window.fieldValues[sKey]);
					} else if (window.fieldValues[sKey].match("isValidBirthdate")) { // Check for date
						msg = eval("osform."+window.fieldValues[sKey]);
					} else if (window.fieldValues[sKey].match("is2FieldPhone")) { // Check for date
						msg = eval("osform."+window.fieldValues[sKey]);
					} else if (window.fieldValues[sKey].match("is2FieldPhone2FieldOption")) { // Check for date
						msg = eval("osform."+window.fieldValues[sKey]);
					} else if (window.fieldValues[sKey].match("isCheckboxChecked")) { // Check for date
						msg = eval("osform."+window.fieldValues[sKey]);
					} else { // Validate expression
						msg = eval("osform."+window.fieldValues[sKey]+"(ofield)");
					}
					if (msg) { 
						osform.warn(ofield, msg);
						bDoSubmit = false;
						ofield.focus();
						return false;
					}
				}
				// Check radios (need different handling)
				else if (window.fieldValues[sKey] == "isRadioChecked") {
					var oRadioGroup = eval("document."+myForm.name+"."+sKey);
					if (oRadioGroup 
							&& !oRadioGroup[0].parentNode.className.match("os-optional") 
							&& !oRadioGroup[0].parentNode.parentNode.className.match("os-optional")
							&& !oRadioGroup[0].parentNode.parentNode.parentNode.className.match("os-optional")) {
						msg = eval("osform.isRadioChecked(oRadioGroup)");
						if (msg) {
							osform.warn(oRadioGroup[oRadioGroup.length-1], msg);
							bDoSubmit = false;
							return false;
						}
					}
				}

			}
	
			// Do submit!
			if (bDoSubmit) { this.submit(); }
			
		}
	}

}

// Form validation warning
OSForm.prototype.createWarning = function() {

	var oBody = document.getElementsByTagName("body")[0];
	var oWarning = document.createElement("div");
	oWarning.id = "os-form-warning";
	var oWarningContainer = document.createElement("div");
	oWarningContainer.id = "os-form-warning-container";
	var oWarningArrow = document.createElement("span");
	oWarningArrow.id = "os-form-warning-arrow";
	var oWarningText = document.createTextNode("Let op: ");
	var oWarningMsg = document.createElement("span");
	oWarningMsg.id = "os-form-warning-msg";
	
	// Construct messagenode
	oWarningContainer.appendChild(oWarningArrow);
	oWarningContainer.appendChild(oWarningText);
	oWarningContainer.appendChild(oWarningMsg);
	oWarning.appendChild(oWarningContainer)
	oWarning._status = null;
	
	if(document.all){ // IE only iframe
		var oWarningIFrame = document.createElement("iframe");
		oWarningIFrame.id = "os-form-warning-iframe";	
		oWarningIFrame.frameBorder = 0;
		oWarningIFrame.scrolling = "no";
		//oWarningIFrame.src = "javascript:false;";
		oWarningIFrame.src = "about:blank";
		oWarning.appendChild(oWarningIFrame);		
	}
	
	// Append to body
	oBody.appendChild(oWarning);

}
OSForm.prototype.warn = function(obj, msg) {
	
	var oWarning = document.getElementById("os-form-warning");
	if (oWarning && !oWarning._status) {
		var oWarningMsg = document.getElementById("os-form-warning-msg");
		var oWarningX   = calculateLeft(obj), oWarningY = calculateTop(obj) + 19;
		oWarning.style.left = oWarningX+"px";
		oWarning.style.top  = oWarningY+"px";
		oWarningMsg.innerHTML = msg;
		oWarning.style.display = "block";
		oWarning._status = "showing";
		setTimeout("window.osform.nowarn()", 5000); // Remove warning after x milliseconds
	}

}
OSForm.prototype.nowarn = function() {

	var oWarning = document.getElementById("os-form-warning");
	if (oWarning) { 
		oWarning.style.display = "none"; 
		oWarning._status = null;
	}

}

// Fetches the postcode info (streetname/placename)
OSForm.prototype.fetchPostcodeInfo = function(pc, hnr, straat, woonplaats) {
	var oForm = document.getElementById(this.sForm);
	if (oForm) {
		var oPC     = document.getElementById(pc);
		var oHnr    = document.getElementById(hnr);
		var oStraat = document.getElementById(straat);
		var oPlaats = document.getElementById(woonplaats);
		
		if ( oPC.value.match("^[1-9]{1}[0-9]{3} ?[A-Za-z]{2}$")  
					&& oHnr.value.length > 0 ) {
		
			var xmlhttp = null;
			if (window.XMLHttpRequest) {
				xmlhttp = new XMLHttpRequest();
			}
			else if (window.ActiveXObject) {
				xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
			}
			if (xmlhttp == null) { 
				if (oStraat) { oStraat.value = ""; }
				oPlaats.value = "";
				return; 
			}
			else {
				if (oStraat) { oStraat.value = "Wordt opgehaald..."; }
				oPlaats.value = "Wordt opgehaald...";
			}
			
			// Build link to AdresXPress proxy URI.
			var url = this.sAdresXpressUri
				+ "?type=pc&output=json"
				+ "&postcode=" + oPC.value 
				+ "&huisnummer=" + oHnr.value;
	
			xmlhttp.open("GET", url, true);
			xmlhttp.onreadystatechange=function() {
			 if (xmlhttp.readyState == 4) { // We've got a result back
				if (xmlhttp.status == 200) { // And it's valid
					var json_data = xmlhttp.responseText;
					var oAdresXpress = eval("(" + json_data + ")");
					if (oAdresXpress && oAdresXpress.adressen.melding.toUpperCase() == "OK") {
						oPC.value     = oAdresXpress.adressen.adres[0].postcode;
						if (oStraat) { oStraat.value = oAdresXpress.adressen.adres[0].straat; }
						oPlaats.value = oAdresXpress.adressen.adres[0].plaats;
					}
					else {
						oPC.value     = oPC.value.toUpperCase();
						if (oStraat) { oStraat.value = ""; }
						oPlaats.value = "";
					}
				}
				else {
					// Something went wrong (not found|forbidden|?)
					if (oStraat) { oStraat.value = ""; }
					oPlaats.value = "";
				}
				xmlhttp = null;
			 }
			}
			xmlhttp.send(null)

		}
	}
}

/*
	Date Format 1.1
	(c) 2007 Steven Levithan <stevenlevithan.com>
	MIT license
	With code by Scott Trenda (Z and o flags, and enhanced brevity)
*/

/*** dateFormat
	Accepts a date, a mask, or a date and a mask.
	Returns a formatted version of the given date.
	The date defaults to the current date/time.
	The mask defaults ``"ddd mmm d yyyy HH:MM:ss"``.
*/
var dateFormat = function () {
	var	token        = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloZ]|"[^"]*"|'[^']*'/g,
		timezone     = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
		timezoneClip = /[^-+\dA-Z]/g,
		pad = function (value, length) {
			value = String(value);
			length = parseInt(length) || 2;
			while (value.length < length)
				value = "0" + value;
			return value;
		};

	// Regexes and supporting functions are cached through closure
	return function (date, mask) {
		// Treat the first argument as a mask if it doesn't contain any numbers
		if (
			arguments.length == 1 &&
			(typeof date == "string" || date instanceof String) &&
			!/\d/.test(date)
		) {
			mask = date;
			date = undefined;
		}

		date = date ? new Date(date) : new Date();
		if (isNaN(date))
			throw "invalid date";

		var dF = dateFormat;
		mask   = String(dF.masks[mask] || mask || dF.masks["default"]);

		var	d = date.getDate(),
			D = date.getDay(),
			m = date.getMonth(),
			y = date.getFullYear(),
			H = date.getHours(),
			M = date.getMinutes(),
			s = date.getSeconds(),
			L = date.getMilliseconds(),
			o = date.getTimezoneOffset(),
			flags = {
				d:    d,
				dd:   pad(d),
				ddd:  dF.i18n.dayNames[D],
				dddd: dF.i18n.dayNames[D + 7],
				m:    m + 1,
				mm:   pad(m + 1),
				mmm:  dF.i18n.monthNames[m],
				mmmm: dF.i18n.monthNames[m + 12],
				yy:   String(y).slice(2),
				yyyy: y,
				h:    H % 12 || 12,
				hh:   pad(H % 12 || 12),
				H:    H,
				HH:   pad(H),
				M:    M,
				MM:   pad(M),
				s:    s,
				ss:   pad(s),
				l:    pad(L, 3),
				L:    pad(L > 99 ? Math.round(L / 10) : L),
				t:    H < 12 ? "a"  : "p",
				tt:   H < 12 ? "am" : "pm",
				T:    H < 12 ? "A"  : "P",
				TT:   H < 12 ? "AM" : "PM",
				Z:    (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
				o:    (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4)
			};

		return mask.replace(token, function ($0) {
			return ($0 in flags) ? flags[$0] : $0.slice(1, $0.length - 1);
		});
	};
}();

// Some common format strings
dateFormat.masks = {
	"default":       "ddd mmm d yyyy HH:MM:ss",
	shortDate:       "m/d/yy",
	mediumDate:      "mmm d, yyyy",
	longDate:        "mmmm d, yyyy",
	fullDate:        "dddd, mmmm d, yyyy",
	shortTime:       "h:MM TT",
	mediumTime:      "h:MM:ss TT",
	longTime:        "h:MM:ss TT Z",
	isoDate:         "yyyy-mm-dd",
	isoTime:         "HH:MM:ss",
	isoDateTime:     "yyyy-mm-dd'T'HH:MM:ss",
	isoFullDateTime: "yyyy-mm-dd'T'HH:MM:ss.lo"
};

// Internationalization strings
dateFormat.i18n = {
	dayNames: [
		"Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat",
		"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
	],
	monthNames: [
		"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
		"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
	]
};

// For convenience...
Date.prototype.format = function (mask) {
	return dateFormat(this, mask);
}
