/**
 *  Overriding of Struts generated method
 */
function _validatePersonalDetailsForm(form) {
	if (bCancel) return true;

	var formValidationResult = validateValidWhenIfNotNull(form);
	formValidationResult = validateValidWhen(form) && formValidationResult;
	formValidationResult = validateRequiredIfNotNull(form) && formValidationResult;
	formValidationResult = validateRequiredIf(form) && formValidationResult;
	formValidationResult = validateStartDate(form) && formValidationResult;
	formValidationResult = validateTimeTwoFields(form) && formValidationResult;
	formValidationResult = validateNotNumbers(form) && formValidationResult;
	formValidationResult = validateMask(form) && formValidationResult;
	formValidationResult = validateMaskForNonSpace(form) && formValidationResult;
	formValidationResult = validateMultipleFieldMask(form) && formValidationResult;
	formValidationResult = validateMinLength(form) && formValidationResult;
	formValidationResult = validateMaxLength(form) && formValidationResult;
	formValidationResult = validateBirthDate(form) && formValidationResult;
	formValidationResult = validateSelectedDate(form) && formValidationResult;
	formValidationResult = validateEmail(form) && formValidationResult;
	formValidationResult = validateIntRange(form) && formValidationResult;
	formValidationResult = validateExpiryDate(form) && formValidationResult;

	if (!formValidationResult) {	//TODO: Refactor - Move outside
		jumpToAnchor(form.currentStep.value + '_id');
	}
    return (formValidationResult == 1);
} 

/**
 * Checks if the field should be not validated.
 */
function isNotValidate(field) {
	var result = false;

	if (field == null || field == "" || isDisabled(field)) {
		result = true
	} else {
		if (field.length > 0 && !isSelectElement(field)) {
			for (var i = 0; i < field.length; i++) {
				if (isInputElement(field[i]) && (isDisabled(field[i])) || isInvisible(field[i])) {
					result = true;
					break;
				}
			}
		} else {
			result = isDisabled(field) || isInvisible(field);
		}
	}
	return result;
}

function validateRequired(form) {
	var isValid = true;

	var oRequired = eval('new ' + form.name + '_required()');
	for (var x in oRequired) {
		var field = form[oRequired[x][0]];

		if (isEmpty(field)) {
			// save validation data for error showing
			addFieldEntry(oRequired[x][0], oRequired[x][1]);
			isValid = false;
		}
	}
	return isValid;
}

function validateRequiredIfNotNull(form) {
	var isValid = true;

	var oRequired = eval('new ' + form.name + '_requiredIfNotNull()');
	for (var x in oRequired) {
		var field = form[oRequired[x][0]];
		
		// validation skipped if field not showing on the page
		if (isNotValidate(field)) {
			continue;
		}
		if (isEmpty(field)) {
			// save validation data for error showing
			addFieldEntry(oRequired[x][0], oRequired[x][1]);
			isValid = false;
		}
	}
	return isValid;
}

function validateMinLength(form) {
    var isValid = true;

    var oMinLength = eval('new ' + form.name + '_minlength()');

    for (var x in oMinLength) {
        var field = form[oMinLength[x][0]];

		// validation skipped if field not showing on the page
		if (isNotValidate(field)) {
			continue;
		}

        if ((field.type == 'hidden' ||
            field.type == 'text' ||
            field.type == 'password' ||
            field.type == 'textarea') &&
            !field.disabled) {

            var iMin = parseInt(oMinLength[x][2]("minlength"));
			var trValue = trim(field.value); 
			if ((trValue && trValue.length > 0) && (field.value.length < iMin)) {
                // save validation data for error showing                    
				addFieldEntry(oMinLength[x][0], oMinLength[x][1]);
                
                isValid = false;
            } 
        }
    }
    return isValid;
}


function validateMaxLength(form) {
    var isValid = true;

    var oMaxLength = eval('new ' + form.name + '_maxlength()');
    for (var x in oMaxLength) {
        var field = form[oMaxLength[x][0]];

		// validation skipped if field not showing on the page
		if (isNotValidate(field)) {
			continue;
		}

        if ((field.type == 'hidden' ||
            field.type == 'text' ||
            field.type == 'password' ||
            field.type == 'textarea') &&
            !field.disabled) {

            var iMax = parseInt(oMaxLength[x][2]("maxlength"));
            if (field.value.length > iMax) {
                // save validation data for error showing                    
				addFieldEntry(oMaxLength[x][0], oMaxLength[x][1]);
                isValid = false;
            } 
        }
    }
    return isValid;
}

function validateMask(form) {
    var isValid = true;

    var oMasked = eval('new ' + form.name + '_mask()');
    for (var x in oMasked) {
        var field = form[oMasked[x][0]];

		// validation skipped if field not showing on the page
		if (isNotValidate(field)) {
			continue;
		}

        if ((field.type == 'hidden' ||
            field.type == 'text' ||
             field.type == 'textarea' ||
			 field.type == 'file') &&
             (field.value.length > 0) &&
             !field.disabled) {

			if (!isMaskMatches(field, oMasked[x][2]("mask"))) {
                // save validation data for error showing
				addFieldEntry(oMasked[x][0], oMasked[x][1]);

                isValid = false;
            } 
        }
    }
    return isValid;
}

function matchPattern(value, mask) {
   return mask.exec(value);
}

function validateEmail(form) {
    var bValid = true;

    var oEmail = eval('new ' + form.name + '_email()');

    for (var x in oEmail) {
        var field = form[oEmail[x][0]];

		// validation skipped if field not showing on the page
		if (isNotValidate(field)) {
			continue;
		}

        if ((field.type == 'hidden' || 
             field.type == 'text' ||
             field.type == 'textarea') &&
            (field.value.length > 0) &&
            !field.disabled) {
            if (!checkEmail(field.value)) {
                // save validation data for error showing                    
				addFieldEntry(oEmail[x][0], oEmail[x][1]);
                bValid = false;
            } 
        }
    }
    return bValid;
}

function checkEmail(emailStr) {
   if (emailStr.length == 0) {
       return true;
   }
   var emailPat=/^(.+)@(.+)$/;
   var specialChars="\\(\\)<>@,;:\\\\\\\"\\.\\[\\]";
   var validChars="\[^\\s" + specialChars + "\]";
   var quotedUser="(\"[^\"]*\")";
   var ipDomainPat=/^(\d{1,3})[.](\d{1,3})[.](\d{1,3})[.](\d{1,3})$/;
   var atom=validChars + '+';
   var word="(" + atom + "|" + quotedUser + ")";
   var userPat=new RegExp("^" + word + "(\\." + word + ")*$");
   var domainPat=new RegExp("^" + atom + "(\\." + atom + ")*$");
   var matchArray=emailStr.match(emailPat);
   if (matchArray == null) {
       return false;
   }
   var user=matchArray[1];
   var domain=matchArray[2];
   if (user.match(userPat) == null) {
       return false;
   }
   var IPArray = domain.match(ipDomainPat);
   if (IPArray != null) {
       for (var i = 1; i <= 4; i++) {
          if (IPArray[i] > 255) {
             return false;
          }
       }
       return true;
   }
   var domainArray=domain.match(domainPat);
   if (domainArray == null) {
       return false;
   }
   var atomPat=new RegExp(atom,"g");
   var domArr=domain.match(atomPat);
   var len=domArr.length;
   if ((domArr[domArr.length-1].length < 2)) {
       return false;
   }
   return len >= 2;
}

function validateInteger(form) {
    var bValid = true;

    var oInteger = eval('new ' + form.name + '_IntegerValidations()');
    for (var x in oInteger) {
        var field = form[oInteger[x][0]];

		// validation skipped if field not showing on the page
		if (isNotValidate(field)) {
			continue;
		}

        if ((field.type == 'hidden' ||
            field.type == 'text' ||
            field.type == 'textarea' ||
            field.type == 'select-one' ||
            field.type == 'radio') &&
            !field.disabled) {

            var value = '';
            // get field's value
            if (field.type == "select-one") {
                var si = field.selectedIndex;
                if (si >= 0) {
                    value = field.options[si].value;
                }
            } else {
                value = field.value;
            }

            if (value.length > 0) {
                if (value.charAt(0) == '0') value = value.substr(1, value.length)

                if (!isAllDigits(value)) {
                    bValid = false;
	                // save validation data for error showing                    
					addFieldEntry(oInteger[x][0], oInteger[x][1]);

                } else {
                    var iValue = parseInt(value);
                    if (isNaN(iValue) || !(iValue >= -2147483648 && iValue <= 2147483647)) {
		                // save validation data for error showing                    
						addFieldEntry(oInteger[x][0], oInteger[x][1]);
                        bValid = false;
                   } 
               }
           }
        }
    }
    return bValid;
}

function isAllDigits(argvalue) {
    argvalue = argvalue.toString();
    var validChars = "0123456789";
    var startFrom = 0;
    if (argvalue.substring(0, 2) == "0x") {
       validChars = "0123456789abcdefABCDEF";
       startFrom = 2;
    } else if (argvalue.charAt(0) == "0") {
       validChars = "01234567";
       startFrom = 1;
    } else if (argvalue.charAt(0) == "-") {
        startFrom = 1;
    }

    for (var n = startFrom; n < argvalue.length; n++) {
        if (validChars.indexOf(argvalue.substring(n, n+1)) == -1) return false;
    }
    return true;
}

function validateIntRange(form) {
    var isValid = true;

    var oRange = eval('new ' + form.name + '_intRange()');
    for (var x in oRange) {
        var field = form[oRange[x][0]];

		// validation skipped if field not showing on the page
		if (isNotValidate(field)) {
			continue;
		}

        if (!field.disabled)  {
            var value = '';
            if (field.type == 'hidden' ||
                field.type == 'text' || field.type == 'textarea' ||
                field.type == 'radio' ) {
                value = field.value;
            }
            if (field.type == 'select-one') {
                var si = field.selectedIndex;
                if (si >= 0) {
                    value = field.options[si].value;
                }
            }
            if (value.length > 0) {
                if (value.charAt(0) == '0' && value.length > 1) value = value.substr(1, value.length)

                var iMin = parseInt(oRange[x][2]("min"));
                var iMax = parseInt(oRange[x][2]("max"));
                var iValue = parseInt(value);
                if (!(iValue >= iMin && iValue <= iMax)) {
	                // save validation data for error showing                    
					addFieldEntry(oRange[x][0], oRange[x][1]);
                    isValid = false;
                } 
            }
        }
    }
    return isValid;
}

/**
 * Checks if all field, which names was founded in the test parameter, are not empty.
 *
 * WARNING: This is not common function, it doesn't understand all of test expressions.
 *			It should be used carefully.
 */
function validateValidWhenIfNotNull(form) {
	var isValid = true;

	var oValidWhen = eval('new ' + form.name + '_validwhenIfNotNull()');
	for (var x in oValidWhen) {
		var fieldName = oValidWhen[x][0];
		var field = form[fieldName];
		
		// validation skipped if field not showing on the page
		if (isNotValidate(field)) {
			continue;
		}
		
		if (!evaluateCondition(form, fieldName, oValidWhen[x][2]("test"), false)) {
			// save validation data for error showing                    
			addFieldEntry(fieldName, oValidWhen[x][1]);
			isValid = false;
		}
	}
	return isValid;
}

/**
 * Checks if the expression is correct.
 *
 * WARNING: This is not common function, it doesn't understand all of test expressions.
 *			It should be used carefully.
 */
function validateValidWhen(form) {
	var isValid = true;

	var oValidWhen = eval('new ' + form.name + '_validwhen()');
	for (var x in oValidWhen) {
		var fieldName = oValidWhen[x][0];
		var field = form[fieldName];

		if (!evaluateCondition(form, fieldName, oValidWhen[x][2]("test"), true)) {
			// save validation data for error showing
			addFieldEntry(fieldName, oValidWhen[x][1]);
			isValid = false;
		}
	}
	return isValid;
}

/**
 *  Evaluate expression for form fields.
 */
function evaluateCondition(form, fieldName, expression, allowNullValues) {
	var result = true;
	var inBrace = false;
	var c;
	var variable = null;
	var value = null;
	var operation = null;	// ==, != , <=, >=, <, >
	var operator = null;	//and, or

	for (var i = 0; i < expression.length; i++) {
		c = expression.substring(i, i+1);
		if (c == '(') {
			inBrace = true;
		} else if (c == ')') {
			inBrace = false;
			if (variable == null || variable.length == 0
				|| operation == null || operation.length == 0) {
					continue;
			}
			if (variable == '*this*') variable = fieldName;
			
			var exprResult = evaluateExpression(form, variable, operation, value, allowNullValues);
			if (operator == null) {
				result = exprResult;
			} else if (operator == 'and') {
				result = result && exprResult;
			} else if (operator == 'or') {
				result = result || exprResult;
			}
			variable = null;
			operation = null;
			value = null;
			operator = null;
		} else if (c != ' ') {
			if (inBrace) {
				// operation, variable, value
				if ('!=<>'.indexOf(c) > -1) {
					// it's an operation
					operation = expression.substring(i, i+2);
					i++;
				} else if ('0123456789'.indexOf(c) > -1) {
					// digit value
					var end = findEnd(expression, i);
					value = trim(expression.substring(i, end));
					i = end - 1;
				} else if (expression.substring(i, i+4) == 'null') {
					value = allowNullValues? null : '';
					i = i + 3;
				} else {
					// variable
					var end = findEnd(expression, i);
					var tmp = trim(expression.substring(i, end));
					if (variable == null) {
						variable = tmp;
					} else {
						value = tmp;	// e.g. boolean variable
					}
					i = end - 1;
				}
			} else {
				// operator
				var end = findEnd(expression, i);
				operator = trim(expression.substring(i, end));
				i = end - 1;
			}
		}
	}
	return result;
}

/**
 *  Evaluates expression like (<variable> <operation> <value>).
 */
function evaluateExpression(form, variable, operation, value, allowNullValues) {
	var result = false;
	var varValue = null;
	
	if (value == 'null') {
		value = null;
	} else if (value != null) {
		value = value.replace(/[\'\"]/g, '');
	}
	
	var field = form[variable];
	
	if (field != null) {
		if (field.length > 0 && !isSelectElement(field)) {
			// Radio button
			varValue = getRadioValue(field);
			if (!allowNullValues && varValue == null) varValue = '';
		} else {
			varValue = trim(field.value);
			if (varValue == null) {
				varValue = field.value;
			}
		}
	}

	operation = trim(operation);
	if (operation == '!=') {
		result = varValue != value;
	} else if (operation == '<=') {
		result = varValue <= value;
	} else if (operation == '>=') {
		result = varValue >= value;
	} else if (operation == '<') {
		result = varValue < value;
	} else if (operation == '>') {
		result = varValue > value;
	} else if (operation == '==') {
		result = varValue == value;
	}

	return result;
}

/**
 *  Searches the end of the symbol.
 */
function findEnd(str, i) {
	var j = i;
	while (str.substring(j, j+1) != ' ' 
			&& str.substring(j, j+1) != ')'
			&& str.substring(j, j+1) != '(' ) {
		j++;
	}
	return j;
}

/**
 *  Checks if the fields not contains numbers.
 */
function validateNotNumbers(form) {
    var isValid = true;

    var oNotNumbers = eval('new ' + form.name + '_notContainNumbers()');
    for (var x in oNotNumbers) {
        var field = form[oNotNumbers[x][0]];

       	var hasNumbers = false;
        if (!isNotValidate(field)) {
            for (var n = 0; n < field.value.length; n++) {
	        	if ('0123456789'.indexOf(field.value.substring(n, n+1)) > -1) {
	        		hasNumbers = true;
	        		break;
	        	}
		    }
        } 
        if (hasNumbers) {
            // save validation data for error showing                    
			addFieldEntry(oNotNumbers[x][0], oNotNumbers[x][1]);
            isValid = false;
        }
    }
    return isValid;
}

/**
 *  Checks if all subfields of multiple field are matches the massk specified.
 */
function validateMultipleFieldMask(form) {
    var isValid = true;

    var oMultipleMasked = eval('new ' + form.name + '_multipleFieldMask()');
    for (var x in oMultipleMasked) {
		if (isNotValidate(form[oMultipleMasked[x][0]])) {
			continue;
		}
        var fields = oMultipleMasked[x][2]("names");
        var fieldNames = new Array();
        var n = 0;
        while ((n = fields.indexOf(',')) >= 0) {
        	fieldNames[fieldNames.length] = trim(fields.substring(0, n));
        	fields = fields.substring(n+1, fields.length);
        }
        fieldNames[fieldNames.length] = fields;
        for (var i = 0; i <= fieldNames.length; i++) {
        	var field = form[fieldNames[i]];
	        if (!isNotValidate(field)) {
	
	            if (!isMaskMatches(field, oMultipleMasked[x][2]("mask"))) {
	                // save validation data for error showing                    
					addFieldEntry(oMultipleMasked[x][0], oMultipleMasked[x][1]);
	
	                isValid = false;
	                break;
	            } 
	        }
		}
    }
    return isValid;
}

/**
 *  Checks if the date fields are not empty or one of the fields entered if issue number is visible.
 *  Also checks if the date fields and issue number field contain only digits.
 *  Additional validation messages takes from INValidationMessage and SDValidationMessage global varialbes.
 */
function validateStartDate(form) {
    var isValid = true;
	var twoDigitsMask = /^\d{0,2}$/;

    var oStartDate = eval('new ' + form.name + '_startDate ()');
    for (var x in oStartDate) {
    	var result = true;
    	var monthField = form[oStartDate[x][0]];
		if (isNotValidate(form[oStartDate[x][0]])) {
			continue;
		}
		
		var issueNumberField = form[oStartDate[x][2]('issueNumber')];
		var yearField = form[oStartDate[x][2]('yearField')];

		var isYearEmpty = yearField == null || yearField.value == null || yearField.value.length == 0 
							|| yearField.value.indexOf('yy') == 0;
		var isMonthEmpty = monthField == null || monthField.value == null || monthField.value.length == 0 
							|| monthField.value.indexOf('mm') == 0;
		var isIssueNumberEmpty = issueNumberField == null || issueNumberField.value == null 
							|| issueNumberField.value.length == 0;
		var isIssueNumberVisible = !isNotValidate(issueNumberField);
		
		if (isIssueNumberVisible) {
			if (isYearEmpty && isMonthEmpty && isIssueNumberEmpty) {
				addFieldEntry(oStartDate[x][0], oStartDate[x][1]);
				result = false;
			} else {
				result = (isYearEmpty && isMonthEmpty) || (!isYearEmpty && isMaskMatches(yearField, twoDigitsMask)
						&& !isMonthEmpty && isMaskMatches(monthField, twoDigitsMask));
				if (!isMonthEmpty && result) {
					result = monthField.value > 0 && monthField.value < 13;
				}
				if (!result) {
					addFieldEntry(oStartDate[x][0], SDValidationMessage);
				}
				if (!isIssueNumberEmpty && !isMaskMatches(issueNumberField, twoDigitsMask)) {
					addFieldEntry(issueNumberField.name, INValidationMessage);
					result = false;
				}
			}
		} else {
			result = (isYearEmpty && isMonthEmpty) 
					|| (!isYearEmpty && isMaskMatches(yearField, twoDigitsMask)
					&& !isMonthEmpty && isMaskMatches(monthField, twoDigitsMask));
			if (result && !isYearEmpty && !isMonthEmpty) {
				result = monthField.value > 0 && monthField.value < 13;
			}
			if (!result) {
				addFieldEntry(oStartDate[x][0], SDValidationMessage);
			}
		}
		if (result && !isYearEmpty && !isMonthEmpty) {
			var today = new Date();
			today.setDate(1);
			today.setHours(0, 0, 0, 0);
			var startDate = convertDate(1, parseInt(monthField.value), parseYear(yearField.value));
			result = startDate <= today;
			if (!result) {
				addFieldEntry(oStartDate[x][0], FutureStartDateMessage);
			}
		}
		if (!result) {
		    isValid = false;
		}
	}
    return isValid;
}

/**
 *  Checks if the date is valid and is in range specified.
 */
function validateBirthDate(form) {
	var isValid = true;

    var oBirthDate = eval('new ' + form.name + '_birthDate ()');      
    for (var x in oBirthDate) {
    	var result = true;
    	var dayField = form[oBirthDate[x][0]];
		var monthField = form[oBirthDate[x][2]('month')];
		var yearField = form[oBirthDate[x][2]('year')];
		var hasPMField = form[oBirthDate[x][2]('hasPayMonthly')];
		var validationRequiredField = form[oBirthDate[x][2]('validationRequiredFieldName')];

        var validationRequired = true;

        if (null != validationRequiredField) {
            validationRequired = 'false' != validationRequiredField.value
        }

		if (isNotValidate(dayField) || isNotValidate(monthField) || isNotValidate(yearField)) {
			continue;
		}
		var minAge = 0; 
		var maxAge = 1000;
		var paymAge = 0;
		if (oBirthDate[x][2]('minAge') != null) minAge = parseInt(oBirthDate[x][2]('minAge'));
		if (oBirthDate[x][2]('maxAge') != null) maxAge = parseInt(oBirthDate[x][2]('maxAge'));
		if (oBirthDate[x][2]('paymAge') != null) paymAge = parseInt(oBirthDate[x][2]('paymAge'));
		if (paymAge && hasPMField && hasPMField.value == 'true') {
			minAge = paymAge;
		}
		var errorMsg = "";
		if (dayField.value.length == 0) {
			errorMsg = NotSelectedDayMessage;
			result = false;
			if (isValid) dayField = monthField;
		}
		if (monthField.value.length == 0) {
			if (!result) errorMsg = errorMsg + "<br>";
			errorMsg = errorMsg + NotSelectedMonthMessage;
			result = false;
		}
		if (yearField.value.length == 0) {
			if (!result) errorMsg = errorMsg + "<br>";
			errorMsg = errorMsg + NotSelectedYearMessage;
			result = false;
		}
		if (result && validationRequired && !isValidDateOfBirth(dayField.value, monthField.value, yearField.value, minAge, maxAge)) {
			errorMsg = oBirthDate[x][1];
			result = false;
		}
		if (!result) {
	        // save validation data for error showing                    
			addFieldEntry(oBirthDate[x][0], errorMsg);
	        isValid = false;
		}
	}
	return isValid;
}

/**
 *  Converts integer parameters into Date object.
 */
function convertDate(day, month, year) {
	var date = null;
	if (day != null && month != null && year != null) {
		month--;
		date = new Date();
		date.setFullYear(year, month, day);
		date.setHours(0, 0, 0, 0);
		if (date.getMonth() != month) {
			// Date doesn't exist
			date = null;
		}
	}
	return date;
}

/**
 *  Checks if the date is valid and is in range specified.
 */
function isValidDateOfBirth(day, month, year, minAge, maxAge) {
	var dob = convertDate(day, month, year);
	var result = dob != null;
	if (result) {
		var today = new Date();
		// Minimal allowed date of birth
		var minDOB = new Date();
		minDOB.setFullYear(today.getFullYear() - maxAge);
		// Maximum allowed date of birth
		var maxDOB = new Date();
		maxDOB.setFullYear(today.getFullYear() - minAge);
		result = dob >= minDOB && dob <= maxDOB;
	}
	return result;
}

/**
 *  Checks if the date fields are not empty, are digits and month is in range specified.
 */
function validateTimeTwoFields(form) {
    var isValid = true;
	var twoDigitsMask = /^\d{0,2}$/;
	var fourDigitsMask = /^\d{0,4}$/;

	var oTimeTwoFields = eval('new ' + form.name + '_timeTwoFields ()');
    for (var x in oTimeTwoFields) {
    	var result = true;
    	var monthField = form[oTimeTwoFields[x][0]];
		if (isNotValidate(form[oTimeTwoFields[x][0]])) {
			continue;
		}
		var yearField = form[oTimeTwoFields[x][2]('yearField')];

		var isYearEmpty = yearField == null || yearField.value == null || yearField.value.length == 0 
							|| yearField.value.indexOf('yyyy') == 0;
		var isMonthEmpty = monthField == null || monthField.value == null || monthField.value.length == 0 
							|| monthField.value.indexOf('Mmm') == 0;
		
		result = !isYearEmpty;
		var month;
		if (result) {
			var minMonth = parseInt([oTimeTwoFields[x][2]('monthMin')]);
			var maxMonth = parseInt([oTimeTwoFields[x][2]('monthMax')]);
			month = parseInt(monthField.value);
			result = !isMonthEmpty && isMaskMatches(monthField, twoDigitsMask)
						&& (month >= minMonth) && (month <= maxMonth);
			if (result) {
				result = !isYearEmpty && isMaskMatches(yearField, fourDigitsMask);
				if (!result) {
					// Year is invalid

					addFieldEntry(oTimeTwoFields[x][0], InvalidStartYearMessage);
				}
			} else {
				// Month is invalid
				addFieldEntry(oTimeTwoFields[x][0], InvalidStartMonthMessage);
			}
		} else {
			// Both of the fields are empty
			addFieldEntry(oTimeTwoFields[x][0], oTimeTwoFields[x][1]);
		}
		if (result) {
			// Check if not exceed the age
			var dateOfBirthFields = oTimeTwoFields[x][2]('birthDate');
			if (matchPattern(dateOfBirthFields, /^[A-Za-z\d]+\/[A-Za-z\d]+\/[A-Za-z\d]+$/)) {
				var dayFieldName = dateOfBirthFields.replace(/\/[A-Za-z\d]+\/[A-Za-z\d]+$/,"");
				var monthFieldName = dateOfBirthFields.replace(/(^[A-Za-z\d]+\/)|(\/[A-Za-z\d]+$)/g,"");
				var yearFieldName = dateOfBirthFields.replace(/^[A-Za-z\d]+\/[A-Za-z\d]+\//,"");
				if (dayFieldName != null && dayFieldName.length > 0 && monthFieldName != null && monthFieldName.length > 0
						&& yearFieldName != null && yearFieldName.length > 0) {
					var birthDay = form[dayFieldName];
					var birthMonth = form[monthFieldName];
					var birthYear = form[yearFieldName];
					if (birthDay != null && birthMonth != null && birthYear != null) {
						var dob = convertDate(1, parseInt(birthMonth.value), parseInt(birthYear.value));
						var date = convertDate(1, month, parseInt(yearField.value));
						if (dob != null && date != null && date < dob) {
							// Date prior the date of birth.
							addFieldEntry(oTimeTwoFields[x][0], DateExceedMessages(oTimeTwoFields[x][0]));
							result = false;
						}
					}
				}
			}
		}
        if (result) {
            month = parseInt(monthField.value);
            var year = parseInt(yearField.value);

            var today = new Date();
            today.setDate(1);
            today.setHours(0, 0, 0, 0);

            var currentMonth = today.getMonth() + 1;
            var currentYear = today.getFullYear();

            if ((currentYear == year) && (currentMonth < month)) {
                addFieldEntry(oTimeTwoFields[x][0], DateInFutureMessage);
                result = false;
            }

        }
        if (!result) {
		    isValid = false;
		}
	}
    return isValid;
}

function isEmpty(field) {
	if ((field.type == 'hidden' ||
			field.type == 'text' ||
			field.type == 'textarea' ||
			field.type == 'file' ||
			field.type == 'checkbox' ||
			field.type == 'select-one' ||
			field.type == 'password') &&
			!field.disabled) {

		var value = '';

		// get field's value
		if (field.type == "select-one") {
			var si = field.selectedIndex;
			if (si >= 0) {
				value = field.options[si].value;
			}
		} else if (field.type == 'checkbox') {
			if (field.checked) {
				value = field.value;
			}
		} else {
			value = field.value;
		}

		var trValue = trim(value);
		if (!trValue || trValue.length == 0) {
			return true;
		}

	} else if (field.type == "select-multiple") {
		var numOptions = field.options.length;
		lastSelected=-1;
		for(loop=numOptions-1;loop>=0;loop--) {
			if(field.options[loop].selected) {
				lastSelected = loop;
				value = field.options[loop].value;
				break;
			}
		}
		trValue = trim(value);
		if(lastSelected < 0 || !trValue || trValue.length == 0) {
			return true;
		}
	} else if ((field.length > 0) && (field[0].type == 'radio' || field[0].type == 'checkbox')) {
		isChecked=-1;
		for (loop=0;loop < field.length;loop++) {
			if (field[loop].checked) {
				isChecked=loop;
				break; // only one needs to be checked
			}
		}
		if (isChecked < 0) {
			return true;
		}
	}
	return false;
}

function validateRequiredIf(form) {
	var isValid = true;

	var oRequiredIf = eval('new ' + form.name + '_requiredif()');

	for (var x in oRequiredIf) {
		var field = form[oRequiredIf[x][0]];
		// validation skipped if field not showing on the page
		if (isNotValidate(field)) {
			continue;
		}
		if (evaluateCondition(form, field.name, oRequiredIf[x][2]('test')) && isEmpty(field)) {
			// save validation data for error showing
			addFieldEntry(oRequiredIf[x][0], oRequiredIf[x][1]);
			isValid = false;
		}
	}
	return isValid;
}

/**
 *  Checks if the value without spaces mathes the mask specified.
 */
function validateMaskForNonSpace(form) {
	var isValid = true;
	var oMaskForNonSpace = eval('new ' + form.name + '_maskForNonSpace()');
	for (var x in oMaskForNonSpace) {
		var field = form[oMaskForNonSpace[x][0]]
		// validation skipped if field not showing on the page
		if (isNotValidate(field)) {
			continue;
		}
		if ((field.type == 'hidden' ||
			field.type == 'text' ||
			 field.type == 'textarea' ||
			 field.type == 'file') &&
			 (field.value.length > 0) &&
			 !field.disabled) {
			// remove all spaces from value
			var value = field.value.replace(/ /g, '');
			// Check if the non space value matches the mask
			var maskRegexp = new RegExp(oMaskForNonSpace[x][2]("mask_nonsp"));
			if (!matchPattern(value, maskRegexp)) {
				// save validation data for error showing
				addFieldEntry(oMaskForNonSpace[x][0], oMaskForNonSpace[x][1]);
				isValid = false;
			}
		}
	}

	return isValid;
}

/**
 *  Checks if the date is valid date in the past.
 */
function validateSelectedDate(form) {
	var isValid = true;

    var oSelectedDate = eval('new ' + form.name + '_selectedDate ()');
    for (var x in oSelectedDate) {
    	var result = true;
    	var dayField = form[oSelectedDate[x][0]];
		var monthField = form[oSelectedDate[x][2]('month')];
		var yearField = form[oSelectedDate[x][2]('year')];
		if (isNotValidate(dayField) || isNotValidate(monthField) || isNotValidate(yearField)) {
			continue;
		}
		isValid = dayField.value.length > 0 && monthField.value.length > 0 && yearField.value.length > 0
					&& isValidDateOfBirth(dayField.value, monthField.value, yearField.value, 0, 1000);
		if (!isValid) {
			// save validation data for error showing
			addFieldEntry(oSelectedDate[x][0], oSelectedDate[x][1]);
		}
	}
	return isValid;
}

/**
 *  Validates postcode against British Standard BS 7666.
 */
function isValidPostcode(postcode) {
	postcode = postcode.toUpperCase().replace(/\s/g, '');	// Removing of whitespaces and upcasing
	var matchResult = /^GIR0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HK-Y][0-9]|[A-HK-Y][0-9]([0-9]|[ABEHMNPRV-Y]))|[0-9][A-HJKS-UW])[0-9][ABD-HJLNP-UW-Z]{2}$/.exec(postcode);
	return isNotBlank(postcode) && matchResult != null && matchResult[0] == postcode;
}

/**
 *  Checks if the date is valid date in the past.
 */
function validateExpiryDate(form) {
	var isValid = true;

    var oExpiryDate = eval('new ' + form.name + '_expiryDate ()');
    for (var x in oExpiryDate) {
    	var monthField = form[oExpiryDate[x][0]];
		var yearField = form[oExpiryDate[x][2]('expiryYear')];
		if (isNotValidate(monthField) || isNotValidate(yearField)) {
			continue;
		}
		isValid = monthField.value.length > 0 && yearField.value.length > 0;

		var msg = oExpiryDate[x][1];;
		if (isValid) {
			msg = PastExpiryDateMessage;
			isValid = isValidExpiryDate(monthField.value, yearField.value);
			if (isValid) {
				msg = CloserTodayExpiryDateMessage;
				isValid = isExpiryDateCloserToday(monthField.value, yearField.value, 10);
			}
		}
		if (!isValid) {
			// save validation data for error showing
			addFieldEntry(oExpiryDate[x][0], msg);
		}
	}
	return isValid;
}

/**
 * Checks if the expiry date is closer today.
 */
function isExpiryDateCloserToday(mStr, yStr, yearRange) {
	var year = parseYear(yStr);
	var exp = convertDate(1, mStr, year);
	var result = exp != null;
	if (result) {
		var closerToday = getToday();
		closerToday.setFullYear(closerToday.getFullYear() + yearRange);
		result = exp <= closerToday;
	}
	return result;
}

/**
 *  Checks if the expiry date specified is now or is in a future.
 */
function isValidExpiryDate(month, yearStr) {
	var year = parseYear(yearStr);
	var exp = convertDate(1, month, year);
	var result = exp != null;
	if (result) {
		var today = getToday();
		result = exp >= today;
	}
	return result;
}

/**
 * Checks if the value of the field specified is matches the mask provided.
 */
function isMaskMatches(field, mask) {
	var result = false;
	if (field && field.value) {
		var matchResult = mask.exec(field.value);
		result = matchResult != null && matchResult[0] == field.value;
	}
	return result;
}
