/*
* Form validation
*
* Possible checks:  "required" - has error string
*                   "email" - has error string
*                   "minLength" - has array [length, error string]
*                   "matchVal" - has array [form element to match, error string]
*                   "cannotBe" - has array [what value cannot be, error string] - nb use this to make a select required
*                   "hasText" - A bit like required but will allow a default value to be submitted - fails on whitespace or numbers only
*
*                   errorTarget example - "#errorsHere" - will append error message label to that element
*/
(function($) {
    $.ti.validate = {
        
        // Check required fields, cannot be empty, cannot be default value
        required: function(formElement, rule) {
            var value = $('#' + formElement).val();
            if(value === '' || value === document.getElementById(formElement).defaultValue) {                
                this.insertMessage(formElement, rule);    
            }
        },
        
        // Check is valid email address
        email: function(formElement, rule) {
            var value = $('#' + formElement).val();            
            if(!value.match(/^[a-zA-Z0-9_\-\.]+\@(([\[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/)) {
                this.insertMessage(formElement, rule);                
            }
        },
        
        // Check is valid date
        date: function(formElement, rule) {
            var value = $('#' + formElement).val();            
            if(!value.match(/^(19|20)\d\d([- /.])(0[1-9]|1[012])\2(0[1-9]|[12][0-9]|3[01])$/)) {
                this.insertMessage(formElement, rule);
            }
        },
        
        // Check length of input value
        minLength: function(formElement, rule) {
            if($('#' + formElement).val().length < rule[0]) {
                this.insertMessage(formElement, rule[1]);               
            }  
        },
        
        // Check length of input value
        maxLength: function(formElement, rule) {
            if($('#' + formElement).val().length > rule[0]) {
                this.insertMessage(formElement, rule[1]);               
            }  
        },
        
        // Check that the value matches that of another for element i.e. compare two email or password fields
        matchVal: function(formElement, rule) {
            if($('#' + formElement).val() !== $(rule[0]).val()) {
                this.insertMessage(formElement, rule[1]);
            }
        },
        
        // Ensure that a particular exact value is not matched
        cannotBe: function(formElement, rule) {            
            if($('#' + formElement).val() === rule[0]) {
                this.insertMessage(formElement, rule[1]);                
            }
        },
        
        // Compare a particular value is not less than e.g. comparing figure or date
        notLess: function(formElement, rule) {            
            if($('#' + formElement).val() < rule[0]) {
                this.insertMessage(formElement, rule[1]);
            }
        },
        
        // Ensure that something has been entered - fails on white space or numbers only
        hasText: function(formElement, rule) {
            var value = $('#' + formElement).val();            
            if(!value.match(/[^\d\s]/)) {
                this.insertMessage(formElement, rule);                
            }  
        },
        
        // Append error message
        insertMessage: function(formElement, message) {
            var errorLabel = $('<label for="' + formElement +'" class="error">' + message + '</label>').hide();
            
            // Set form as not valid
            this.checks.valid = false;
            
            // Set has already thrown an error for this form element
            this.options.rules[formElement].hasError = true;
                
            if(!this.options.errorTarget){
                $('#' + formElement).before(errorLabel);   
            } else {
                if(this.checks.shown === 0) {
                    $(this.options.errorTarget).append(errorLabel);
                    if(!this.options.showAll) {
                        this.checks.shown = 1;    
                    }                    
                }
            }  
            errorLabel.fadeIn(500);
        },
        
        options: {
            errorTarget: false, // If false inserted before input
            showAll: true,  // If set to false only the first error message encountered will display
            success: false,
            failure: false
        },
        
        checks: {
            valid: true,
            shown: 0
        },
        
        check: function(form, settings) {
            var formElement, rule;
            
            // Reset checks
            this.checks.valid = true;
            this.checks.shown = 0;
            
            // update options with settings
            $.extend(this.options, settings);
            // Clear any existing errors
            $('label.error', form).remove();
            
            // Get each form element that has a rule
            for(formElement in this.options.rules){
                if(this.options.rules.hasOwnProperty(formElement)) {
                     // Get each rule for the form element
                    for(rule in this.options.rules[formElement]) {
                        if(this.options.rules[formElement].hasOwnProperty(rule)) {                            
                            // Check that a rule has not already been broken before checking that element again
                            if(!this.options.rules[formElement].hasError) {
                                // Run the required check on that element.
                                $.ti.validate[rule](formElement, this.options.rules[formElement][rule]);
                            }
                        }
                    }
                }
            }
         
            // If no errors get thrown run success callback   
            if(this.checks.valid) {            
              this.options.success($(form));   
            } else {
                // or failure callback if one exists
                if(this.options.failure) {
                    this.options.failure($(form));   
                }
            } 
        }
    };
})(jQuery);