/************************************************************************************
 Segnant Advanced Form Validator 
 An easiest way to apply checks on forms. You can use inbuilt form checks functions
 or you can call your own custom functions. Document is avaibable at: 
 ./documentations/index.html
 File also contains a working example of validation rules. 
 For any bug or suggestions please contact me at SteveCurry@Segnant.com
 Creation Date: Sept 19, 2007
*************************************************************************************/
var undef;
var internalRules;

// Parent function for the validator script.
// It calls other validator functions to collect
// rules to apply and the fields which contains errors.
function performCheck(formName, strRules, alertType) 
{
    var rules = makeRules(strRules);
    internalRules = makeRules(strRules);
    this.f = document.forms[formName];
    if( !this.f ) 
	{
        debug('DEBUG: could not find form object ' + formName);
        return null;
    }
    var errors = new Array();
    var ix = 0;
    if (rules.length) 
	{
        for(var i=0; i<rules.length; i++) 
		{
            var aRule = rules[i];
            if (aRule!=null) 
			{
                highlight(getField(f, aRule.el), inputclassnormal);
            }
        }
    } 
	else 
	{
        if (rules!=null) 
		{
            highlight(getField(f, rules.el), inputclassnormal);
        }
    }
    if (rules.length) 
	{
        for(var i=0; i<rules.length; i++) 
		{
            var aRule = rules[i];
            var anErr = null;
            if (aRule==null) 
			{
                //do nothing
            } 
			else if (aRule.ruleType=='pre-condition' || aRule.ruleType=='post-condition') 
			{
                //do nothing
            } 
			else if (aRule.ruleName=='implies') 
			{
                pre  = aRule.el;
                post = aRule.comparisonValue;
				
                var oldClassName = getField(f, rules[pre].el).className;
                if ( checkRule(f, rules[pre])==null && checkRule(f, rules[post])!=null ) 
				{
                    anErr = aRule.alertMsg;
                } 
				else if ( checkRule(f, rules[pre])!=null ) 
				{
                    getField(f, rules[pre].el).className = oldClassName;
                }
            } 
			else 
			{
                anErr = checkRule(f, aRule);
            }
            if ( anErr!=null ) 
			{
                errors[ix] = anErr;
                ix++;
            }
        }//for
    } 
	else 
	{
        var myRule = rules;
        err = checkRule(f, myRule);
        if ( err!=null ) 
		{
            errors[0] = err;
        }
    }
    return displayAlert(errors, alertType);
}

// Key for keypress. 
// Function used in keypress rule
// It allow the user to type only certain defined characters
function checkKeyPress(ev, obj, strRules) 
{
    var keyCode = null;
    if ( getBrowser()=='msie' ) 
	{
        keyCode = window.event.keyCode;
    } 
	else if ( getBrowser()=='netscape' || getBrowser()=='firefox' ) 
	{
        keyCode = ev.which;
    }
    var rules = makeRules(strRules);
    var keyAllowed = true;
    if (rules.length) 
	{
        for(var i=0; i<rules.length; i++) 
		{
            var aRule = rules[i];
            if (aRule.ruleName=='keypress' && aRule.el==obj.name) 
			{
                keyAllowed = isKeyAllowed(keyCode, aRule.comparisonValue);
                break;
            }
        }
    } 
	else 
	{
        var aRule = rules;
        if (aRule.ruleName=='keypress' && aRule.el==obj.name) 
		{
            keyAllowed = isKeyAllowed(keyCode, aRule.comparisonValue);
        }
    }
    if (!keyAllowed) 
	{
        if ( getBrowser()=='msie' ) 
		{
            window.event.keyCode=0;
        } 
		else if ( getBrowser()=='netscape' || getBrowser()=='firefox' ) 
		{
            ev.preventDefault();
            ev.stopPropagation();
            ev.returnValue=false;
        }
    }
    return false;
}

// Function to control the type of alert you want.
// Classic is the basic javascript alert (all errors in one alert)
// innerHTML to display errors in the form of innerHtml in a DIV
// jsVar also display errors in alert but they are developer friendly errors.
function displayAlert(messages, alertType) 
{
    var retval =null;
    if (alertType=='classic') 
	{
        retval = displayClassic(messages);
    } 
	else if (alertType=='innerHtml') 
	{
        retval = displayInnerHtml(messages);
    }
	else if (alertType=='jsVar') 
	{
        retval = displayJsVar(messages);
    } 
	else 
	{
        debug('DEBUG: alert type ' + alertType + ' not supported');
    }
    return retval;
}

// This function is called if the user choose 'classis' type alerts.
// It is defined in the onsubmit of form tab. 
// Syntax: onsubmit="return performCheck('formName', rules, 'classic');"
function displayClassic(messages) 
{
    var str = '';
    if ( messages!=null && messages.length>0 ) 
	{
    	if (strTrim(HEADER_MSG).length > 0) 
		{
            str += HEADER_MSG + '\n\n';
        }
        for (var i=0; i<messages.length; i++) 
		{
            str += ' ' + messages[i] + '\n';
        }
    	if (strTrim(FOOTER_MSG).length > 0) 
		{
            str += '\n' + FOOTER_MSG;
        }
        alert(str);
        return false;
    } 
	else 
	{
    	return true;
    }
}

// This function is called if the user choose 'innerHtml' type alerts.
// It is defined in the onsubmit of form tab. 
// Syntax: onsubmit="return performCheck('formName', rules, 'innerHtml');"
function displayInnerHtml(messages) 
{
    if ( messages!=null && messages.length>0 ) 
	{
        var str = '';
    	if (strTrim(HEADER_MSG).length > 0) 
		{
            str += HEADER_MSG;
        }
        str += '<ul>';
        for (var i=0; i<messages.length; i++) 
		{
            str += '<li>'+messages[i]+'</li>';
        }
        str += '</ul>';
    	if (strTrim(FOOTER_MSG).length > 0) 
		{
            str += FOOTER_MSG;
        }
        document.getElementById(errorsdiv).innerHTML = str;
        document.getElementById(errorsdiv).className = innererror;
        document.getElementById(errorsdiv).style.display = 'block';
        return false;
    } 
	else 
	{
        document.getElementById(errorsdiv).innerHTML = '';
        document.getElementById(errorsdiv).className = '';
        document.getElementById(errorsdiv).style.display = 'none';
        return true;
    }
}

// This function is called if the user choose 'jsVar' type alerts.
// It is defined in the onsubmit of form tab. 
// Syntax: onsubmit="return performCheck('formName', rules, 'jsVar');"
function displayJsVar(messages) 
{
    document.getElementById(errorsdiv).className = '';
    document.getElementById(errorsdiv).style.display = 'none';
    if ( messages!=null && messages.length>0 ) 
	{
        var str = '';
        str += '<script>var jsErrors;</script>';
        document.getElementById(errorsdiv).innerHTML = str;
        jsErrors = messages;
        return false;
    } 
	else 
	{
        document.getElementById(errorsdiv).innerHTML = '<script>var jsErrors;</script>';
        return true;
    }
}

// Master function for defining rules.
// It will read the rules defined by the user
// Parse them, assign values to object variables.
function rule(el, ruleName, comparisonValue, alertMsg, ruleType) 
{
    if ( !checkArguments(arguments) ) 
	{
        return false;
    }
    tmp = el.split(':');
    nameDisplayed = '';
    if (tmp.length == 2) 
	{
        nameDisplayed = tmp[1];
        el = tmp[0];
    }
    this.el = el;
    this.nameDisplayed = nameDisplayed;
    this.ruleName = ruleName;
    this.comparisonValue = comparisonValue;
    this.ruleType = ruleType;
    if (alertMsg==undef || alertMsg==null) 
	{
        this.alertMsg = getDefaultMessage(el, nameDisplayed, ruleName, comparisonValue);
    } 
	else 
	{
        this.alertMsg = alertMsg;
    }
}

// Checks what rule has been applied on what field.
// If that rule is defined then it will call its desired function
// and execute the code defined for that rule.
// If an error occurs it will update the err object with a 
// proper message.
function checkRule(f, myRule) 
{
    retVal = null;
    if (myRule != null) 
	{
        if (myRule.ruleName=='custom') 
		{
            var customFunction = ' retVal = ' + myRule.el;
            eval(customFunction);
        } 
		else if (myRule.ruleName=='and') 
		{
            var op_1 = myRule.el;
            var op_next = myRule.comparisonValue;
            if ( checkRule(f, internalRules[op_1])!=null ) 
			{
                retVal = myRule.alertMsg;
                if (myRule.ruleType=='pre-condition') 
				{
                    highlight(getField(f, internalRules[op_1].el), inputclassnormal);
                }
            } 
			else 
			{
                var op_k = op_next.split('-');
                for(var k=0; k<op_k.length; k++) 
				{
                    if ( checkRule(f, internalRules[op_k[k]])!=null ) 
					{
                        retVal = myRule.alertMsg;
                        if (myRule.ruleType=='pre-condition') 
						{
                            highlight(getField(f, internalRules[op_k[k]].el), inputclassnormal);
                        }
                        break;
                    }
                }
            }
        } 
		else if (myRule.ruleName=='or') 
		{
            var op_1 = myRule.el;
            var op_next = myRule.comparisonValue;
            var success = false;
            if ( checkRule(f, internalRules[op_1])==null ) 
			{
                success = true;
            } 
			else 
			{
                if (myRule.ruleType=='pre-condition') 
				{
                    highlight(getField(f, internalRules[op_1].el), inputclassnormal);
                }
                var op_k = op_next.split('-');
                for(var k=0; k<op_k.length; k++) 
				{
                    if ( checkRule(f, internalRules[op_k[k]])==null ) 
					{
                        success = true;
                        break;
                    } 
					else 
					{
                        if (myRule.ruleType=='pre-condition') 
						{
                            highlight(getField(f, internalRules[op_k[k]].el), inputclassnormal);
                        }
                    }
                }
            }
            if (!success) 
			{
                retVal = myRule.alertMsg;
            }
        } 
		else 
		{
            el = getField(f, myRule.el);
            if (el == null) 
			{
                debug('DEBUG: could not find element ' + myRule.el);
                return null;
            }
            var err = null;
            if(el.type) 
			{
				if(el.type=='hidden'||el.type=='text'||el.type=='password'||el.type=='textarea') 
				{
                    err = checkText(el, myRule);
                } 
				else if(el.type=='checkbox') 
				{
                    err = checkCheckbox(el, myRule);
                } 
				else if(el.type=='select-one') 
				{
                    err = checkSelOne(el, myRule);
                } 
				else if(el.type=='select-multiple') 
				{
                    err = checkSelMul(el, myRule);
                } 
				else if(el.type=='radio') 
				{
                    err = checkRadio(el, myRule);
                } 
				else if(el.type=='file')
				{
					err = checkFileUpload(el, myRule);	
				}
				else 
				{
                    debug('DEBUG: type '+ el.type +' not supported');
                }
            } 
			else 
			{
                err = checkRadio(el, myRule);
            }
            retVal = err;
        }
    }
    return retVal;
}

// Function check for the arguments passed to the rule.
// Function called in rules function
function checkArguments(args) 
{
    if (args.length < 4) 
	{
        debug('DEBUG: rule requires four arguments at least');
        return false;
    } 
	else if (args[0]==null || args[1]==null) 
	{
        debug('DEBUG: el and ruleName are required');
        return false;
    }
    return true;
}

// Function called in checkRule() function
// If the rule is applied on a radio button
// then this block of code executes.
function checkRadio(el, myRule) 
{
    var err = null;
    if (myRule.ruleName=='required') 
	{
        var radios = el;
	    var found=false;
	    if (isNaN(radios.length) && radios.checked) 
		{
	    	found=true;
	    } 
		else 
		{
		    for(var j=0; j < radios.length; j++) 
			{
		        if(radios[j].checked) 
				{
		            found=true;
		            break;
		        }
		    }
		}
        if( !found ) 
		{
            highlight(el, inputclasserror);
            err = myRule.alertMsg;
        }
    } 
	else if (myRule.ruleName=='equal') 
	{
        var radios = el;
	    var found=false;
	    if (isNaN(radios.length) && radios.checked) 
		{
	    	if (radios.value==myRule.comparisonValue) 
			{
	    	    found=true;
	    	}
	    } 
		else 
		{
		    for(var j=0; j < radios.length; j++) 
			{
		        if(radios[j].checked) 
				{
        	    	if (radios[j].value==myRule.comparisonValue) 
					{
        	    	    found=true;
                        break;
        	    	}
		        }
		    }
		}
        if( !found ) 
		{
            err = myRule.alertMsg;
        }
    } 
	else if (myRule.ruleName=='notequal') 
	{
        var radios = el;
	    var found=false;
	    if (isNaN(radios.length) && radios.checked) 
		{
	    	if (radios.value!=myRule.comparisonValue) 
			{
	    	    found=true;
	    	}
	    } 
		else 
		{
		    for(var j=0; j < radios.length; j++) 
			{
		        if(radios[j].checked) 
				{
        	    	if (radios[j].value!=myRule.comparisonValue) 
					{
        	    	    found=true;
                        break;
        	    	}
		        }
		    }
		}
        if( !found ) 
		{
            err = myRule.alertMsg;
        }
    } 
	else 
	{
        debug('DEBUG: rule ' + myRule.ruleName + ' not supported for radio');
    }
    return err;
}

// Function called in checkRule() function
// If the rule is applied on a text, textarea, hidden, password field
// then this block of code executes.
function checkText(el, myRule) 
{
    err = null;
    if (trimenabled) 
	{
    	el.value = strTrim(el.value);
    }
    if (myRule.ruleName=='required') 
	{
        if ( el.value==null || el.value=='' ) 
		{
            highlight(el, inputclasserror);
            err = myRule.alertMsg;
        }
    } 
	else if (myRule.ruleName=='equal') 
	{
        err = checkEqual(el, myRule);
    } 
	else if (myRule.ruleName=='notequal') 
	{
        err = checkNotEqual(el, myRule);
    } 
	else if (myRule.ruleName=='numeric') 
	{
        reg = new RegExp("^[0-9]*$");
        if ( !reg.test(el.value) ) 
		{
            highlight(el, inputclasserror);
            err = myRule.alertMsg;
        }
    } 
	else if (myRule.ruleName=='above') 
	{
        if ( isNaN(myRule.comparisonValue) ) 
		{
            debug('DEBUG: comparisonValue for rule ' + myRule.ruleName + ' not a number');
        } 
		else if ( el.value < myRule.comparisonValue ) 
		{
            highlight(el, inputclasserror);
            err = myRule.alertMsg;
        }
    }
	else if (myRule.ruleName=='alphabetic') 
	{
        reg = new RegExp("^[A-Za-z]*$");
        if ( !reg.test(el.value) ) 
		{
            highlight(el, inputclasserror);
            err = myRule.alertMsg;
        }
    } 
	else if (myRule.ruleName=='alphabeticspace') 
	{
        reg = new RegExp("^[A-Za-z ]*$");
        if ( !reg.test(el.value) ) 
		{
            highlight(el, inputclasserror);
            err = myRule.alertMsg;
    	}	
    } 
	else if (myRule.ruleName=='alphanumeric') 
	{
        reg = new RegExp("^[A-Za-z0-9]*$");
        if ( !reg.test(el.value) ) 
		{
            highlight(el, inputclasserror);
            err = myRule.alertMsg;
        }
    } 
	else if (myRule.ruleName=='alnumhyphen') 
	{
        reg = new RegExp("^[A-Za-z0-9\-_]*$");
        if ( !reg.test(el.value) ) 
		{
            highlight(el, inputclasserror);
            err = myRule.alertMsg;
        }
    } 
	else if (myRule.ruleName=='alnumhyphenat') 
	{
        reg = new RegExp("^[A-Za-z0-9\-_@]*$");
        if ( !reg.test(el.value) ) 
		{
            highlight(el, inputclasserror);
            err = myRule.alertMsg;
        }
    } 
	else if (myRule.ruleName=='alphaspace') 
	{
        reg = new RegExp("^[A-Za-z0-9\-_ \n\r\t]*$");
        if ( !reg.test(el.value) ) 
		{
            highlight(el, inputclasserror);
            err = myRule.alertMsg;
        }
    }
	else if (myRule.ruleName=='below') 
	{
        if ( isNaN(myRule.comparisonValue) ) 
		{
            debug('DEBUG: comparisonValue for rule ' + myRule.ruleName + ' not a number');
        } 
		else if ( el.value > myRule.comparisonValue ) 
		{
            highlight(el, inputclasserror);
            err = myRule.alertMsg;
        }
    } 
	else if (myRule.ruleName=='email') 
	{
        reg = new RegExp("^(([0-9a-zA-Z]+[-._+&])*[0-9a-zA-Z]+@([-0-9a-zA-Z]+[.])+[a-zA-Z]{2,6}){0,1}$");
        if ( !reg.test(el.value) ) 
		{
            highlight(el, inputclasserror);
            err = myRule.alertMsg;
        }
    }
	else if (myRule.ruleName=='phone') 
	{
		var checkVal = el.value;
		var phone = /^((\+\d{1,3}(-| )?\(?\d\)?(-| )?\d{1,5})|(\(?\d{2,6}\)?))(-| )?(\d{3,4})(-| )?(\d{4})(( x| ext)\d{1,5}){0,1}$/; 
		if ((!checkVal.match(phone)) && checkVal != "")
		{
			highlight(el, inputclasserror);
            err = myRule.alertMsg;
		} 
    }
	else if (myRule.ruleName=='url') 
	{
        reg = new RegExp("^(https?|ftp):\/\/.*$");
        if (el.value != "")
		{
			if ( !reg.test(el.value) ) 
			{
				highlight(el, inputclasserror);
				err = myRule.alertMsg;
			}
		}
    } 
	else if (myRule.ruleName=='maxlength') 
	{
        if ( isNaN(myRule.comparisonValue) ) 
		{
            debug('DEBUG: comparisonValue for rule ' + myRule.ruleName + ' not a number');
        }
		else if ( el.value.length > myRule.comparisonValue ) 
		{
            highlight(el, inputclasserror);
            err = myRule.alertMsg;
        }
    } 
	else if (myRule.ruleName=='minlength') 
	{
        if ( isNaN(myRule.comparisonValue) ) 
		{
            debug('DEBUG: comparisonValue for rule ' + myRule.ruleName + ' not a number');
        } 
		else if ( el.value.length < myRule.comparisonValue ) 
		{
            highlight(el, inputclasserror);
            err = myRule.alertMsg;
        }
    } 
	else if (myRule.ruleName=='numrange') 
	{
        reg = new RegExp("^[-+]{0,1}[0-9]*[.]{0,1}[0-9]*$");
        if ( !reg.test(unformatNumber(el.value)) ) 
		{
            highlight(el, inputclasserror);
            err = myRule.alertMsg;
        } 
		else 
		{
            regRange = new RegExp("^[0-9]+-[0-9]+$"); 
            if ( !regRange.test(myRule.comparisonValue) ) 
			{
                debug('DEBUG: comparisonValue for rule ' + myRule.ruleName + ' not in format number1-number2');
            } 
			else 
			{
                rangeVal = myRule.comparisonValue.split('-');
                if (eval(unformatNumber(el.value))<eval(rangeVal[0]) || eval(unformatNumber(el.value))>eval(rangeVal[1])) 
				{
                    highlight(el, inputclasserror); 
                    err = myRule.alertMsg;
                }
            }
        }
    } 
	else if (myRule.ruleName=='regexp') 
	{
        reg = new RegExp(myRule.comparisonValue);
        if ( !reg.test(el.value) ) 
		{
            highlight(el, inputclasserror);
            err = myRule.alertMsg;
        }
    }
	else if (myRule.ruleName=='integer') 
	{
        err = checkInteger(el, myRule);
    } 
	else if (myRule.ruleName=='double') 
	{
        err = checkDouble(el, myRule);
    } 
	else if (myRule.ruleName=='date') 
	{
        err = checkDate(el, myRule);
    } 
	else if (myRule.ruleName=='date_gt') 
	{
        err = checkDateMoreThan(el, myRule, false);
    } 
	else if (myRule.ruleName=='date_ge') 
	{
        err = checkDateMoreThan(el, myRule, true);
    } 
	else if (myRule.ruleName=='date_lt') 
	{
        err = checkDateLessThan(el, myRule, false);
    } 
	else if (myRule.ruleName=='date_le') 
	{
        err = checkDateLessThan(el, myRule, true);
    } 
	else if (myRule.ruleName=='keypress') 
	{
        // do nothing
    } 
	else if (myRule.ruleName=='empty') 
	{
        if ( el.value!=null && el.value!='' ) 
		{
            highlight(el, inputclasserror);
            err = myRule.alertMsg;
        }
    } 
	else 
	{
        debug('DEBUG: rule ' + myRule.ruleName + ' not supported for ' + el.type);
    }
    return err;
}

// Function called if the rule applied is 'integer'
// Syntax: fieldName:nameDisplayed|integer|msg
function checkInteger(el, myRule) 
{
    reg = new RegExp("^[-+]{0,1}[0-9]*$");
    if ( !reg.test(el.value) ) 
	{
        highlight(el, inputclasserror);
        return myRule.alertMsg;
    }
}

// Function called if the rule applied is 'double'
// Syntax: fieldName:nameDisplayed|double|msg
function checkDouble(el, myRule) 
{
    var sep = DECIMAL_SEP;
    reg = new RegExp("^[-+]{0,1}[0-9]*[" + sep + "]{0,1}[0-9]*$");
    if ( !reg.test(el.value) ) 
	{
        highlight(el, inputclasserror);
        return myRule.alertMsg;
    }
}

// Function called if the rule applied is 'date'
// Validates if the field containing value is a valid data.
// You can define the date format in safv-config.js file.
// Syntax: fieldName:nameDisplayed|date|msg
function checkDate(el, myRule) 
{
    error = null;
    if (el.value!='') 
	{
        var dateFormat = DATE_FORMAT;
        ddReg = new RegExp("dd");
        MMReg = new RegExp("MM");
        yyyyReg = new RegExp("yyyy");
        if ( !ddReg.test(dateFormat) || !MMReg.test(dateFormat) || !yyyyReg.test(dateFormat)  ) 
		{
            debug('DEBUG: locale format ' + dateFormat + ' not supported');
        } 
		else 
		{
            ddStart = dateFormat.indexOf('dd');
            MMStart = dateFormat.indexOf('MM');
            yyyyStart = dateFormat.indexOf('yyyy');
        }
        strReg = dateFormat.replace('dd','[0-9]{2}').replace('MM','[0-9]{2}').replace('yyyy','[0-9]{4}');
        reg = new RegExp("^" + strReg + "$");
        if ( !reg.test(el.value) ) 
		{
            highlight(el, inputclasserror);
            error = myRule.alertMsg;
        } 
		else 
		{
            dd   = el.value.substring(ddStart, ddStart+2);
            MM   = el.value.substring(MMStart, MMStart+2);
            yyyy = el.value.substring(yyyyStart, yyyyStart+4);
            if ( !checkddMMyyyy(dd, MM, yyyy) ) 
			{
                highlight(el, inputclasserror);
                error = myRule.alertMsg;
            }
        }
    }
    return error;
}

// Function called if the rule applied is 'date_gt' or 'date_ge'
// Validates if the field containing value is has a date greater than its second date parameter.
// Syntax: fieldName:nameDisplayed|date_gt|dateValue|msg
// Syntax: fieldName:nameDisplayed|date_ge|dateValue|msg
function checkDateMoreThan(el, myRule, isEqualAllowed) 
{
    error = null;
    var isDate = checkDate(el, myRule)==null ? true : false;
    if ( isDate && el.value!='' ) 
	{
        var dateFormat = DATE_FORMAT;
        ddStart = dateFormat.indexOf('dd');
        MMStart = dateFormat.indexOf('MM');
        yyyyStart = dateFormat.indexOf('yyyy');
        dd   = el.value.substring(ddStart, ddStart+2);
        MM   = el.value.substring(MMStart, MMStart+2);
        yyyy = el.value.substring(yyyyStart, yyyyStart+4);
        myDate = "" + yyyy + MM + dd;
        strReg = dateFormat.replace('dd','[0-9]{2}').replace('MM','[0-9]{2}').replace('yyyy','[0-9]{4}');
        reg = new RegExp("^" + strReg + "$");
        var isMeta = myRule.comparisonValue.indexOf('$')==0 
            ? true
            : false;
        var comparisonDate = '';
        if (isMeta) 
		{
            toSplit = myRule.comparisonValue.substr(1);
            tmp = toSplit.split(':');
            if (tmp.length == 2) 
			{
                comparisonDate = this.getField(f, tmp[0]).value;
            } 
			else 
			{
                comparisonDate = this.getField(f, myRule.comparisonValue.substr(1)).value;
            }
        } 
		else 
		{
            comparisonDate = myRule.comparisonValue;
        }
        if ( !reg.test(comparisonDate) ) 
		{
            highlight(el, inputclasserror);
            error = myRule.alertMsg;
        }
		else 
		{
            cdd   = comparisonDate.substring(ddStart, ddStart+2);
            cMM   = comparisonDate.substring(MMStart, MMStart+2);
            cyyyy = comparisonDate.substring(yyyyStart, yyyyStart+4);
            cDate = "" + cyyyy + cMM + cdd;
            if (isEqualAllowed) 
			{
                if ( !checkddMMyyyy(cdd, cMM, cyyyy) || myDate<cDate ) 
				{
                    highlight(el, inputclasserror);
                    error = myRule.alertMsg;
                }
            } 
			else 
			{
                if ( !checkddMMyyyy(cdd, cMM, cyyyy) || myDate<=cDate ) 
				{
                    highlight(el, inputclasserror);
                    error = myRule.alertMsg;
                }
            }
        }
    } 
	else 
	{
        if ( el.value!='' ) 
		{
            highlight(el, inputclasserror);
            error = myRule.alertMsg;
        }
    }
    return error;
}

// Function called if the rule applied is 'date_lt' or 'date_le'
// Validates if the field containing value is has a date less than its second date parameter.
// Syntax: fieldName:nameDisplayed|date_lt|dateValue|msg
// Syntax: fieldName:nameDisplayed|date_le|dateValue|msg
function checkDateLessThan(el, myRule, isEqualAllowed) 
{
    error = null;
    var isDate = checkDate(el, myRule)==null ? true : false;
    if ( isDate && el.value!='' ) 
	{
        var dateFormat = DATE_FORMAT;
        ddStart = dateFormat.indexOf('dd');
        MMStart = dateFormat.indexOf('MM');
        yyyyStart = dateFormat.indexOf('yyyy');
        dd   = el.value.substring(ddStart, ddStart+2);
        MM   = el.value.substring(MMStart, MMStart+2);
        yyyy = el.value.substring(yyyyStart, yyyyStart+4);
        myDate = "" + yyyy + MM + dd;
        strReg = dateFormat.replace('dd','[0-9]{2}').replace('MM','[0-9]{2}').replace('yyyy','[0-9]{4}');
        reg = new RegExp("^" + strReg + "$");
        var isMeta = myRule.comparisonValue.indexOf('$')==0 
            ? true
            : false;
        var comparisonDate = '';
        if (isMeta) 
		{
            toSplit = myRule.comparisonValue.substr(1);
            tmp = toSplit.split(':');
            if (tmp.length == 2) 
			{
                comparisonDate = this.getField(f, tmp[0]).value;
            } 
			else 
			{
                comparisonDate = this.getField(f, myRule.comparisonValue.substr(1)).value;
            }
        } 
		else 
		{
            comparisonDate = myRule.comparisonValue;
        }
        if ( !reg.test(comparisonDate) ) 
		{
            highlight(el, inputclasserror);
            error = myRule.alertMsg;
        }
		else 
		{
            cdd   = comparisonDate.substring(ddStart, ddStart+2);
            cMM   = comparisonDate.substring(MMStart, MMStart+2);
            cyyyy = comparisonDate.substring(yyyyStart, yyyyStart+4);
            cDate = "" + cyyyy + cMM + cdd;
            if (isEqualAllowed) 
			{
                if ( !checkddMMyyyy(cdd, cMM, cyyyy) || myDate>cDate ) 
				{
                    highlight(el, inputclasserror);
                    error = myRule.alertMsg;
                }
            } 
			else 
			{
                if ( !checkddMMyyyy(cdd, cMM, cyyyy) || myDate>=cDate ) 
				{
                    highlight(el, inputclasserror);
                    error = myRule.alertMsg;
                }
            }
        }
    } 
	else 
	{
        if ( el.value!='' ) 
		{
            highlight(el, inputclasserror);
            error = myRule.alertMsg;
        }
    }
    return error;
}

// function called to check that the two parameters passed
// in the rule have equal value or not.
// Used for rule 'equal'
// Syntax: fieldName:nameDisplayed|equal|textValue|msg
function checkEqual(el, myRule) 
{
    error = null;
    var isMeta = myRule.comparisonValue.indexOf('$')==0 
        ? true
        : false;
    var comparisonVal = '';
    if (isMeta) 
	{
        toSplit = myRule.comparisonValue.substr(1);
        tmp = toSplit.split(':');
        if (tmp.length == 2) 
		{
            comparisonVal = this.getField(f, tmp[0]).value;
        } 
		else 
		{
            comparisonVal = this.getField(f, myRule.comparisonValue.substr(1)).value;
        }
    } 
	else 
	{
        comparisonVal = myRule.comparisonValue;
    }
    if ( el.value!=comparisonVal ) 
	{
        highlight(el, inputclasserror);
        error = myRule.alertMsg;
    }
    return error;
}

// function called to check that the two parameters passed
// in the rule are must not be equal.
// Used for rule 'notequal'
// Syntax: fieldName:nameDisplayed|notequal|textValue|msg
function checkNotEqual(el, myRule) 
{
    error = null;
    var isMeta = myRule.comparisonValue.indexOf('$')==0 
        ? true
        : false;
    var comparisonVal = '';
    if (isMeta) 
	{
        toSplit = myRule.comparisonValue.substr(1);
        tmp = toSplit.split(':');
        if (tmp.length == 2) 
		{
            comparisonVal = this.getField(f, tmp[0]).value;
        } 
		else 
		{
            comparisonVal = this.getField(f, myRule.comparisonValue.substr(1)).value;
        }
    } 
	else 
	{
        comparisonVal = myRule.comparisonValue;
    }
    if ( el.value==comparisonVal ) 
	{
        highlight(el, inputclasserror);
        error = myRule.alertMsg;
    }
    return error;
}

// Internal function to see if the value
// entered in the month, date and year are valid or not.
function checkddMMyyyy(dd, MM, yyyy) 
{
    retVal = true;
    if (    (dd > 31) || (MM > 12) ||
            (dd==31 && (MM==2 || MM==4 || MM==6 || MM==9 || MM==11) ) ||
            (dd >29 && MM==2) ||
            (dd==29 && (MM==2) && ((yyyy%4 > 0) || (yyyy%4==0 && yyyy%100==0 && yyyy%400>0 )) )) 
	{
       retVal = false;
    }
    return retVal;
}

// Internal function, it is called if the rule is applied
// on a check box. 
function checkCheckbox(el, myRule) 
{
    if (myRule.ruleName=='required') 
	{
        if ( !el.checked ) 
		{
            highlight(el, inputclasserror);
            return myRule.alertMsg;
        }
    } 
	else if (myRule.ruleName=='equal') 
	{
        if ( !el.checked || el.value!=myRule.comparisonValue ) 
		{
            highlight(el, inputclasserror);
            return myRule.alertMsg;
        }
    } 
	else if (myRule.ruleName=='notequal') 
	{
        if ( !el.checked || el.value==myRule.comparisonValue ) 
		{
            highlight(el, inputclasserror);
            return myRule.alertMsg;
        }
    } 
	else 
	{
        debug('DEBUG: rule ' + myRule.ruleName + ' not supported for ' + el.type);
    }
}

// Internal function, it is called if the rule is 
// applied on a select box
function checkSelOne(el, myRule) 
{
    if (myRule.ruleName=='required') 
	{
        var found = false;
        var inx = el.selectedIndex;
        if(inx>=0 && el.options[inx].value) 
		{
            found = true;
        }
        if ( !found ) 
		{
            highlight(el, inputclasserror);
            return myRule.alertMsg;
        }
    } 
	else if (myRule.ruleName=='equal') 
	{
        var found = false;
        var inx = el.selectedIndex;
        if(inx>=0 && el.options[inx].value==myRule.comparisonValue) 
		{
            found = true;
        }
        if ( !found ) 
		{
            highlight(el, inputclasserror);
            return myRule.alertMsg;
        }
    } 
	else if (myRule.ruleName=='notequal') 
	{
        var found = false;
        var inx = el.selectedIndex;
        if(inx>=0 && el.options[inx].value!=myRule.comparisonValue) 
		{
            found = true;
        }
        if ( !found ) 
		{
            highlight(el, inputclasserror);
            return myRule.alertMsg;
        }
    } 
	else 
	{
        debug('DEBUG: rule ' + myRule.ruleName + ' not supported for ' + el.type);
    }
}

// Internal function, it is called if the rule is 
// applied on a file field to validate if the 
// field has a right file extension.
// Syntax: fieldName:nameDisplayed|fileext|textValue|msg
function checkFileUpload(el, myRule) 
{
	err = null;
	if (myRule.ruleName=='required') 
	{
	   if ( el.value==null || el.value=='' ) 
		{
            highlight(el, inputclasserror);
            err = myRule.alertMsg;
        }
    } 
	else if (myRule.ruleName=='fileext') 
	{
		if (el.value != "")
		{
			myFileName = el.value;		
			allowedExt = myRule.comparisonValue;
			myFileName = myFileName.toLowerCase();
			allowedExt = allowedExt.toLowerCase();
			myExt = new Array();
			myExt = allowedExt.split(",");
			var arrayLen = 0;
			var isMatch = 0;
			if ((myFileName.lastIndexOf(".")) != -1)
			{
				for (arrayLen = 0; arrayLen < myExt.length; arrayLen++)
				{
					var startChar 	= myFileName.lastIndexOf(".");
					fileExt			= myFileName.substring(startChar+1,myFileName.length);
					if (fileExt == myExt[arrayLen])
					{
						//match found	
						isMatch = 1;
						break;
					}
				}
			}
			else if(el.value != "")
			{
				highlight(el, inputclasserror);
				err = myRule.alertMsg;
			}
		}
		if (!isMatch && el.value != "")
		{
			highlight(el, inputclasserror);
            err = myRule.alertMsg;
		}
    }
	else 
	{
        debug('DEBUG: rule ' + myRule.ruleName + ' not supported for ' + el.type);
    }
	return err;
}

// Internal function, it is called if the rule is 
// applied on a multiselect select box
function checkSelMul(el, myRule) 
{
    if (myRule.ruleName=='required') 
	{
        var found = false;
        opts = el.options;
        for(var i=0; i<opts.length; i++) 
		{
            if(opts[i].selected && opts[i].value) 
			{
                found = true;
                break;
            }
        }
        if ( !found ) 
		{
            highlight(el, inputclasserror);
            return myRule.alertMsg;
        }
    } 
	else if (myRule.ruleName=='equal') 
	{
        var found = false;
        opts = el.options;
        for(var i=0; i<opts.length; i++) 
		{
            if(opts[i].selected && opts[i].value==myRule.comparisonValue) 
			{
                found = true;
                break;
            }
        }
        if ( !found ) 
		{
            highlight(el, inputclasserror);
            return myRule.alertMsg;
        }
    } 
	else if (myRule.ruleName=='notequal') 
	{
        var found = false;
        opts = el.options;
        for(var i=0; i<opts.length; i++) 
		{
            if(opts[i].selected && opts[i].value!=myRule.comparisonValue) 
			{
                found = true;
                break;
            }
        }
        if ( !found ) 
		{
            highlight(el, inputclasserror);
            return myRule.alertMsg;
        }
    } 
	else 
	{
        debug('DEBUG: rule ' + myRule.ruleName + ' not supported for ' + el.type);
    }
}

// Function used to display an error message to developer
// if the debug mode is on.
// configure it in safv.config.js
function debug(msg) 
{
   if (debugmode) 
   {
        alert(msg);
   }
}

// Internal function used to trim spaces before using the value
// You can switch auto trimming on/off in safv.config.js file.
function strTrim(str) 
{
    return str.replace(/^\s+/,'').replace(/\s+$/,'');
}

// Internal function used to parse the rules array
// defined by the user.
function makeRules(strRules) 
{
    var rules=new Array();
    if (strRules.length) 
	{
        for(var i=0; i<strRules.length; i++) 
		{
            rules[i] = splitRule(strRules[i]);
        }
    } 
	else 
	{
        rules[0] = splitRule(strRules);
    }
    return rules;
}

// Internal function used to split the array rule
// into parameters
function splitRule(strRule) 
{
    var retval = null;
    if (strRule!=undef) 
	{
        params = strRule.split('|');
        switch (params.length) 
		{
            case 2:
                retval = new rule(params[0], params[1], null, null, null);
                break;
            case 3:
                if (threeParamRule(params[1])) 
				{
                    retval = new rule(params[0], params[1], params[2], null, null);
                }
				else if (params[2]=='pre-condition' || params[2]=='post-condition') 
				{
                    retval = new rule(params[0], params[1], null, 'foo', params[2]);
                }
				else 
				{
                    retval = new rule(params[0], params[1], null, params[2], null);
                }
                break;
            case 4:
                if (threeParamRule(params[1]) && (params[3]=='pre-condition' || params[3]=='post-condition')) 
				{
                    retval = new rule(params[0], params[1], params[2], 'foo', params[3]);
                } 
				else 
				{
                    retval = new rule(params[0], params[1], params[2], params[3], null);
                }
                break;
            default:
                debug('DEBUG: wrong definition of rule');
        }
    }
    return retval;
}

// Function declaring the rule which must need three 
// parameters to run.
function threeParamRule(ruleName) 
{
    return (ruleName=='equal' || ruleName=='notequal' || ruleName=='above' || ruleName=='below' || ruleName=='minlength' || ruleName=='maxlength' || ruleName=='date_gt' || ruleName=='date_ge' || ruleName=='date_lt' || ruleName=='date_le' || ruleName=='implies' || ruleName=='fileext' || ruleName=='regexp' || ruleName=='numrange' || ruleName=='keypress' || ruleName=='and' || ruleName=='or')
        ? true
        : false;
}

// Internal function, used to highlight the field containing error.
// You can change its display using a CSS.
// See safv.config.js for more help.
function highlight(el, clazz) 
{
    if (el!=undef && inputhighlight) 
	{
        el.className = clazz;
    }
}

// Internal function, defining the error messages to be displayed
// If the error messge is passed from with in the rule array then it will 
// be used otherwise a default messge defined in safv.config.js is used.
function getDefaultMessage(el, nameDisplayed, ruleName, comparisonValue) 
{
    if (nameDisplayed.length == 0) 
	{
        nameDisplayed = el;
    }
    var msg = DEFAULT_MSG;
    if (ruleName=='required') 
	{
        msg = REQUIRED_MSG.replace('{1}', nameDisplayed);
    } 
	else if (ruleName=='above') 
	{
        msg = ABOVE_MSG.replace('{1}', nameDisplayed).replace('{2}', comparisonValue);
    }
	else if (ruleName=='below') 
	{
        msg = BELOW_MSG.replace('{1}', nameDisplayed).replace('{2}', comparisonValue);
    }
	else if (ruleName=='minlength') 
	{
        msg = MINLENGTH_MSG.replace('{1}', nameDisplayed).replace('{2}', comparisonValue);
    } 
	else if (ruleName=='maxlength') 
	{
        msg = MAXLENGTH_MSG.replace('{1}', nameDisplayed).replace('{2}', comparisonValue);
    } 
	else if (ruleName=='numrange') 
	{
        msg = NUMRANGE_MSG.replace('{1}', nameDisplayed).replace('{2}', comparisonValue);
    } 
	else if (ruleName=='date') 
	{
        msg = DATE_MSG.replace('{1}', nameDisplayed);
    } 
	else if (ruleName=='numeric') 
	{
        msg = NUMERIC_MSG.replace('{1}', nameDisplayed);
    } 
	else if (ruleName=='integer') 
	{
        msg = INTEGER_MSG.replace('{1}', nameDisplayed);
    }
	else if (ruleName=='double') 
	{
        msg = DOUBLE_MSG.replace('{1}', nameDisplayed);
    }
	else if (ruleName=='equal') 
	{
        msg = EQUAL_MSG.replace('{1}', nameDisplayed).replace('{2}', getComparisonDisplayed(comparisonValue));
    }
	else if (ruleName=='notequal') 
	{
        msg = NOTEQUAL_MSG.replace('{1}', nameDisplayed).replace('{2}', getComparisonDisplayed(comparisonValue));
    }
	else if (ruleName=='alphabetic') 
	{
        msg = ALPHABETIC_MSG.replace('{1}', nameDisplayed);
    }
	else if (ruleName=='alphabeticspace') 
	{
        msg = ALPHABETIC_SPC_MSG.replace('{1}', nameDisplayed);
    }
	else if (ruleName=='alphanumeric') 
	{
        msg = ALPHANUMERIC_MSG.replace('{1}', nameDisplayed);
    } 
	else if (ruleName=='alnumhyphen') 
	{
        msg = ALNUMHYPHEN_MSG.replace('{1}', nameDisplayed);
    }
	else if (ruleName=='alnumhyphenat') 
	{
        msg = ALNUMHYPHENAT_MSG.replace('{1}', nameDisplayed);
    }
	else if (ruleName=='alphaspace') 
	{
        msg = ALPHASPACE_MSG.replace('{1}', nameDisplayed);
    }
	else if (ruleName=='email') 
	{
        msg = EMAIL_MSG.replace('{1}', nameDisplayed);
    }
	else if (ruleName=='phone') 
	{
        msg = PHONE_MSG.replace('{1}', nameDisplayed);
    }
	else if (ruleName=='url') 
	{
        msg = URL_MSG.replace('{1}', nameDisplayed);
    }
	else if (ruleName=='fileext') 
	{
        msg = FILEEXT_MSG.replace('{1}', comparisonValue);
    }
	else if (ruleName=='regexp') 
	{
        msg = REGEXP_MSG.replace('{1}', nameDisplayed).replace('{2}', comparisonValue);
    }
	else if (ruleName=='date_gt') 
	{
        msg = DATE_GT_MSG.replace('{1}', nameDisplayed).replace('{2}', getComparisonDisplayed(comparisonValue));
    }
	else if (ruleName=='date_ge') 
	{
        msg = DATE_GE_MSG.replace('{1}', nameDisplayed).replace('{2}', getComparisonDisplayed(comparisonValue));
    }
	else if (ruleName=='date_lt') 
	{
        msg = DATE_LT_MSG.replace('{1}', nameDisplayed).replace('{2}', getComparisonDisplayed(comparisonValue));
    }
	else if (ruleName=='date_le') 
	{
        msg = DATE_LE_MSG.replace('{1}', nameDisplayed).replace('{2}', getComparisonDisplayed(comparisonValue));
    }
	else if (ruleName=='empty') 
	{
        msg = EMPTY_MSG.replace('{1}', nameDisplayed);
    }
    return msg;
}

// Internal function used to fetch the value of the parameter
// called in the rules array.
function getComparisonDisplayed(comparisonValue) 
{
    comparisonDisplayed = comparisonValue;
    if (comparisonValue.substring(0, 1)=='$') 
	{
        comparisonValue = comparisonValue.substring(1, comparisonValue.length);
        tmp = comparisonValue.split(':');
        if (tmp.length == 2) 
		{
            comparisonDisplayed = tmp[1];
        }
		else 
		{
            comparisonDisplayed = comparisonValue;
        }
    }
    return comparisonDisplayed;
}

// Internal function, used to detect he web browser.
function getBrowser() 
{
    brs=navigator.userAgent.toLowerCase();
    var retval;
    if (brs.search(/msie\s(\d+(\.?\d)*)/)!=-1) 
	{
        retval='msie';
    } 
	else if (brs.search(/netscape[\/\s](\d+([\.-]\d)*)/)!=-1) 
	{
        retval='netscape';
    }
	else if (brs.search(/firefox[\/\s](\d+([\.-]\d)*)/)!=-1) 
	{
        retval='firefox';
    }
	else
	{
        retval='unknown';
    }
    return retval;
}

// Internal function, called from checkKeyPress
function isKeyAllowed(keyCode, charsAllowed) 
{
    retval = false;
    var aCharCode;
    if (keyCode==8) 
	{
        retval = true;
    }
	else 
	{
        for(var i=0; i<charsAllowed.length; i++) 
		{
            aCharCode = charsAllowed.charCodeAt(i);
            if (aCharCode==keyCode) 
			{
                retval = true;
                break;
            }
        }
    }
    return retval;
}

function getField(formObj, fieldName)
{
	var retval = null;
	if (formObj.elements[fieldName])
	{
		retval = formObj.elements[fieldName];
	}
	else if (document.getElementById(fieldName))
	{
		retval = document.getElementById(fieldName);
	}
	return retval;
}

function unformatNumber(viewValue)
{
    var retval = viewValue.replace(THOUSAND_SEP, ""); 
    retval = retval.replace(DECIMAL_SEP, ".");
    return retval;
}

