(function($){

    var phone_regex = /^(1-?)?(\([2-9]\d{2}\)|[2-9]\d{2})-?[2-9]\d{2}-?\d{4}$/;

    var states = ['AL','AK','AS','AZ','AR','CA','CO','CT','DE','DC','FM','FL','GA','GU','HI','ID','IL','IA','KS','KY','LA','ME','MH','MD','MA','MI','MN','MS','MO','MT','NE','NV','NH','NJ','NM','NY','NC','ND','MP','OH','OK','OR','PW','PA','PR','RI','SC','SD','TN','TX','UT','VT','VI','VA','WA','WV','WI','WY'];

    if ($.validator) {
        $.validator.addMethod("match", function(value, element, param) {
            return this.optional(element) || value.match(new RegExp("^(" + param + ")$", "i"));
        });
        $.validator.addMethod("endswith", function(value, element, param) {
            return this.optional(element) || (value.match(param+'$')==param);
        }, $.format('Please enter in a value that ends with {0}'));
        $.validator.addMethod("phoneUS", function(phone_number, element) {
            phone_number = phone_number.replace(/\s+/g, "");
            var valid = phone_number.length > 9 && phone_number.match(phone_regex);
            return this.optional(element) || valid;
        }, "Please specify a valid phone number");
        $.validator.addMethod('phone_number', function(phone_number, element) {
            phone_number = phone_number.replace(/\s+|_+/g, "");
            var valid = false;
            var stripped_phone_number = $.stripChars(phone_number);
            if (stripped_phone_number.length >= 6) {
                valid = stripped_phone_number.length > 9 && phone_number.match(phone_regex);
            } else if (stripped_phone_number.length >= 3) {
                valid = /^\d+$/.test(phone_number);
            }
            return this.optional(element) || valid;
        }, "Please specify a valid phone number or extension");
        $.validator.addMethod('extension_domestic_international_phone_number', function(phone_number, element) {
            phone_number = phone_number.replace(/\s+/g, "");
            var valid = false;
            var stripped_phone_number = $.stripChars(phone_number);
            if (stripped_phone_number.length >= 11) { // international
                valid = /^011\d+$/.test(phone_number);
            } else if (stripped_phone_number.length >= 6) { // domestic
                valid = stripped_phone_number.length > 9 && phone_number.match(phone_regex);
            } else if (stripped_phone_number.length >= 3) { // extension
                valid = /^\d+$/.test(phone_number);
            }
            return this.optional(element) || valid;
        }, "Please specify a valid extension, phone number, or international phone number without any additional characters");
        $.validator.addMethod('just_phone_number', function(phone_number, element) {
            phone_number = phone_number.replace(/\s+/g, "");
            var valid = phone_number.length > 9 && phone_number.match(phone_regex);
            return this.optional(element) || valid;
        }, "Please specify a valid phone number or extension");
        $.validator.addMethod('mac_address', function(mac, element) {
            return this.optional(element) || mac.match(/(^([0-9a-f]{2}([:]|$)){6}$|^[0-9a-f]{12}$)/);
        }, "Please specify a valid MAC address <em>(00:12:34:ab:cd:ef)</em>");
        $.validator.addMethod('notEqualToValueInObject', function(value, element, params) {
            return this.optional(element) || value != params[0][params[1]];
        }, "Passcodes cannot equal each other");
        $.validator.addMethod('just_username', function(value, element, params) {
            return this.optional(element) || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))\.?$/i.test(value);
        }, "Username is not valid");
        $.validator.addMethod('just_domain', function(value, element, params) {
            return this.optional(element) || /^((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test(value);
        }, "Domain is not valid");
        $.validator.addMethod('unique_in_values', function(value, element, params) {
            var val = params.prefix||'' + value + params.suffix||'';
            var exists = false;
            $.each(params.values, function() {
                exists = (val == this.toString());
                return !exists;
            });
            return this.optional(element) || !exists;
        }, "Value already exists");
        $.validator.addMethod('alpha', function(value, element, params) {
            return this.optional(element) || /^[a-zA-Z]+$/.test(value);
        }, "Contains non-alpha characters");
        $.validator.addMethod('alphanumeric', function(value, element, params) {
            return this.optional(element) || /^[a-zA-Z0-9]+$/.test(value);
        }, "Only letters and numbers can be used");
        $.validator.addMethod('state_abbr', function(value, element, params) {
            if (value) value=value.toUpperCase();
            return this.optional(element) || ($.inArray(value, states) != -1);
        }, "Must be a state abbreviation");
        $.validator.addMethod('does_not_start_with_zero', function(value, element, params) {
        	return this.optional(element) || !(/^0/.test(value));
        }, "Cannot start with zero");
        $.validator.addClassRules('extension',{
            required: true,
            digits: true,
            minlength: 3,
            maxlength: 5
        });
        $.validator.addClassRules('short_state',{
            alpha:true
        });
    }

    if ($.editable) {
        $.editable.addInputType('password', {
            element : function(settings, original) {
                var input = $('<input />');
                if (settings.width  != 'none') {
                    input.width(settings.width);
                }
                if (settings.height != 'none') {
                    input.height(settings.height);
                }
                /* https://bugzilla.mozilla.org/show_bug.cgi?id=236791 */
                //input[0].setAttribute('autocomplete','off');
                input.attr('autocomplete','off');
                input.attr('type','password');
                $(this).append(input);
                return(input);
            },
            content : function() {
                $(':input:first', this).val('');
            }
        });
        $.editable.addInputType('address', {
            element: function(settings, original) {
            $(this).setTemplateURL($.template('/address_input.jt')).processTemplate();
            return $('#address_json', this);
            },
            submit: function(settings, original) {
                var value = {
                        line1: $('#address_line1', this).val(),
                        line2: $('#address_line2', this).val(),
                        city: $('#address_city', this).val(),
                        state: $('#address_state', this).val(),
                        zip: $('#address_zip', this).val()
                };
                $('#address_json', this).val($.toJSON(value));
            },
            content: function(htmlString, settings, original) {
                var html = $('<div></div>');
                html.html(htmlString);
                $('#address_line1', this).val(html.find('.line1').text());
                $('#address_line2', this).val(html.find('.line2').text());
                $('#address_city', this).val(html.find('.city').text());
                $('#address_state', this).val(html.find('.state').text());
                $('#address_zip', this).val(html.find('.zip').text());
            }
        });
    }

})(jQuery);
