(function($){
    function jqueryValidateCurrency(value, element, params)
    {
        var settings = {symbol:"$", group:",", decimal:".", maxDecimals:"2"};
        $.extend(settings, params);

        var sign = settings.symbol == "$" ? "\\$" : settings.symbol;
        var group = settings.group == "," ? "\\," : settings.group;
        var dec = settings.decimal == "." ? "\\." : settings.decimal;
        var places = settings.maxDecimals;

        var expr = new RegExp("^\\+?( ?(" + sign + ")? ?((\\d+|\\d{1,3})((" + group + ")?\\d{3})*)?(" + dec + "(\\d{1," + places + "})?)?)$");
        var matches = expr.exec(value);
        return matches && matches.length > 0;
    }
    
    function jqueryValidatePositiveCurrency(value, element, params)
    {
      // Validate currency
      if (!(jqueryValidateCurrency(value, element, params))) return false;
      if (!value) return true;
      
      // Settings
      var settings = {symbol:"$", group:",", decimal:".", maxDecimals:"2"};
      $.extend(settings, params);
      
      // Parse float
      var noSign = value.replace(settings.symbol, "");
      var value = parseFloat(noSign);
      
      // Determine if > 0
      return value > 0;
    }

    function jqueryValidatePhone(value, element, params)
    {
        if( !value )
            return true;

        // Australian land line
        if( value.match(/^\(?(\d{2})\)?\s*(\d{4})\s*(\d{4})(\s*((ext)|x)\s*\d+)?$/) )
            return true;

        // Australian land line w/ country code
        if( value.match(/^(\+\d{2})\s*\(?(\d{1,2})\)?\s*(\d{4})\s*(\d{4})(\s*((ext)|x)\s*\d+)?$/) )
            return true;

        // Australian mobile
        if( value.match(/^\d{4}\s*\d{3}\s*\d{3}$/) )
            return true;

        // Matches any of the following North American formats:
        // "(555) 555-5555"
        // "(555) 555-5555 ext 23"
        // "(555) 555-5555 x 23"
        // "555 555 5555"
        // "555-555-5555"
        // "555 - 555    - 5555     ext 493234"
        var expr = /^(\(?(\d{3})\)?)?\s*-?\s*(\d{3})\s*-?\s*(\d{4})(\s*((ext)|x)\s*(\d+))?$/;
        var matches = value.match(expr);

        if( matches && matches[3] && matches[4] )   // have to have at least the main part (555-5555)
        {
            var areaCode = matches[2];
            var prefix = matches[3];
            var suffix = matches[4];
            var ext = matches[8];

            var newNumber = areaCode ? ("(" + areaCode + ") ") : "";
            newNumber += prefix + "-" + suffix;
            if( ext )
                newNumber += " ext " + ext;

            $(element).val(newNumber);
            return true;
        }
        return false;
    }
    
    /** Slightly different phone validation used by Personal Fundraising */
    function jqueryValidatePhoneByCountry(value, element, params)
    {
      // Get country from country selector
      var country = "";
      if (self.countrySelectorData) country = $("#" + self.countrySelectorData.boxId).val();
      
      // Fire validation based upon country
      if (!country) return true; // Nothing to do
      if (country == "US" || country == "CA") return jqueryValidateUSCAPhone(value, element, params);
      if (country =="AU") return jqueryValidateAUPhone(value, element, params);
      return true;
    }
    
    function jqueryValidateUSCAPhone(value, element, params)
    {
      // Matches any of the following North American formats:
      // "(555) 555-5555"
      // "(555) 555-5555 ext 23"
      // "(555) 555-5555 x 23"
      // "555 555 5555"
      // "555-555-5555"
      // "555 - 555    - 5555     ext 493234"
      var expr = /^(\(?(\d{3})\)?)?\s*-?\s*(\d{3})\s*-?\s*(\d{4})(\s*((ext)|x)\s*(\d+))?$/;
      var matches = value.match(expr);

      if( matches && matches[3] && matches[4] )   // have to have at least the main part (555-5555)
      {
          var areaCode = matches[2];
          var prefix = matches[3];
          var suffix = matches[4];
          var ext = matches[8];

          var newNumber = areaCode ? ("(" + areaCode + ") ") : "";
          newNumber += prefix + "-" + suffix;
          if( ext )
              newNumber += " ext " + ext;

          $(element).val(newNumber);
          return true;
      }
      return false;
    }
    
    function jqueryValidateAUPhone(value, element, params)
    {
      // Australian land line
      if( value.match(/^\(?(\d{2})\)?\s*(\d{4})\s*(\d{4})(\s*((ext)|x)\s*\d+)?$/) )
          return true;

      // Australian land line w/ country code
      if( value.match(/^(\+\d{2})\s*\(?(\d{1,2})\)?\s*(\d{4})\s*(\d{4})(\s*((ext)|x)\s*\d+)?$/) )
          return true;

      // Australian mobile
      if( value.match(/^\d{4}\s*\d{3}\s*\d{3}$/) )
          return true;
      
      return false;
    }

    function jqueryValidateMultipleEmails(value, element)
    {
        if( this.optional(element) )
            return true;

        var emailOnly = /^[0-9a-zA-z\.\-_]+@[0-9a-zA-z\.\-_]+\.[a-z]+$/;
        var fullEmail = /^\"[^\"]+\" <[0-9a-zA-z\.\-_]+@[0-9a-zA-z\.\-_]+\.[a-z]+>$/;
        var everyone = /^\[Everyone\]$/;

        var normal = value.replace(/[\r\n;]/g, ",");
        var emails = normal.split(",");

        var passed = true;
        $.each(emails, function(i, x) {
            x = $.trim(x);
            if( !fullEmail.test(x) && !emailOnly.test(x) && !everyone.test(x) )
                passed = false;
        });

        return passed;
    }

    function jqueryValidateBasicEtapPassword(value, element)
    {
        if( this.optional(element) )
            return true;

        value = value.toLowerCase();

        if( value.length < 6 )
            return false;

        if( value == "password" )
            return false;

        var same = true;
        var consec = true;
        $.each(value, function(i) {
            if( i > 0 && value.charAt(i-1) != value.charAt(i) )
                same = false;

            if( i > 0 && (value.charCodeAt(i-1)+1) != value.charCodeAt(i) )
                consec = false;
        });

        return !(same || consec);
    }
    
    $.validator.addMethod("currency", jqueryValidateCurrency, "Please enter a valid currency value.");
    $.validator.addMethod("positiveCurrency", jqueryValidatePositiveCurrency, "Please enter a valid currency value greater than zero.");
    $.validator.addMethod("phone", jqueryValidatePhone, "Please enter a valid phone number.");
    $.validator.addMethod("phoneByCountry", jqueryValidatePhoneByCountry, "Please enter a valid phone number for the country you selected.");
    $.validator.addMethod("emails", jqueryValidateMultipleEmails, "Please enter valid email addresses.");
    $.validator.addMethod("etapPassword", jqueryValidateBasicEtapPassword, "Password does not match minimum strength requirements.");
})(jQuery);

