/* --------------------------------------------------------------------------------------------- */
/* Form Validation Library
/* Copyrite 2007 3Legs Ltd.
/* You do not have permission to reuse, alter, share, or copy this code without permission
/* --------------------------------------------------------------------------------------------- */

String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ''); }

/* --------------------------------------------------------------------------------------------- */

function tl_validate (def_name, form_id, form_label) {
    var rules = tl_validation_defs()[def_name];
    var form = document.getElementById(form_id);


    //console.log(rules);
    //console.log(form);

    var errors = tl_process_validation(form, rules);

    if (errors.length) {
        alert( tl_error_string(form_label, errors) );
        return(false);
    }
    else {
        return(true);
    }   
    

}

/* --------------------------------------------------------------------------------------------- */

function tl_error_string(form_label, errors) {
    var message = 'The following errors occured for the ' + form_label + ' form:\n\n';
    
    var bullet = "\u25C9";    

    for (var i = 0; i < errors.length; i++) {

        message = message + ' ' + bullet + ' ' + errors[i] + '\n\n';
    }

    return(message);

}

/* --------------------------------------------------------------------------------------------- */

function tl_process_validation (form, rules) {
    var form_elements = tl_get_form_elements(form);
    var errors = [];

    //console.log(form_elements);

    
    for (var i = 0; i < form_elements.length; i++) {
        var rule = rules[form_elements[i].name];
        if (rule) { //if there is a validation rule then apply it
            var value = form_elements[i].value;
            if (form_elements[i].type == 'checkbox') {
                if (form_elements[i].checked) {
                    value = 'checked';
                }
                else {  
                    value = '';
                }
            }


            var error = tl_apply_rule(value, rule);
            if (error) {
                errors.push(error);
            }
        }
    }

    return(errors);

}

/* --------------------------------------------------------------------------------------------- */

function tl_get_form_elements (form) {
    var elements = [];
    var element_types = ['SELECT', 'INPUT', 'TEXTAREA', 'CHECK'];    //works
        
    for (var i=0; i <= element_types.length; i++) {
        var these_elements = form.getElementsByTagName(element_types[i]);
        for (var j = these_elements.length - 1; j > -1; j-- ) {
            //alert ("Pushing: " + these_elements[j]);
            elements.push( these_elements[j] );
        }
    }
        
    return(elements);
        
}

/* --------------------------------------------------------------------------------------------- */

function tl_apply_rule (data, rule) {
    //rule def is an array that can look like this:
    //['Name', true, 're(.*)', false, 'must be bla bla']
    //Nice name of field, required, pattern, negate, error message

    //pattern can be any of the following:
    //re()                  regular expression
    //range(int, int)       range of integer values
    //enum(list)            enumeration of strings
    //email()               email address
    //date(format)          date of certain format (d m and y are understood)

    var name     = rule[0];     //name of the field in the form
    var required = rule[1];     //is the field required (any value)
    var pattern  = rule[2];     //pattern to match, can be one of the functions above
    var negate   = rule[3];     //negate the pattern match
    var message  = rule[4];     //message to display when failed.  (tags to end)
    var message_replace = rule[5];  //use the message above as the complete error message

    //console.log('Apply Rule: ' + rule);

    //trim the input, if it is a string
    if (data.trim) {
        data = data.trim();
    }

    var error_string;

    if (required || data) { 
        var match;
        var validated;  //true if the validation was sucessful

        if (pattern) {
            //find and apply the individual rule
            if (match = tl_match_re(pattern, 're\\\((.+)\\\)')) {
                validated = tl_rule_re(data, match[1]);
            }
            if (match = tl_match_re(pattern, 'range\\\((.+)\\\)')) {
                validated = tl_rule_range(data, match[1]);
            }
            if (match = tl_match_re(pattern, 'enum\\\((.+)\\\)')) {
                validated = tl_rule_enum(data, match[1]);
            }
            if (match = tl_match_re(pattern, 'email\\\((.*)\\\)')) {
                validated = tl_rule_email(data, match[1]);
            }
            if (match = tl_match_re(pattern, 'date\\\((.+)\\\)')) {
                //console.log('Date type validation: ' + match[1]);
            }
        }
        else {
            //there is no pattern to match
            if (data) {
                validated = true;
            }
        }    

        //console.log( {'data' : data, 'required' : required, 'validated' : validated} );

        if (negate) {
            validated = ! validated;
        }

        if ( ! validated ) {
            error_string = tl_make_error_string(name, required, pattern, negate, message, message_replace);
        }

    }

    return(error_string);

}

/* --------------------------------------------------------------------------------------------- */

function tl_make_error_string (name, required, pattern, negate, message, message_replace) {

    if (message_replace) {
        return(message);
    }


    var error_pattern = 'match pattern ' + pattern;
    if (message) {
        error_pattern = message;
    }
    var required_string = ' is required';
    if ( ! required) {
        required_string = '';
    }
    var negate_string = 'NOT ';
    if ( ! negate) {
        negate_string = '';
    }

    var error_string = name + required_string;
    if (pattern) {
        if (required) {
            error_string = error_string  + ' and must ' + negate_string + error_pattern;
        }
        else {
            error_string = error_string  + ' must ' + negate_string + error_pattern;
        }
        
    }
    if ( ! required) {
        error_string = error_string + ' if value is set';
    }

    return(error_string);

}        

/* --------------------------------------------------------------------------------------------- */

function tl_rule_re (data, args) {
    
    var matches  = tl_match_re(data, args);

    //console.log(matches);

    if (matches) {
        return(true);
    }
    else {
        return(false);
    }
    
}

/* --------------------------------------------------------------------------------------------- */

function tl_rule_range (data, args) {
    //see if a value is between range
    //if either value is null then bound is infinite

    var split_args = args.split(',');
    var lower = split_args[0];
    var upper = split_args[1];

    var fail_validation;

    if ( ! tl_match_re(data, '^\\\d+$') ) {
        return(false);
    }
    else {
        data = Number(data);
    }

    if (lower) {
        if ( data < lower) {
            fail_validation = 1;
        }
    }
    
    if (upper) {
        if ( data > upper ) {
            fail_validation = 1;
        }
    }

    if (fail_validation) {
        return(false);
    }
    else {
        return(true);
    }

}

/* --------------------------------------------------------------------------------------------- */

function tl_rule_enum (data, args) {
    var valid_values = args.split(',');

    var matched = false;

    for (var i = 0; i < valid_values.length; i++) {
        var valid = valid_values[i];
        valid = valid.trim();
        
        //console.log(data + ' : ' + valid);

        if (data == valid) {
            matched = true;
            i = 999999999;  //exit now
        }
    }

    if (matched) {
        return(true);
    }
    else {
        return(false);
    }

}

/* --------------------------------------------------------------------------------------------- */

function tl_rule_email (data, args) {
    
    var email_re = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
    if (email_re.test(data)) {
        return(true);
    }
    else {
        return(false);
    }

}

/* --------------------------------------------------------------------------------------------- */

function tl_match_re (data, re, re_options) {
    var reg = new RegExp(re, re_options);

    //console.log('Match: ' + data + ' to ' + re);
    
    var found = reg.exec(data);

    return(found);

}

/* --------------------------------------------------------------------------------------------- */


