﻿// TODO: move these functions to a global utils library javascript file...
function attachEventHandler(o, e, f) {
	if(o) {
		if(o.addEventListener) {
			o.addEventListener(e, f, false);
		} else if(o.attachEvent) {
			o.attachEvent("on" + e, f);
		}
	}
}

function getEvent(e) {
	if(e) {
		return e;
	} else if(window.event) {
		return window.event;
	}
}

function getEventSource(e, o) {
	if(e.srcElement) {
		return e.srcElement;
	} else {
		return o;
	}
}

function cancelEvent(e) {
	if(e) {
		e.cancelBubble = true;
		if(e.preventDefault) {
			e.preventDefault();
		} else {
			e.returnValue = false;
		}
	}
}

String.prototype.capitaliseFirstWord = function() {
	return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
}

// These two are not complete, but works fine for now
String.prototype.encode = function() {
	var s = this.replace(/</g, "&lt;");
	s = s.replace(/>/g, "&gt;");
	s = s.replace(/&/g, "&amp;");
	s = s.replace(/"/g, "&quot;");
	s = s.replace(/'/g, "&apos;");
	return s;
}

String.prototype.decode = function() {
	var s = this.replace(/&lt;/g, "<");
	s = s.replace(/&gt;/g, ">");
	s = s.replace(/&amp;/g, "&");
	s = s.replace(/&quot;/g, "\"");
	s = s.replace(/&apos;/g, "'");
	return s;
}

// This method does a standard escape and also escapes forward slashes. We may want to extend this further?
function escapeAll(str) {
	str = escape(str);
	str = str.replace(/\//g, "%2F%C2"); 
	return str;
}

// -------------------------------------------------------------------------------------------------------------------------------------------------

document.ignoreButton = false;
document.formItems = new Array();

Array.prototype.resetRequiresValidation = function() {
	for(var i in this) {
		if (typeof(this[i]) == 'object' && this[i].requiresValidation) {
			this[i].requiresValidation = true;
		}
	}
}

function formItem(name) {
	this.validators = new Array();
	this.name = name;
	this.isMultiLine = false;
	this.requiresValidation = true;
}

// = CUSTOM VALIDATORS ==================================================================================================================================

// Regular expression validator
function RegExValidator(message, expression) {
	this.type = "RegExValidator";
	this.formItem; // Parent
	this.hasError = false;
	this.message = message.decode();
	
	this.expression = expression;
	
	this.validate = _RegExValidator_validate;
}

function _RegExValidator_validate(formItem, form) {
	if(_getFormElementValue(formItem) != "") {
		this.hasError = !this.expression.test(_getFormElementValue(formItem));
	} else {
		this.hasError = false;
	}
	return !this.hasError;
}

// ------------------------------------------------------------------------------------------------------------------------------------------------------

// Is Required validator
function IsRequiredValidator(message) {
	this.type = "IsRequiredValidator";
	this.formItem; // Parent
	this.hasError = false;
	this.message = message.decode();
	
	this.validate = _IsRequiredValidator_validate;
}

function _IsRequiredValidator_validate(formItem, form) {
	this.hasError = (_getFormElementValue(formItem).trim() == "");
	return !this.hasError;
}

// ------------------------------------------------------------------------------------------------------------------------------------------------------

// Confirmation validator
function ConfirmValidator(message, confirmName, ignoreCase) {
	this.type = "ConfirmValidator";
	this.formItem; // Parent
	this.hasError = false;
	this.message = message.decode();
	
	this.confirmName = confirmName;
	this.ignoreCase = ignoreCase;
	
	this.validate = _ConfirmValidator_validate;
}

function _ConfirmValidator_validate(formItem, form) {
	var oConfirmValue = form.elements[this.confirmName];
	if(oConfirmValue) {
		if(this.ignoreCase) {
			this.hasError = (oConfirmValue.value.toLowerCase() != _getFormElementValue(formItem).toLowerCase());
		} else {
			this.hasError = (oConfirmValue.value != _getFormElementValue(formItem));
		}
	} else {
		this.hasError = false;
	}
	return !this.hasError;
}

// ------------------------------------------------------------------------------------------------------------------------------------------------------

// Compare validator
function CompareValidator(message, compareName, expression, match, validator) {
	this.type = "CompareValidator";
	this.formItem; // Parent
	this.hasError = false;
	this.message = message.decode();
	
	this.compareName = compareName;
	if(expression != "") {
		this.expression = new RegExp(expression);
	}
	this.match = match;
	this.validator = validator;
	
	this.validate = _CompareValidator_validate;
}

function _CompareValidator_validate(formItem, form) {
	if(this.formItem.isMultiLine) {
		if(!this.baseName) {
			this.baseName = this.compareName;
		}
		
		var formItemName = new String(formItem.name);
		var iIndex = formItemName.indexOf("_");
		if(iIndex != -1) {
			this.compareName = this.baseName + "_" + formItemName.substr(iIndex + 1);
		} else {
			return;
		}
	}
	
	var oCompareValue = form.elements[this.compareName];
	this.hasError = false;
	if(oCompareValue) {
		var sValue;
		if(!oCompareValue.type) {
			sValue = _getRadioValue(oCompareValue);
		} else {
			sValue = oCompareValue.value;
		}

		if((this.expression && this.expression.test(sValue)) || (this.match == sValue)) {
			this.hasError = !this.validator.validate(formItem, form);
			if(this.hasError) {
				this.message = this.validator.message;
			}
		}
	}
	return !this.hasError;
}

// ------------------------------------------------------------------------------------------------------------------------------------------------------

// Number validator
function NumberValidator(message, decimalPlaces, allowZero, allowNegative) {
	this.type = "NumberValidator";
	this.formItem; // Parent
	this.hasError = false;
	this.message = message.decode();
	
	this.decimalPlaces = decimalPlaces;
	this.allowZero = allowZero;
	this.allowNegative = allowNegative;
	
	this.validate = _NumberValidator_validate;
}

function _NumberValidator_validate(formItem, form) {
	this.hasError = false;

	var val = _getFormElementValue(formItem);
	
	if(val != "") {
		if(isNaN(val)) {
			this.hasError = true;
		} else {
			if((!this.allowNegative && val < 0) ||
					(!this.allowZero && val == 0)) {
				this.hasError = true;
			} else {
				var decimalIndex = val.indexOf(".");
				if(decimalIndex != -1 && this.decimalPlaces == 0) {
					this.hasError = true;
				} else {
					var d = val.substr(decimalIndex + 1);
					if(decimalIndex != -1 && d.length > this.decimalPlaces) {
						this.hasError = true;
					}
				}
			}
		}
	}
	
	return !this.hasError;
}

// ------------------------------------------------------------------------------------------------------------------------------------------------------

// Number range validator
function RangeValidator(message, min, max) {
	this.type = "RangeValidator";
	this.formItem; // Parent
	this.hasError = false;
	this.message = message.decode();
	
	this.max = max;
	this.min = min;
	
	this.validate = _RangeValidator_validate;
}

function _RangeValidator_validate(formItem, form) {
	this.hasError = false;

	var val = _getFormElementValue(formItem);
	
	if(val != "") {
		if(isNaN(val)) {
			this.hasError = true;
		} else {
			if(val < this.min || val > this.max) {
				this.hasError = true;
			}
		}
	}
	
	return !this.hasError;
}

// ======================================================================================================================================================

function _getFormElementValue(formElement) {
	if(formElement.type == "checkbox") {
		if(formElement.checked) {
			return formElement.value;
		} else {
			return "";
		}
	} else if(formElement.type == "radio") {
		return _getRadioValue(document.getElementsByName(formElement.name));
	}
	
	return formElement.value;
}

function _getRadioValue(o) {
	if(o) {
		for(var i = 0; i < o.length; i++) {
			if(o[i].checked) {
				return o[i].value;
			}
		}
	}
	return "";
}


// Add Regular expression validator
function v(name, validator, isDisabled) {
	_appendValidator(name, validator, false, isDisabled == true);
}

// Multiline validators
function vml(name, validator, isDisabled) {
	_appendValidator(name, validator, true, isDisabled == true);
}

function _appendValidator(name, validator, isMultiLine, isDisabled) {
	if(document.getElementById && document.getElementsByName) {
		var fi = document.formItems[name];
		if(!fi) {
			fi = new formItem(name);
			fi.isMultiLine = isMultiLine;
			fi.requiresValidation = !isDisabled;
			document.formItems[name] = fi;
		}
		validator.formItem = fi;
		fi.validators[fi.validators.length] = validator;
	}
}

// Attach Form Events
function afe(formId) {
	if(document.getElementById && document.getElementsByName) {
		var oForm = document.getElementById(formId);
		if(oForm) {
			attachEventHandler(oForm, "submit", validateForm);
			// Events can be attached to individual form elements here...
			try {
				afeCallback(formId, oForm)
			} catch(e) {
			}
		}
	}
}

function ignoreValidation() {
	document.ignoreButton = true;
}

function validateFormCallbackArgs(form, event) {
	this.form = form;
	this.event = event;
	
	this.control;
	this.message;
}

function validateForm(e) {
	if(document.ignoreButton) {
		document.ignoreButton = false;
		return;
	} else {
		document.ignoreButton = false;
	}
	
	document.isValidating = true;
	
	var validator;
	var fi;
	var firstError;
	var message = "";

	var event = getEvent(e);
	var oForm = getEventSource(e, this);
	var oErrorMsg = document.getElementById("h-error");
	if(oErrorMsg) {
		oErrorMsg.style.display = "none";
	}

	var errorCount, totalErrorCount = 0, oFormElement, validatorMessage, radioElementNames = "", bValidate, iIndex, baseName, formElementName, fi;
	for(var i = 0; i < oForm.elements.length; i++) {
		oFormElement = oForm.elements[i];
		if(oFormElement.name && oFormElement.type != "hidden" && oFormElement.type != "button" && oFormElement.type != "submit") {
			bValidate = true;
			if(oFormElement.type == "radio") {
				if(radioElementNames.indexOf("[" + oFormElement.name + "]") == -1) {
					radioElementNames += ("[" + oFormElement.name + "]");
				} else {
					bValidate = false;
				}
			}
			if(bValidate) {
				fi = null;
				formElementName = new String(oFormElement.name);
				iIndex = formElementName.indexOf("_");
				if(iIndex != -1) {
					baseName = formElementName.substr(0, iIndex);
					if(baseName) {
						fi = document.formItems[baseName];
					}
				}
				if(!fi) {
					fi = document.formItems[oFormElement.name];
				}
				if(fi && fi.requiresValidation == true && fi.validators) {
					errorCount = 0, validatorMessage = "";
					for(var ii = 0; ii < fi.validators.length; ii++) {
						fi.validators[ii].validate(oFormElement, oForm);
						
						if(fi.validators[ii].hasError) {
							errorCount++;
							totalErrorCount++;

							if(!validatorMessage) {
								validatorMessage = fi.validators[ii].message;
							}
		
							if(!firstError) {
								firstError = oFormElement;
								message = validatorMessage;
							}
						}
					}
					
					_setControlMessage((errorCount > 0), oFormElement, validatorMessage);
				}
			}
		}
	}

	if(!firstError) {
		try {
			var args = new validateFormCallbackArgs(oForm, event);
			validateFormCallback(args)
			firstError = args.control;
			if(args.message) {
				_setControlMessage(true, firstError, args.message);
			}
		} catch(e) {
		}
	}
	
	if(firstError) {
		if(message) {
			var msg = message;
			
			if("“".length > 1 && String.fromCharCode) {	// Check to see of the browser fully supports UTF-8 in javascript...
				// If not then replace the “ and ” character to a simple " character...
				msg = msg.replace(String.fromCharCode(8220), "\"");
				msg = msg.replace(String.fromCharCode(8221), "\"");
			}
			
			alert(msg);
		}
		firstError.focus();

		cancelEvent(event);
	}

	try {
		postValidationCallBack(totalErrorCount > 0, oForm);
	} catch(e) {
	}

	document.isValidating = false;
}

function clearControlMessage(formElement) {
	if(formElement) {
		_setControlMessage(false, formElement);
	}
}

function _setControlMessage(hasError, oFormElement, validatorMessage) {
	var id;
	var oControls = document.getElementsByName(oFormElement.name);
	if(oControls && oControls.length > 1) {
		var index;
		var i = oFormElement.id.indexOf("-");
		if(i > 0) {
			index = parseInt(oFormElement.id.substr(i + 1));
			if(isNaN(index)) {
				index = null;
			}
		}
		id = oFormElement.name + "-" + index + "-emsg";
	} else {
		id = oFormElement.name + "-emsg";
	}
	var o = document.getElementById(id);

	if(hasError) {
		if(oFormElement.type == "radio") {
			oFormElement.parentNode.parentNode.className = "r error";
		} else {
			oFormElement.parentNode.className = "error";
		}

		if(!o) {
			o = document.createElement("p");
			o.id = id;
			o.className = "error-m";
			if(oFormElement.type == "radio") {
				oFormElement.parentNode.parentNode.parentNode.appendChild(o, oFormElement.parentNode.parentNode);
			} else {
				oFormElement.parentNode.parentNode.insertBefore(o, oFormElement.parentNode);
			}
		}
		if(o.style) {
			o.style.display = "block";
		}

		if(o.textContent != null) {
			o.textContent = validatorMessage;
		} else {
			o.innerHTML = validatorMessage;
		}
	} else {
		if(oFormElement.type == "radio") {
			oFormElement.parentNode.parentNode.className = "r";
		} else {
			oFormElement.parentNode.className = "";
		}
		
		if(o) {
			o.style.display = "none";
		}
	}
}


