/*
 * All globals will start vdn to ensure no namespace clash.
 */

/* Global variables all defined here */

var VDN_OKIMAGE  = "vdn_ok.png";
var VDN_ERRIMAGE = "vdn_error.png";

var VDN_MSG_ERROR = "One or more fields have invalid values. Please correct these before proceeding:";
var VDN_MSG_MANDATORY = "The mandatory field, %n, must be specified";
var VDN_MSG_LENGTH = "The field, %n, is too short or too long";
var VDN_MSG_DATE = "The date field, %n, should contain a valid date in the format DD/MM/YYYY; %v is not a valid date.";
var VDN_MSG_INTEGER = "The integer field, %n, should contain a valid number. %v is not a valid number.";
var VDN_MSG_EMAIL = "The email address field, %n, should contain a valid email address.";

// If this is set to true, and internal error has occurred and we just *ignore* all further things
// I.e. turn validation off permanently so that we don't screw the browser or create loops etc.
var vdn_globalerror = false;
var vdn_objDebugWindow;

function vdn_onload()
{
	// Find all the forms in the page.
	var i;
	
	for (i=0; i<document.forms.length; i++)
	{
		vdn_initform(document.forms[i]);
	}
}

function vdn_initform(objForm)
{
	var blnNeedsValidation = false;
	var i;
	for (i=0; i<objForm.elements.length; i++)
	{
		var objElement = objForm.elements[i];
		if ((objElement.type == "text") || (objElement.type == "textarea") || (objElement.type == "select-one"))
		{
			if (vdn_initelement(objElement)) 
				blnNeedsValidation = true;
		}
	}
	if (blnNeedsValidation) {
		objForm.onsubmit = vdn_onsubmit;
	}
}

/* Returns true if we want to do validation on this element, false otherwise */
function vdn_initelement(objElement)
{
	// Attempt to find a validation hidden field.
	var objForm = objElement.form;
	if (! objForm) vdn_error("Cannot find form");
	var objVdnElement = objForm.elements["vdn_" + objElement.name];
	if (! objVdnElement) return false;
	var objValidator = new vdn_Validator();
	// Process config directives
	var i;
	var splitString;
	splitString = objVdnElement.value.split(";");
	for (i=0; i<splitString.length; i++) 
	{
		var strName, strVal;
		var bits;
		bits = splitString[i].split(":");
		strName = bits[0];
		strVal = bits[1];
		var strType = typeof(objValidator[strName]);
		if (strType == "undefined")
		{
			vdn_error("Undefined validation property:" + strName + " on Form element " + objElement.name);
		}
		if (strType == "boolean")
		{
			objValidator[strName] = false;
			if (strVal == "true") objValidator[strName] = true;
		}
		if (strType == "string")
		{
			objValidator[strName] = strVal;
		}
		if (strType == "number")
			objValidator[strName] = parseInt(strVal,10);
	}
	// Try to find an image:
	var objImage = document.images["vdnimage_" + objElement.name];
	if (objImage)
		objValidator.image = objImage;
	// Set up the "element" propertyon the validator object.
	objValidator.element = objElement;
	// Set up vdn_validator custom property.
	objElement.vdn_validator = objValidator;
	// Set up onchange event.
	objElement.onchange = vdn_onchange;
	// Finally do it
	objValidator.validate();
	return true;
}

function vdn_onchange()
{
	this.vdn_validator.validate();
	return true;
}

// Validator also has the following properties:
// "element" - an object which is the element we're validating.
// "image" which is an optional image which is the validation icon.
/* Constructor for validator object */
function vdn_Validator()
{
	this.mandatory = false;
	this.minlength = 0;
	this.maxlength = 1000;
	this.type = "string";
	this.validate = vdn_Validator_validate;
	this.ok = vdn_Validator_ok;
	this.fail = vdn_Validator_fail;
}

// Method called to do validation.
function vdn_Validator_validate()
{
	var blnOk = true;
	var value = this.element.value;
	// Work around for NS4 etc with Select boxes
	if (this.element.selectedIndex)
		value = this.element.selectedIndex;
	// If it's mandatory and absent, error.
	if (this.mandatory && (value == ""))
	{
		blnOk = false;
		this.errmsg = VDN_MSG_MANDATORY;
	} else {
		// Check integers.
		if (this.type == "integer")
		{
			var i = parseInt(value,10);
			if (isNaN(i)) blnOk = false;
			if (blnOk) this.element.value = i;
			if (!blnOk) this.errmsg = VDN_MSG_INTEGER;
		}
		// Check dates
		if (this.type == "date")
		{
			blnOk = vdn_validate_date(value);
			if (blnOk) this.element.value = vdn_parse_date(value);
			if (!blnOk) this.errmsg = VDN_MSG_DATE;
		}
		// Check dates
		if (this.type == "email")
		{
			blnOk = vdn_validate_email(value);
			if (!blnOk) this.errmsg = VDN_MSG_EMAIL;
		}
		// Check length
		if (value.length < this.minlength) {
			blnOk = false;
			this.errmsg = VDN_MSG_LENGTH;
		}
		if (value.length > this.maxlength) {
			blnOk = false;
			this.errmsg = VDN_MSG_LENGTH;
		}
		// If it's not mandatory and it's not supplied, override other validation
		// And return true;
		if ((! this.mandatory) && (value == ""))
		{
			blnOk = true;
		}
	}
	if (blnOk) 
		this.ok();
	else
		this.fail();
	return blnOk;
}

function vdn_Validator_ok()
{
	if (this.image)
		this.image.src=VDN_OKIMAGE;
}

function vdn_Validator_fail()
{
	if (this.image)
		this.image.src=VDN_ERRIMAGE;
}

/** Strictly dd/mm/yyyy **/
function vdn_validate_date(strDate)
{
	var day,month,year;
	var dayspermonth = [ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
	var bits,i;
	bits = strDate.split("/");
	if (bits.length != 3) return false;
	day = parseInt(bits[0],10);
	month = parseInt(bits[1],10);
	year = parseInt(bits[2],10);
	if (isNaN(day)) return false;
	if (isNaN(month)) return false;
	if (isNaN(year)) return false;
	if ((day <1) || (day>31)) return false;
	if ((month<1) || (month>12)) return false;
	if ((year<1900) || (year>2100)) return false;
	// Now we've done the trivial checks
	// Check if leap year
	if (vdn_isleap(year)) dayspermonth[2] = 29;
	// Check day is valid.
	vdn_debugprint("This month has " + dayspermonth[month]);
	if (day > dayspermonth[month]) return false;
	vdn_debugprint("Date validation ok");
	return true;
}

function vdn_parse_date(strDate)
{
	var day,month,year;
	var bits;
	bits = strDate.split("/");
	day = parseInt(bits[0],10);
	month = parseInt(bits[1],10);
	year = parseInt(bits[2],10);
	var strOut;
	strOut = vdn_padzero(day) + "/" + vdn_padzero(month) + "/" +  year;
	return strOut;
}

function vdn_validate_email(strEmail)
{
	// TODO: Make cleverer
	if (strEmail.indexOf("@") == -1) return false;
	return true;
}

function vdn_padzero(strIn)
{
	strIn = strIn.toString();
	if (strIn.length <2) return "0" + strIn;
	return strIn;
}

// This function works for the years 1900 to 2100 I think
function vdn_isleap(intYear)
{
	// Years not divisible by four are never leap years.
	if ((intYear % 4) != 0) return false;
	// The y2k was a leap year
	if (intYear == 2000) return true;
	// Other years divisible by 100 generally aren't
	if ((intYear % 100) == 0) return false;
	// All other divisible by 4 years are.
	return true;
}

// Called when a validated form is submitted
function vdn_onsubmit()
{
	var objForm = this;
	var blnOk = true;
	var i;
	var strErrors = "";
	for (i=0; i<objForm.elements.length; i++)
	{
		var objElement = objForm.elements[i];
		var objValidator = objElement.vdn_validator;
		if (objValidator) {
			var blnResult = objValidator.validate();
			if (! blnResult) {
				vdn_debugprint("Failed on " + objElement.name);
				blnOk = false;
				strErrors = strErrors + vdn_expand_errmsg(objValidator) + "\n";
			}
		}
	}
	if (window.vdn_custom) {
		var strMsg = vdn_custom();
		if (strMsg != "")
		{
			strErrors = strErrors + strMsg + "\n";
			blnOk = false;
		}
	}
	if (! blnOk) {
		alert(VDN_MSG_ERROR + "\n" + strErrors);
	}
	return blnOk;
}

function vdn_expand_errmsg(objValidator)
{
	var strMsg = objValidator.errmsg;
	strMsg = strMsg.replace("%n",objValidator.element.name);
	strMsg = strMsg.replace("%v",objValidator.element.value);
	return strMsg;
}

/*************** DEBUGGING FUNCTIONS *************/
/* keep at end */
/* NOT called if there's a validation error, called if there's an internal error. */
function vdn_error(strMessage)
{
	if (vdn_globalerror) return;
	alert("Validation library internal error\r\n " + strMessage);
	vdn_globalerror = true;
	// Don't use throw keyword because not supported in some browser
	// Use "eval" instead as that's safe even if the keyword isn't recognised.
	eval("throw '" + strMessage +"'");
}

function vdn_debugprint(strMessage)
{
	var obj;
	obj = document.forms[0].vdn_debug;
	if (! obj) return;
	obj.value = obj.value + strMessage + "\n";
}


