// JavaScript Document
// Description:	client-side validation class
// Author:	Sirichai Meemutha (jjoi@gayji.net)
// Ver:		$Id: validate.js v1.00

// messages
var MSG_REQUIRED = 'You\'ve not entered %t';
var MSG_EVAL = 'value in %t is invalid';
var MSG_NOTNUMERIC = 'value in %t must be numeric';
var MSG_INVALIDDATE = 'value in %t is not valid date format';
var MSG_NOTEMAIL = 'value in %t is not valid e-mail';
var MSG_NOTCITIZEN = 'Invalid Citizen ID';
var MSG_NOTPHONE = 'value in %t  is not valid phone number';
var MSG_ISZERO = 'value in %t cannot be zero';
var MSG_REGEXP = 'value in %t is not in valid format';

var FLD_REQUIRED = 1;
var FLD_NUMERIC = 2;
var FLD_DATE = 4;
var FLD_EMAIL = 8;
var FLD_PIN = 16;
var FLD_PHONE = 32;
var FLD_NOTZERO = 64;
var FLD_REGEXP = 128;
var FLD_EVAL = 256;

// predefined regexp
// avoid curly braces to get into interpolation from template class
var PASSWORD_REGEX = /^[a-z0-9]{5,12}$/i;

var LEFT_BRACE = '{';		// fix problem with template engine

// masking functions

var keyTab = 9;
var keyBS = 8;
var keyMinus = 45;

var dateSeparator = '/';
var decimalSeparator = '.';
var dateFormat = 'dd/mm/yyyy';
var minDate = new Date(1753, 1, 1);
var maxDate = new Date(9999, 12, 31);
var EPOH = new Date(0);

function Validator() {
		this._validateKeys = [];
		this._validateParams = [];
}

Validator.prototype.addRule = function (validateKey, validation, groupName, validateParam) {
		groupName = groupName || 'default';
		if(this._validateKeys[groupName] == undefined) {
			this._validateKeys[groupName] = [];
		}
			
		this._validateKeys[groupName][validateKey] = validation;
		if (validateParam) {
			if(this._validateParams[groupName] == undefined) {
				this._validateParams[groupName] = [];
			}
			this._validateParams[groupName][validateKey] = validateParam;
		}
};

// masking function 

Validator.prototype.isNumberKey = 	function(keyCode) {
	return (keyCode >= 48 && keyCode <= 57);
	//  || keyCode >= 99 && keyCode <= 105 for keyup event
};
	
Validator.prototype.numberOnlyMask = function(objInput) {
	var keyCode = event.keyCode;
	
	if (!isNumberKey(keyCode) && keyCode != keyTab && keyCode != keyBS && keyCode != keyMinus) {
		event.cancelBubble = true;
		return false;
	}
	else if (keyCode == keyMinus & objInput.value.length != '') {
		event.cancelBubble = true;
		return false;
	}
	return true;
};

Validator.prototype.TISMask = function(objInput) {
	var iKeyCode = event.keyCode;
	if (iKeyCode >= 0xE00 && iKeyCode <= 0xEF7)
		return true;	
		
	var keyCode = String.fromCharCode(event.keyCode);
	var re = /[^. ]/;

	return (!re.exec(keyCode))
}

Validator.prototype.EngMask = function(objInput) {
	var keyCode = String.fromCharCode(event.keyCode);
	var re = /[^A-Z\-. ]/i;

	return (!re.exec(keyCode))
}

Validator.prototype.EngAddressMask = function(objInput) {
	var keyCode = String.fromCharCode(event.keyCode);
	var re = /[^A-Z\-.\/_0-9\s]/i;

	return (!re.exec(keyCode))
}
	
Validator.prototype.noSpaceMask = function(objInput) {
	var keyCode = event.keyCode;
	if (keyCode == 32) {
		event.cancelBubble = true;
		return false;
	}
	return true;
};
	
Validator.prototype.numericMask = function(objInput) {
	var keyCode = event.keyCode;

	if (!this.isNumberKey(keyCode) && keyCode != keyTab && keyCode != keyBS
			 && String.fromCharCode(keyCode) != decimalSeparator 
			 && keyCode != keyMinus) {
		event.cancelBubble = true;
		return false;
	}
	else if (keyCode == keyMinus && objInput.value != '') {
		event.cancelBubble = true;
		return false;
	}
	else if (String.fromCharCode(keyCode) == decimalSeparator && objInput.value.lastIndexOf(decimalSeparator) >= 0) {
		event.cancelBubble = true;
		return false;
	}
	return true;
};
	
Validator.prototype.rangeMask = function(objInput, minValue, maxValue) {
	var keyCode = event.keyCode;
	var newValue;
	
	if (!numberOnlyMask(objInput))
		return false;
	else if (minValue >= 0 && keyCode == keyMinus)
		return false;

	selRange = document.selection.createRange();
	currentSelected = selRange.text;
	selRange.text = '';
	newValue = parseInt(objInput.value + String.fromCharCode(keyCode));
	if ( newValue < minValue || newValue > maxValue) {
		event.cancelBubble = true;	
		selRange.text = currentSelected;		
		return false;		
	}
	return true;
};
	
Validator.prototype.hourMask =	function(objInput, objMinuteInput) {
	return rangeMask(objInput, 0, 23);
};
	
Validator.prototype.minuteMask = function(objInput) {
	return rangeMask(objInput, 0, 59);
};
	
Validator.prototype.dateMask =	function(objInput) {
	var keyCode = event.keyCode;
	if (!numberOnlyMask(objInput)) {
		if (String.fromCharCode(keyCode) != dateSeparator)
			return false;
		else
			event.cancelBubble = false;
	}
	else if (keyCode == keyMinus && keyMinus != dateSeparator)
		return false;
		
	return true;
};

// utility function
	
Validator.prototype.toFullYear	 = function(yearInput) {
	return (yearInput < 1000) ? yearInput + 1900 : yearInput; 
};
	
Validator.prototype.parseDate =  function (dateString) {
	var day, month, year;
	var dateValues = dateString.split(dateSeparator);
	if (dateValues.length != 3) return EPOH;
	
	var dateParts = dateFormat.split(dateSeparator);
	for (i =0; i < 3; i++) {
		switch(dateParts[i]) {
			case 'd':
			case 'dd':
				day = parseInt(dateValues[i],10);
				break;
			case 'm':
			case 'mm':
				month = parseInt(dateValues[i],10) - 1;
				break;
			case 'yy':
				year = parseInt(dateValues[i]);
				year = toFullYear(year);
				break;
			case 'yyyy':
				year = parseInt(dateValues[i]);
				break;
		}
	}

	var tmpDate = new Date(year,month,day);	
	if (isNaN(tmpDate)) return EPOH;
	else if (tmpDate < minDate) return EPOH;
	else if (tmpDate > maxDate) return EPOH;
	else if (this.toFullYear(tmpDate.getYear()) == year &&
		 month == tmpDate.getMonth() &&
		 day == tmpDate.getDate())  {
		return tmpDate;
	}
	else
		return EPOH;
};

Validator.prototype.formatDate = function(dateValue) {
	var dateParts = dateFormat.split(dateSeparator);
	var returnValue = '';
	for (i =0; i < 3; i++) {
		switch(dateParts[i]) {
			case 'd':
			case 'dd':
				returnValue += dateValue.getDate().toString();
				break;
			case 'm':
			case 'mm':
				returnValue += (dateValue.getMonth() + 1).toString();
				break;
			case 'yy':
				returnValue += datevalue.getYear().toString();
				break;
			case 'yyyy':
				returnValue += dateValue.getFullYear().toString();
				break;
		}
		if (i < 2) returnValue += dateSeparator;
	}
	return returnValue;
};

Validator.prototype.focusObject = function(objField) {
	var currentNode;
	
	// set selected tab :: tabpane script
	currentNode = objField;
	while (currentNode != document){
			currentNode = currentNode.parentNode;
			if (currentNode.tagName) {
				if (currentNode.tagName.toLowerCase() == 'div' && currentNode.className == 'tab-page') {
					for (var i = 0; i < tp1.pages.length; i++) {
						if (tp1.pages[i].element == currentNode) {
							tp1.setSelectedIndex(i);
							break;
						}
					}
					break;
				}
			}
	}
	
	try {
		objField.focus();
	}
	catch (e){
	}	
};
	
// type check function
	
Validator.prototype.IsNumeric = function(inp) {
	return !isNaN(inp.replace(/,/g,''));
};
	
Validator.prototype.IsDate = function(dateString) {
	var dateValue;
	
	dateValue = this.parseDate(dateString);
	return (dateValue != EPOH);
};

Validator.prototype.IsValidMail = function(str) {
	re = /[a-zA-Z0-9_]+\@[-a-zA-Z0-9_]+(\.[-a-zA-Z0-9]+)+$/;
	
	m = re.exec(str);
	return m != null;
};

Validator.prototype.IsValidPIN = function(str) {
		if (!/^\d{13}$/.exec(str))
			return false;
		
		var sum = 0;
		var checkDigit  = str.charCodeAt(12) - 48;
		for (i = 0; i <= 11; i++) {
				digit = str.charCodeAt(i) - 48;
				if (digit < 0 || digit > 9)
					return false;
				sum += digit  * (13 - i);
		}
		var calcDigit = 11 - (sum % 11);
		if (calcDigit >= 10)
			calcDigit -= 10;

		return calcDigit == checkDigit;
		
}

Validator.prototype.isValidPhone = function(str) {
		return /^\d{2,3}\-\d{7,8}/.exec(str);
}


// validate 

Validator.prototype.getValidateKey = function (key, groupName) {
		if (groupName) {
			if (groupName && this._validateKeys[groupName])
				return this._validateKeys[groupName][key];
		}
		else {
				for (var grp in this._validateKeys) {
						if (this._validateKeys[grp][key]) {
							return this._validateKeys[grp][key];
						}
				}
		}
		
		return null;
};

Validator.prototype.getValidateParam = function (key, groupName) {
		if (groupName) {
			if (groupName && this._validateParams[groupName])
				return this._validateParams[groupName][key];
		}
		else {
				for (var grp in this._validateParams) {
						if (this._validateParams[grp][key]) {
							return this._validateParams[grp][key];
						}
				}
		}
		
		return null;
};

Validator.prototype.Validate = function (objForm, groupName) {
	var objField;
	var validation, validateValue;
	var displayTitle;
	
	if (objForm)
		this._form = objForm;
	
	for (var i = 0; i < this._form.elements.length; i++) {
			objField = this._form.elements[i];

			if (objField.id)
				validation = this.getValidateKey(objField.id, groupName);
			else if(objField.name)
				validation = this.getValidateKey(objField.name, groupName);
			else
				continue;

			if (objField.title)
				displayTitle = objField.title;
			else
				displayTitle = objField.name;
				
			validateValue = objField.value;
			if (validation & FLD_REQUIRED) {
				if(validateValue == '') {
					alert (MSG_REQUIRED.replace('%t', displayTitle));
					this.focusObject(objField);
					return false;
				}
			}
			
			if (validation & FLD_EVAL) {
				var validateParam = this.getValidateParam(objField.name, groupName);

				var validateResult = eval(validateParam);
				if (!validateResult) {
					alert (MSG_EVAL.replace('%t', displayTitle));
					this.focusObject(objField);
					return false;
				}					
			}
			
			if (validateValue) {
				if (validation & FLD_NUMERIC) {
					if (!this.IsNumeric(validateValue)) {
						alert (MSG_NOTNUMERIC.replace('%t', displayTitle));
						this.focusObject(objField);
						return false;
					}
				}
				
				if (validation & FLD_DATE) {
					if (!this.IsDate(validateValue)) {
						alert (MSG_INVALIDDATE.replace('%t', displayTitle));
						this.focusObject(objField);
						return false;
					}
				}
				
				if (validation & FLD_EMAIL) {
					if (!this.IsValidMail(validateValue)) {
						alert (MSG_NOTEMAIL.replace('%t', displayTitle));
						this.focusObject(objField);
						return false;
					}					
				}
				
				if (validation & FLD_PIN) {
						if (!this.IsValidPIN(validateValue)) {
							alert (MSG_NOTCITIZEN.replace('%t', displayTitle));
							this.focusObject(objField);
							return false;
						}
				}
				
				if (validation & FLD_PHONE) {
					if (!this.isValidPhone(validateValue)) {
							alert(MSG_NOTPHONE.replace('%t', displayTitle));
							this.focusObject(objField);
							return false;
					}
				}
				
				if (validation & FLD_NOTZERO) {
					if (validateValue == 0) {
						alert (MSG_ISZERO.replace('%t', displayTitle));
						this.focusObject(objField);
						return false;
					}					
				}
				
				if (validation & FLD_REGEXP) {
					var re = new RegExp(this.getValidateParam(objField.name, groupName));
					if (!re.exec(validateValue)) {
						alert (MSG_REGEXP.replace('%t', displayTitle));
						this.focusObject(objField);
						return false;
					}					
				}
				
			}		// if (validateValue)
			
	} // for elements
	
	return true;
	
};