/***** Validator class *****/
var Validator = new Object();

/* regular expressions */
Validator.RE = new Object();
Validator.RE.email = /^[_\.0-9A-Za-z-]+@([0-9A-Za-z][0-9A-Za-z-]+\.)+[A-Za-z]{2,6}$/;

/* checkString : boolean */
Validator.checkString = function( str, min_len, max_len, chktype )
{
    if( typeof chktype != "string" ) { chktype = ""; }
    if( typeof str != "string" )
    { alert( "Validator.checkString error: non-string provided" ); return false; }
    // trim the string!
    str = str.trim();
    if( min_len == 0 && str.length == 0 ) { return true; }
    if( str.length < min_len ) { return false; }
    if( str.length > max_len ) { return false; }
    switch( chktype )
    {
        case 'email':
            return Validator.RE.email.test(str);
            break;
        
        case 'no-bad-chars': // like these ones ~`!@#$%^&*()[]{}|\:;"'<,>.?/
            var badCharCodes = [126,96,33,64,35,36,37,94,38,42,40,41,91,93,123,125,124,92,58,59,34,39,60,44,62,46,63,47];
            for( var i=0; i<str.length; i++ )
            {
                for( var j=0; j<badCharCodes.length; j++ )
                { if( str.charCodeAt(i) == badCharCodes[j] ) return false; }
            }
            break;
        
        case 'safe-ascii': // ascii chars except non-printing ones
            for( var i=0; i<str.length; i++ )
            { if( str.charCodeAt(i)>125 || str.charCodeAt(i)<32 ) return false; }
            break;
        
        case 'non-english':
            for( var i=0; i<str.length; i++ )
            { if( str.charCodeAt(i)<128 ) return false; }
            break;
            
        case 'tw-pid': // Personal ID (Taiwan)
            var c, n, i;
            var t = "ABCDEFGHJKLMNPQRSTUVXYWZIO";
            var s = str;
            c = s.substring(0,1);
            c = t.indexOf(c.toUpperCase());
            if ((s.length!= 10) || (c<0)) return false;
            n = parseInt(c/10)+ c%10*9+ 1;
            for (var i=1; i<9; i++) n = n + parseInt(s.substring(i,i+1))* (9-i);
            n = (10- (n% 10))% 10;
            if (n != parseInt(s.substring(9,10))) return false;
            break;
        
        default: // only check length, which is done above
            break;
    }   // end switch
    return true;
}   // end Validator.checkString()

/* checkNumber : boolean */
Validator.checkNumber = function( num, min, max, chktype )
{
    if( isNaN(num) ) { return false; }
    switch( chktype )
    {
        case 'float':
            return ( num >= min && num <= max ); 
            break;
            
        case 'int':
        default:
            if( !(/^[0-9]+$/.test(num) ) ) { return false; }
            else { return ( num >= min && num <= max ); }
            break;
    }
    return true;
}


/***** Form Validation *****/
/*
grabs values from the "required" hidden field
*/
Validator.genericFormChecker = function( formObj )
{
    // no "required" field specified
    if( !formObj.required ) return true;
    var warnings = "";
    // sample "required" field value="username,帳號,3,24|gender,密碼|city|email,E-mail,10,128,email"
    var req_fields_arr = formObj.required.value.split("|");
    for( var i=0; i<req_fields_arr.length; i++ )
    {
        var field_params_arr = req_fields_arr[i].split(",");
        var field_name = field_params_arr[0];
        var field_label = (field_params_arr[1]) ? field_params_arr[1] : field_name;
        if( !formObj.elements[field_name] )
        { alert("Validator.genericFormChecker Error:\nNot a form element: "+field_name); }
        var ele = formObj.elements[field_name];
        // alert( field_name + " is of type: " + ele.type +", with "+ele.length+" sub elements." );
        // do things according to field type
        switch( ele.type )
        {
            case 'text':
            case 'textarea':
                var min_len = (field_params_arr[2]) ? field_params_arr[2] : 0;
                // max length is optional and will be derviced from "required" param, maxlength attribute or hard coded (216)
                var max_len = (field_params_arr[3]) ? field_params_arr[3] : (ele.maxLength) ? ele.maxLength : 216;
                var chktype = (field_params_arr[4]) ? field_params_arr[4] : ""; // eg. "email"
                if( chktype == "int" || chktype == "float" )
                {
                    if( !Validator.checkNumber( ele.value, min_len, max_len, chktype ) )
                    { warnings += "\n- " + field_label; }
                }
                else if( !Validator.checkString( ele.value, min_len, max_len, chktype ) )
                { warnings += "\n- " + field_label; }
                break;
            
            case 'select-one':
                // just check if selected value is empty or not
                // due to IE's inability to automatically fill-in "text" as the value when
                // none has been specified
                if( ele.options[ele.selectedIndex].value == "" && ele.selectedIndex == 0 )
                { warnings += "\n- " + field_label; }
                break;
            
            case 'select-multiple':
                // not sure what to check for just yet
                break;
            
            case 'checkbox':
                // if specified, must be checked
                if( !ele.checked )
                { warnings += "\n- " + field_label }
                break;
            
            case 'file':
                if( ele.value == "" )
                { warnings += "\n- " + field_label; }
                break;
            
            case 'password': // only check for length
                var min_len = (field_params_arr[2]) ? field_params_arr[2] : 0;
                // max length is optional and will be derviced from "required" param, maxlength attribute or hard coded (216)
                var max_len = (field_params_arr[3]) ? field_params_arr[3] : (ele.maxLength) ? ele.maxLength : 216;
                var chktype = (field_params_arr[4]) ? field_params_arr[4] : ""; // eg. "email"
                if( !Validator.checkString( ele.value, min_len, max_len, chktype ) )
                { warnings += "\n- " + field_label; }
                break;
            
            default: // most likely radio group
                // determine whether this is a group of radio buttons
                if( typeof ele.length != "undefined" && ele[0].type == "radio" )
                {   // there's more than one
                    var radio_checked = 0;
                    for( var j=0; j<ele.length; j++ )
                    { if( ele[j].checked ) { radio_checked++; } }
                    if( radio_checked < 1 )
                    { warnings += "\n- " + field_label; }
                }
        }   // end switch
    
    }   // end for
    if( warnings.length > 1 )
    {
        alert( "請填寫下列欄位:\n" + warnings );
        return false;
    }
    return confirm( "確定要送出？" );
    
}
