/**
 * 
 * Simple HTML5 form validator
 * 
 * @author Elze Kool <e.kool@visualmedia.nl>
 * @copyright 2013 Visual Media
 * 
 **/

(function($) {    
    
    $.fn.html5validator = function(options) {

        // Extend the default options
        options = $.extend(true, {}, $.fn.html5validator.options, options);
    
        /**
         * Validate required field
         * 
         * @param {DOMElement} field   Field to validate
         * 
         * @return {Boolean} Field valid
         */
        var validateRequired = function(field) {
            var valid;
            
            if (field.is('[disabled]') || field.is('[readonly]')) {
                valid = true;
            } else if (field.is('[type="checkbox"], [type="radio"]')) {
                if (field.attr('name') !== undefined) {
                    var form = field.parents('form').first();
                    valid = form.find('input[name="' + field.attr('name') + '"]:checked').length > 0;
                } else {
                    valid = field.is(':checked');
                }
            } else {
                var val = field.val();
                if (val === null) val = '';
                valid = /^.+$/m.test(val);
            }
            return valid;
        };
        
        /**
         * Validate group selection
         * 
         * @param {DOMElement} field Field to validate
         * 
         * @return {Boolean} Field valid
         */
        var validateRequiredGroup = function(field) {
            var valid;
            valid = (field.find(':selected').length > 0);
            return valid;
        };
        
        /**
         * Validate pattern for field
         * 
         * @param {DOMElement} field   Field to validate
         * @param {String}     pattern Pattern to validate
         * 
         * @return {Boolean} Field valid
         */
        var validatePattern = function(field, pattern) {
            var valid;            
            var regex;
            regex = new RegExp(pattern);            
            valid = regex.test(field.val());
            return valid;
        };
    
        /**
         * Validator field
         * 
         * @param {DOMElement} field    Field to validate
         * @param {Boolean}    onsubmit Triggered by submit
         * 
         * @return {Boolean} Field valid
         */
        var validateField = function(field, onsubmit) {
            
            var result = true;  
            var message;
            var is_required = false;
            
            if (field.is(options.requiredSelector)) {
                result = validateRequired(field);                
                if (!result) {
                    if (field.attr('data-required-message') != null) {
                        message = field.attr('data-required-message');
                    } else {
                        message = options.requiredMessage;
                    }
                }
                is_required = true;
                
            } else if (field.is(options.requiredGroupSelector)) {
                result = validateRequired(field);                
                if (!result) {
                    if (field.attr('data-required-message') != null) {
                        message = field.attr('data-required-message');
                    } else {
                        message = options.requiredMessage;
                    }
                }
                is_required = true;
            }
            
            var val = field.val();
            if ((is_required === true) || ((val !== '') && (val !== null))) {
            
                if (field.is(options.patternSelector)) {
                    result = validatePattern(field, field.attr('pattern'));                
                    if (!result) {
                        if (field.attr('data-invalid-message') != null) {
                            message = field.attr('data-invalid-message');
                        } else {
                            message = options.patternMessage;
                        }
                    }
                }

                $.each(options.types, function(type) {
                    if (field.is('[type="' + type + '"]')) {      
                        result = validatePattern(field, this.pattern);                
                        if (!result) {
                            if (field.attr('data-invalid-message') != null) {
                                message = field.attr('data-invalid-message');
                            } else {
                                message = this.message;
                            }
                        }
                        return false;
                    }
                });

            }
            
            if (result === true) {
                result = options.validField(field, onsubmit);
            } else {
                result = options.inValidField(field, message, onsubmit);
            }
            
            return result;
            
        };
        
        return this.each(function() {
            var form = $(this);
            
            var selector = options.requiredSelector + ',' + options.requiredGroupSelector + ',' + options.patternSelector;
            $.each(options.types, function(key) {
                selector += ',[type="' + key + '"]';
            });
            
            form.find(selector).on('change', function() {
                var field = $(this);
                validateField(field, false);
            });
            
            form.on('submit', function() {      
                options.beforeValidate();
                var invalid = [];               
                form.find(selector).each(function() {
                    var field = $(this);
                    if (!validateField(field, true)) {
                        invalid.push(field);
                    }
                });                
                var submit = options.beforeSubmit(invalid);                
                return submit;                
            });
            
        });    
        
        
    
    };
    
    //Set the default validation options
    $.fn.html5validator.options = {
        
        
        validField : function(field, onsubmit) { return true; },
        inValidField : function(field, message, onsubmit) { return false; },
        beforeValidate : function() { return; },
        beforeSubmit : function(invalid) { return (invalid.length === 0); },
        
        requiredSelector : '[required]',
        requiredMessage : 'This field is required',
        
        requiredGroupSelector : '[data-required]',
        requiredGroupMessage : 'Make a selection',
        
        patternSelector : '[pattern]',
        patternMessage : 'Invalid format',
        
        types: {
            number: {
                pattern: "^[+-]?\\d+(\.\\d+)?$",
                message: "Please enter correct number."
            },
            email: {
                pattern: "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$",
                message: "Please enter valid email."
            },
            url: {
                pattern: "^([a-z]{1,5}:\\/\\/)?(.+?)\\.(.+?)$",
                message: "Please enter valid URL."
            },
            tel: {
                pattern: "^\\(?(\\d{3})\\)?[- ]?(\\d{3})[- ]?(\\d{4})$",
                message: "Please enter valid phone number."
            }
        }
        
        
    };
    
})(jQuery);

