/** Format text message for output
* @param string sKey - key of message
* @param string aParam - params to substitute
* @return  string formatted message.
*/
function validator_formatMes(sKey, aParam){
    var aMes = [];
    aMes['minlen']  = 'Length of `%s0` field should be more than or equal to %s1 characters.';
    aMes['maxlen']  = 'Length of `%s0` field should be less than or equal to %s1 characters.';
    aMes['max']     = '`%s0`: field value should be less than or equal to %s1.';
    aMes['min']     = '`%s0`: field value should be more than or equal to %s1.';
    aMes['mineq']   = '`%s0`: field value should be more than %s1.';
    aMes['maxeq']   = '`%s0`: field value should be less than %s1.';
    aMes['pattern'] = 'Please provide a correct `%s0`.';
    var sStr = aMes[sKey];
    for(m=0; m<aParam.length; ++m)
        sStr = sStr.replace('%s'+m, aParam[m]);
    return sStr;
}

/** Gets field value, depending on field type
* @param object oField field
* @return string value of field
* @todo add support for dates
*/
function validator_getValue(oField){
        var sVal = oField.value;
        if (oField.type.toLowerCase() == 'checkbox' && !oField.checked )
                sVal = '';
        return sVal;
}
/** Checks is form valid
* @param object oForm  - form to validate
* @param array aShema  - array of validation shemas (hash) related to certan field
* @param array aRules  - array of validation rules bentween 2 fields
* @param string sDiv  - name of html DIV element for errors output
* @return  boolean  true if all is ok or false + alert wiht error messages if form contains errors.
*/
function validator_isValid(oForm, aShema, aRules, sDiv) {
        // errors
    var aErr  = [];
        var oFld  = null; // first field with error

        // for each fields
        for( i=0; i< aShema.length; ++i ){
                var oShema = aShema[i];
                var sVal = validator_getValue(oForm.elements[oShema.field]);

                //optional param
                if( typeof(oShema.optional) != 'undefined' && !sVal.length)
                        continue;
        sMes = ( typeof(oShema.message) != 'undefined' ? oShema.message : '');

        var aTmpErr = [];
                // validation
                if (typeof(oShema.minlen) != 'undefined' &&  oShema.minlen > sVal.length)
            aTmpErr[aTmpErr.length] = validator_formatMes('minlen', [oShema.title, oShema.minlen]);

                if (typeof(oShema.maxlen) != 'undefined' &&  oShema.maxlen < sVal.length)
            aTmpErr[aTmpErr.length] = validator_formatMes('maxlen', [oShema.title, oShema.maxlen]);

                if (typeof(oShema.pattern) != 'undefined' && sVal.search(oShema.pattern) == -1 )
            aTmpErr[aTmpErr.length] = validator_formatMes('pattern', [oShema.title]);

                if (typeof(oShema.min) != 'undefined' &&  oShema.min > sVal)
            aTmpErr[aTmpErr.length] = validator_formatMes('min', [oShema.title, oShema.min]);

                if (typeof(oShema.max) != 'undefined' &&  oShema.max < sVal)
            aTmpErr[aTmpErr.length] = validator_formatMes('max', [oShema.title, oShema.max]);

        if (typeof(oShema.mineq) != 'undefined' &&  oShema.mineq >= sVal)
            aTmpErr[aTmpErr.length] = validator_formatMes('mineq', [oShema.title, oShema.mineq]);

        if (typeof(oShema.maxeq) != 'undefined' &&  oShema.maxeq < sVal)
            aTmpErr[aTmpErr.length] = validator_formatMes('maxeq', [oShema.title, oShema.maxeq]);

        // store error messages for field
        if (sMes && aTmpErr.length) // if given custom error message store only it
            aErr[aErr.length] = sMes;
        else // store all errors
            aErr = aErr.concat(aTmpErr);

        // if first error, try to set focus
        if (aErr.length && oFld == null)
                        oFld = oForm.elements[oShema.field];

    }// end loop by single elements

        // for each rules
        if ( 'undefined' != typeof(aRules) ){
                for( i=0; i < aRules.length; ++i ) { // for each rules  0 - first op, 1 - second op, 2 - operation, 3 - Error message text
                        var v1 = oForm.elements[aRules[i][0]].value;
                        var v2 = oForm.elements[aRules[i][1]].value;
                        switch( aRules[i][2] ){
                                case '==' :
                                        if ( v1 != v2 )
                                                aErr[aErr.length] = aRules[i][3];
                                break;
                                case '<=' :
                                        if ( parseFloat(v1) > parseFloat(v2) )
                                                aErr[aErr.length] = aRules[i][3];
                                break;
                                case '>=' :
                                        if ( parseFloat(v1) < parseFloat(v2) )
                                                aErr[aErr.length] = aRules[i][3];
                                break;
                                case '!=' :
                                        if ( v1 == v2 )
                                                aErr[aErr.length] = aRules[i][3];
                                case 'req' :
                                        if ( v1 && !v2 )
                                                aErr[aErr.length] = aRules[i][3];
                                break;
                        }

                        if (aErr.length && oFld == null) // if first error
                            oFld = oForm.elements[aRules[i][0]];
        }// end loop by rules
    }//end rules

    // make output
    if ( aErr.length ){
        var sOut = '';
        var oDiv = document.getElementById(sDiv);
        if (oDiv){
                for(i=0; i<aErr.length; ++i)
                    sOut += '<b style="color:red">'+aErr[i]+'</b><br>';
            oDiv.innerHTML = sOut;
            } else
                alert(aErr.join("\n"));
       
        if (oFld) oFld.focus();
        return false;
        }
        return true;
}