1/*
2 * Copyright (C) 2009 The Libphonenumber Authors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.i18n.phonenumbers;
18
19import com.google.i18n.phonenumbers.Phonemetadata.NumberFormat;
20import com.google.i18n.phonenumbers.Phonemetadata.PhoneMetadata;
21
22import java.util.ArrayList;
23import java.util.Iterator;
24import java.util.List;
25import java.util.regex.Matcher;
26import java.util.regex.Pattern;
27
28/**
29 * A formatter which formats phone numbers as they are entered.
30 *
31 * <p>An AsYouTypeFormatter can be created by invoking
32 * {@link PhoneNumberUtil#getAsYouTypeFormatter}. After that, digits can be added by invoking
33 * {@link #inputDigit} on the formatter instance, and the partially formatted phone number will be
34 * returned each time a digit is added. {@link #clear} can be invoked before formatting a new
35 * number.
36 *
37 * <p>See the unittests for more details on how the formatter is to be used.
38 *
39 * @author Shaopeng Jia
40 */
41public class AsYouTypeFormatter {
42  private String currentOutput = "";
43  private StringBuilder formattingTemplate = new StringBuilder();
44  // The pattern from numberFormat that is currently used to create formattingTemplate.
45  private String currentFormattingPattern = "";
46  private StringBuilder accruedInput = new StringBuilder();
47  private StringBuilder accruedInputWithoutFormatting = new StringBuilder();
48  // This indicates whether AsYouTypeFormatter is currently doing the formatting.
49  private boolean ableToFormat = true;
50  // Set to true when users enter their own formatting. AsYouTypeFormatter will do no formatting at
51  // all when this is set to true.
52  private boolean inputHasFormatting = false;
53  // This is set to true when we know the user is entering a full national significant number, since
54  // we have either detected a national prefix or an international dialing prefix. When this is
55  // true, we will no longer use local number formatting patterns.
56  private boolean isCompleteNumber = false;
57  private boolean isExpectingCountryCallingCode = false;
58  private final PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
59  private String defaultCountry;
60
61  // Character used when appropriate to separate a prefix, such as a long NDD or a country calling
62  // code, from the national number.
63  private static final char SEPARATOR_BEFORE_NATIONAL_NUMBER = ' ';
64  private static final PhoneMetadata EMPTY_METADATA =
65      new PhoneMetadata().setInternationalPrefix("NA");
66  private PhoneMetadata defaultMetadata;
67  private PhoneMetadata currentMetadata;
68
69  // A pattern that is used to match character classes in regular expressions. An example of a
70  // character class is [1-4].
71  private static final Pattern CHARACTER_CLASS_PATTERN = Pattern.compile("\\[([^\\[\\]])*\\]");
72  // Any digit in a regular expression that actually denotes a digit. For example, in the regular
73  // expression 80[0-2]\d{6,10}, the first 2 digits (8 and 0) are standalone digits, but the rest
74  // are not.
75  // Two look-aheads are needed because the number following \\d could be a two-digit number, since
76  // the phone number can be as long as 15 digits.
77  private static final Pattern STANDALONE_DIGIT_PATTERN = Pattern.compile("\\d(?=[^,}][^,}])");
78
79  // A pattern that is used to determine if a numberFormat under availableFormats is eligible to be
80  // used by the AYTF. It is eligible when the format element under numberFormat contains groups of
81  // the dollar sign followed by a single digit, separated by valid phone number punctuation. This
82  // prevents invalid punctuation (such as the star sign in Israeli star numbers) getting into the
83  // output of the AYTF.
84  private static final Pattern ELIGIBLE_FORMAT_PATTERN =
85      Pattern.compile("[" + PhoneNumberUtil.VALID_PUNCTUATION + "]*"
86          + "(\\$\\d" + "[" + PhoneNumberUtil.VALID_PUNCTUATION + "]*)+");
87  // A set of characters that, if found in a national prefix formatting rules, are an indicator to
88  // us that we should separate the national prefix from the number when formatting.
89  private static final Pattern NATIONAL_PREFIX_SEPARATORS_PATTERN = Pattern.compile("[- ]");
90
91  // This is the minimum length of national number accrued that is required to trigger the
92  // formatter. The first element of the leadingDigitsPattern of each numberFormat contains a
93  // regular expression that matches up to this number of digits.
94  private static final int MIN_LEADING_DIGITS_LENGTH = 3;
95
96  // The digits that have not been entered yet will be represented by a \u2008, the punctuation
97  // space.
98  private static final String DIGIT_PLACEHOLDER = "\u2008";
99  private static final Pattern DIGIT_PATTERN = Pattern.compile(DIGIT_PLACEHOLDER);
100  private int lastMatchPosition = 0;
101  // The position of a digit upon which inputDigitAndRememberPosition is most recently invoked, as
102  // found in the original sequence of characters the user entered.
103  private int originalPosition = 0;
104  // The position of a digit upon which inputDigitAndRememberPosition is most recently invoked, as
105  // found in accruedInputWithoutFormatting.
106  private int positionToRemember = 0;
107  // This contains anything that has been entered so far preceding the national significant number,
108  // and it is formatted (e.g. with space inserted). For example, this can contain IDD, country
109  // code, and/or NDD, etc.
110  private StringBuilder prefixBeforeNationalNumber = new StringBuilder();
111  private boolean shouldAddSpaceAfterNationalPrefix = false;
112  // This contains the national prefix that has been extracted. It contains only digits without
113  // formatting.
114  private String extractedNationalPrefix = "";
115  private StringBuilder nationalNumber = new StringBuilder();
116  private List<NumberFormat> possibleFormats = new ArrayList<NumberFormat>();
117
118  // A cache for frequently used country-specific regular expressions.
119  private RegexCache regexCache = new RegexCache(64);
120
121  /**
122   * Constructs an as-you-type formatter. Should be obtained from {@link
123   * PhoneNumberUtil#getAsYouTypeFormatter}.
124   *
125   * @param regionCode  the country/region where the phone number is being entered
126   */
127  AsYouTypeFormatter(String regionCode) {
128    defaultCountry = regionCode;
129    currentMetadata = getMetadataForRegion(defaultCountry);
130    defaultMetadata = currentMetadata;
131  }
132
133  // The metadata needed by this class is the same for all regions sharing the same country calling
134  // code. Therefore, we return the metadata for "main" region for this country calling code.
135  private PhoneMetadata getMetadataForRegion(String regionCode) {
136    int countryCallingCode = phoneUtil.getCountryCodeForRegion(regionCode);
137    String mainCountry = phoneUtil.getRegionCodeForCountryCode(countryCallingCode);
138    PhoneMetadata metadata = phoneUtil.getMetadataForRegion(mainCountry);
139    if (metadata != null) {
140      return metadata;
141    }
142    // Set to a default instance of the metadata. This allows us to function with an incorrect
143    // region code, even if formatting only works for numbers specified with "+".
144    return EMPTY_METADATA;
145  }
146
147  // Returns true if a new template is created as opposed to reusing the existing template.
148  private boolean maybeCreateNewTemplate() {
149    // When there are multiple available formats, the formatter uses the first format where a
150    // formatting template could be created.
151    Iterator<NumberFormat> it = possibleFormats.iterator();
152    while (it.hasNext()) {
153      NumberFormat numberFormat = it.next();
154      String pattern = numberFormat.getPattern();
155      if (currentFormattingPattern.equals(pattern)) {
156        return false;
157      }
158      if (createFormattingTemplate(numberFormat)) {
159        currentFormattingPattern = pattern;
160        shouldAddSpaceAfterNationalPrefix =
161            NATIONAL_PREFIX_SEPARATORS_PATTERN.matcher(
162                numberFormat.getNationalPrefixFormattingRule()).find();
163        // With a new formatting template, the matched position using the old template needs to be
164        // reset.
165        lastMatchPosition = 0;
166        return true;
167      } else {  // Remove the current number format from possibleFormats.
168        it.remove();
169      }
170    }
171    ableToFormat = false;
172    return false;
173  }
174
175  private void getAvailableFormats(String leadingDigits) {
176    List<NumberFormat> formatList =
177        (isCompleteNumber && currentMetadata.intlNumberFormatSize() > 0)
178        ? currentMetadata.intlNumberFormats()
179        : currentMetadata.numberFormats();
180    boolean nationalPrefixIsUsedByCountry = currentMetadata.hasNationalPrefix();
181    for (NumberFormat format : formatList) {
182      if (!nationalPrefixIsUsedByCountry
183          || isCompleteNumber
184          || format.isNationalPrefixOptionalWhenFormatting()
185          || PhoneNumberUtil.formattingRuleHasFirstGroupOnly(
186              format.getNationalPrefixFormattingRule())) {
187        if (isFormatEligible(format.getFormat())) {
188          possibleFormats.add(format);
189        }
190      }
191    }
192    narrowDownPossibleFormats(leadingDigits);
193  }
194
195  private boolean isFormatEligible(String format) {
196    return ELIGIBLE_FORMAT_PATTERN.matcher(format).matches();
197  }
198
199  private void narrowDownPossibleFormats(String leadingDigits) {
200    int indexOfLeadingDigitsPattern = leadingDigits.length() - MIN_LEADING_DIGITS_LENGTH;
201    Iterator<NumberFormat> it = possibleFormats.iterator();
202    while (it.hasNext()) {
203      NumberFormat format = it.next();
204      if (format.leadingDigitsPatternSize() == 0) {
205        // Keep everything that isn't restricted by leading digits.
206        continue;
207      }
208      int lastLeadingDigitsPattern =
209          Math.min(indexOfLeadingDigitsPattern, format.leadingDigitsPatternSize() - 1);
210      Pattern leadingDigitsPattern = regexCache.getPatternForRegex(
211          format.getLeadingDigitsPattern(lastLeadingDigitsPattern));
212      Matcher m = leadingDigitsPattern.matcher(leadingDigits);
213      if (!m.lookingAt()) {
214        it.remove();
215      }
216    }
217  }
218
219  private boolean createFormattingTemplate(NumberFormat format) {
220    String numberPattern = format.getPattern();
221
222    // The formatter doesn't format numbers when numberPattern contains "|", e.g.
223    // (20|3)\d{4}. In those cases we quickly return.
224    if (numberPattern.indexOf('|') != -1) {
225      return false;
226    }
227
228    // Replace anything in the form of [..] with \d
229    numberPattern = CHARACTER_CLASS_PATTERN.matcher(numberPattern).replaceAll("\\\\d");
230
231    // Replace any standalone digit (not the one in d{}) with \d
232    numberPattern = STANDALONE_DIGIT_PATTERN.matcher(numberPattern).replaceAll("\\\\d");
233    formattingTemplate.setLength(0);
234    String tempTemplate = getFormattingTemplate(numberPattern, format.getFormat());
235    if (tempTemplate.length() > 0) {
236      formattingTemplate.append(tempTemplate);
237      return true;
238    }
239    return false;
240  }
241
242  // Gets a formatting template which can be used to efficiently format a partial number where
243  // digits are added one by one.
244  private String getFormattingTemplate(String numberPattern, String numberFormat) {
245    // Creates a phone number consisting only of the digit 9 that matches the
246    // numberPattern by applying the pattern to the longestPhoneNumber string.
247    String longestPhoneNumber = "999999999999999";
248    Matcher m = regexCache.getPatternForRegex(numberPattern).matcher(longestPhoneNumber);
249    m.find();  // this will always succeed
250    String aPhoneNumber = m.group();
251    // No formatting template can be created if the number of digits entered so far is longer than
252    // the maximum the current formatting rule can accommodate.
253    if (aPhoneNumber.length() < nationalNumber.length()) {
254      return "";
255    }
256    // Formats the number according to numberFormat
257    String template = aPhoneNumber.replaceAll(numberPattern, numberFormat);
258    // Replaces each digit with character DIGIT_PLACEHOLDER
259    template = template.replaceAll("9", DIGIT_PLACEHOLDER);
260    return template;
261  }
262
263  /**
264   * Clears the internal state of the formatter, so it can be reused.
265   */
266  public void clear() {
267    currentOutput = "";
268    accruedInput.setLength(0);
269    accruedInputWithoutFormatting.setLength(0);
270    formattingTemplate.setLength(0);
271    lastMatchPosition = 0;
272    currentFormattingPattern = "";
273    prefixBeforeNationalNumber.setLength(0);
274    extractedNationalPrefix = "";
275    nationalNumber.setLength(0);
276    ableToFormat = true;
277    inputHasFormatting = false;
278    positionToRemember = 0;
279    originalPosition = 0;
280    isCompleteNumber = false;
281    isExpectingCountryCallingCode = false;
282    possibleFormats.clear();
283    shouldAddSpaceAfterNationalPrefix = false;
284    if (!currentMetadata.equals(defaultMetadata)) {
285      currentMetadata = getMetadataForRegion(defaultCountry);
286    }
287  }
288
289  /**
290   * Formats a phone number on-the-fly as each digit is entered.
291   *
292   * @param nextChar  the most recently entered digit of a phone number. Formatting characters are
293   *     allowed, but as soon as they are encountered this method formats the number as entered and
294   *     not "as you type" anymore. Full width digits and Arabic-indic digits are allowed, and will
295   *     be shown as they are.
296   * @return  the partially formatted phone number.
297   */
298  public String inputDigit(char nextChar) {
299    currentOutput = inputDigitWithOptionToRememberPosition(nextChar, false);
300    return currentOutput;
301  }
302
303  /**
304   * Same as {@link #inputDigit}, but remembers the position where {@code nextChar} is inserted, so
305   * that it can be retrieved later by using {@link #getRememberedPosition}. The remembered
306   * position will be automatically adjusted if additional formatting characters are later
307   * inserted/removed in front of {@code nextChar}.
308   */
309  public String inputDigitAndRememberPosition(char nextChar) {
310    currentOutput = inputDigitWithOptionToRememberPosition(nextChar, true);
311    return currentOutput;
312  }
313
314  @SuppressWarnings("fallthrough")
315  private String inputDigitWithOptionToRememberPosition(char nextChar, boolean rememberPosition) {
316    accruedInput.append(nextChar);
317    if (rememberPosition) {
318      originalPosition = accruedInput.length();
319    }
320    // We do formatting on-the-fly only when each character entered is either a digit, or a plus
321    // sign (accepted at the start of the number only).
322    if (!isDigitOrLeadingPlusSign(nextChar)) {
323      ableToFormat = false;
324      inputHasFormatting = true;
325    } else {
326      nextChar = normalizeAndAccrueDigitsAndPlusSign(nextChar, rememberPosition);
327    }
328    if (!ableToFormat) {
329      // When we are unable to format because of reasons other than that formatting chars have been
330      // entered, it can be due to really long IDDs or NDDs. If that is the case, we might be able
331      // to do formatting again after extracting them.
332      if (inputHasFormatting) {
333        return accruedInput.toString();
334      } else if (attemptToExtractIdd()) {
335        if (attemptToExtractCountryCallingCode()) {
336          return attemptToChoosePatternWithPrefixExtracted();
337        }
338      } else if (ableToExtractLongerNdd()) {
339        // Add an additional space to separate long NDD and national significant number for
340        // readability. We don't set shouldAddSpaceAfterNationalPrefix to true, since we don't want
341        // this to change later when we choose formatting templates.
342        prefixBeforeNationalNumber.append(SEPARATOR_BEFORE_NATIONAL_NUMBER);
343        return attemptToChoosePatternWithPrefixExtracted();
344      }
345      return accruedInput.toString();
346    }
347
348    // We start to attempt to format only when at least MIN_LEADING_DIGITS_LENGTH digits (the plus
349    // sign is counted as a digit as well for this purpose) have been entered.
350    switch (accruedInputWithoutFormatting.length()) {
351      case 0:
352      case 1:
353      case 2:
354        return accruedInput.toString();
355      case 3:
356        if (attemptToExtractIdd()) {
357          isExpectingCountryCallingCode = true;
358        } else {  // No IDD or plus sign is found, might be entering in national format.
359          extractedNationalPrefix = removeNationalPrefixFromNationalNumber();
360          return attemptToChooseFormattingPattern();
361        }
362        // fall through
363      default:
364        if (isExpectingCountryCallingCode) {
365          if (attemptToExtractCountryCallingCode()) {
366            isExpectingCountryCallingCode = false;
367          }
368          return prefixBeforeNationalNumber + nationalNumber.toString();
369        }
370        if (possibleFormats.size() > 0) {  // The formatting patterns are already chosen.
371          String tempNationalNumber = inputDigitHelper(nextChar);
372          // See if the accrued digits can be formatted properly already. If not, use the results
373          // from inputDigitHelper, which does formatting based on the formatting pattern chosen.
374          String formattedNumber = attemptToFormatAccruedDigits();
375          if (formattedNumber.length() > 0) {
376            return formattedNumber;
377          }
378          narrowDownPossibleFormats(nationalNumber.toString());
379          if (maybeCreateNewTemplate()) {
380            return inputAccruedNationalNumber();
381          }
382          return ableToFormat
383             ? appendNationalNumber(tempNationalNumber)
384             : accruedInput.toString();
385        } else {
386          return attemptToChooseFormattingPattern();
387        }
388    }
389  }
390
391  private String attemptToChoosePatternWithPrefixExtracted() {
392    ableToFormat = true;
393    isExpectingCountryCallingCode = false;
394    possibleFormats.clear();
395    lastMatchPosition = 0;
396    formattingTemplate.setLength(0);
397    currentFormattingPattern = "";
398    return attemptToChooseFormattingPattern();
399  }
400
401  // @VisibleForTesting
402  String getExtractedNationalPrefix() {
403    return extractedNationalPrefix;
404  }
405
406  // Some national prefixes are a substring of others. If extracting the shorter NDD doesn't result
407  // in a number we can format, we try to see if we can extract a longer version here.
408  private boolean ableToExtractLongerNdd() {
409    if (extractedNationalPrefix.length() > 0) {
410      // Put the extracted NDD back to the national number before attempting to extract a new NDD.
411      nationalNumber.insert(0, extractedNationalPrefix);
412      // Remove the previously extracted NDD from prefixBeforeNationalNumber. We cannot simply set
413      // it to empty string because people sometimes incorrectly enter national prefix after the
414      // country code, e.g. +44 (0)20-1234-5678.
415      int indexOfPreviousNdd = prefixBeforeNationalNumber.lastIndexOf(extractedNationalPrefix);
416      prefixBeforeNationalNumber.setLength(indexOfPreviousNdd);
417    }
418    return !extractedNationalPrefix.equals(removeNationalPrefixFromNationalNumber());
419  }
420
421  private boolean isDigitOrLeadingPlusSign(char nextChar) {
422    return Character.isDigit(nextChar)
423        || (accruedInput.length() == 1
424            && PhoneNumberUtil.PLUS_CHARS_PATTERN.matcher(Character.toString(nextChar)).matches());
425  }
426
427  /**
428   * Checks to see if there is an exact pattern match for these digits. If so, we should use this
429   * instead of any other formatting template whose leadingDigitsPattern also matches the input.
430   */
431  String attemptToFormatAccruedDigits() {
432    for (NumberFormat numberFormat : possibleFormats) {
433      Matcher m = regexCache.getPatternForRegex(numberFormat.getPattern()).matcher(nationalNumber);
434      if (m.matches()) {
435        shouldAddSpaceAfterNationalPrefix =
436            NATIONAL_PREFIX_SEPARATORS_PATTERN.matcher(
437                numberFormat.getNationalPrefixFormattingRule()).find();
438        String formattedNumber = m.replaceAll(numberFormat.getFormat());
439        return appendNationalNumber(formattedNumber);
440      }
441    }
442    return "";
443  }
444
445  /**
446   * Returns the current position in the partially formatted phone number of the character which was
447   * previously passed in as the parameter of {@link #inputDigitAndRememberPosition}.
448   */
449  public int getRememberedPosition() {
450    if (!ableToFormat) {
451      return originalPosition;
452    }
453    int accruedInputIndex = 0;
454    int currentOutputIndex = 0;
455    while (accruedInputIndex < positionToRemember && currentOutputIndex < currentOutput.length()) {
456      if (accruedInputWithoutFormatting.charAt(accruedInputIndex)
457          == currentOutput.charAt(currentOutputIndex)) {
458        accruedInputIndex++;
459      }
460      currentOutputIndex++;
461    }
462    return currentOutputIndex;
463  }
464
465  /**
466   * Combines the national number with any prefix (IDD/+ and country code or national prefix) that
467   * was collected. A space will be inserted between them if the current formatting template
468   * indicates this to be suitable.
469   */
470  private String appendNationalNumber(String nationalNumber) {
471    int prefixBeforeNationalNumberLength = prefixBeforeNationalNumber.length();
472    if (shouldAddSpaceAfterNationalPrefix && prefixBeforeNationalNumberLength > 0
473        && prefixBeforeNationalNumber.charAt(prefixBeforeNationalNumberLength - 1)
474            != SEPARATOR_BEFORE_NATIONAL_NUMBER) {
475      // We want to add a space after the national prefix if the national prefix formatting rule
476      // indicates that this would normally be done, with the exception of the case where we already
477      // appended a space because the NDD was surprisingly long.
478      return new String(prefixBeforeNationalNumber) + SEPARATOR_BEFORE_NATIONAL_NUMBER
479          + nationalNumber;
480    } else {
481      return prefixBeforeNationalNumber + nationalNumber;
482    }
483  }
484
485  /**
486   * Attempts to set the formatting template and returns a string which contains the formatted
487   * version of the digits entered so far.
488   */
489  private String attemptToChooseFormattingPattern() {
490    // We start to attempt to format only when at least MIN_LEADING_DIGITS_LENGTH digits of national
491    // number (excluding national prefix) have been entered.
492    if (nationalNumber.length() >= MIN_LEADING_DIGITS_LENGTH) {
493
494      getAvailableFormats(nationalNumber.toString());
495      // See if the accrued digits can be formatted properly already.
496      String formattedNumber = attemptToFormatAccruedDigits();
497      if (formattedNumber.length() > 0) {
498        return formattedNumber;
499      }
500      return maybeCreateNewTemplate() ? inputAccruedNationalNumber() : accruedInput.toString();
501    } else {
502      return appendNationalNumber(nationalNumber.toString());
503    }
504  }
505
506  /**
507   * Invokes inputDigitHelper on each digit of the national number accrued, and returns a formatted
508   * string in the end.
509   */
510  private String inputAccruedNationalNumber() {
511    int lengthOfNationalNumber = nationalNumber.length();
512    if (lengthOfNationalNumber > 0) {
513      String tempNationalNumber = "";
514      for (int i = 0; i < lengthOfNationalNumber; i++) {
515        tempNationalNumber = inputDigitHelper(nationalNumber.charAt(i));
516      }
517      return ableToFormat ? appendNationalNumber(tempNationalNumber) : accruedInput.toString();
518    } else {
519      return prefixBeforeNationalNumber.toString();
520    }
521  }
522
523  /**
524   * Returns true if the current country is a NANPA country and the national number begins with
525   * the national prefix.
526   */
527  private boolean isNanpaNumberWithNationalPrefix() {
528    // For NANPA numbers beginning with 1[2-9], treat the 1 as the national prefix. The reason is
529    // that national significant numbers in NANPA always start with [2-9] after the national prefix.
530    // Numbers beginning with 1[01] can only be short/emergency numbers, which don't need the
531    // national prefix.
532    return (currentMetadata.getCountryCode() == 1) && (nationalNumber.charAt(0) == '1')
533        && (nationalNumber.charAt(1) != '0') && (nationalNumber.charAt(1) != '1');
534  }
535
536  // Returns the national prefix extracted, or an empty string if it is not present.
537  private String removeNationalPrefixFromNationalNumber() {
538    int startOfNationalNumber = 0;
539    if (isNanpaNumberWithNationalPrefix()) {
540      startOfNationalNumber = 1;
541      prefixBeforeNationalNumber.append('1').append(SEPARATOR_BEFORE_NATIONAL_NUMBER);
542      isCompleteNumber = true;
543    } else if (currentMetadata.hasNationalPrefixForParsing()) {
544      Pattern nationalPrefixForParsing =
545          regexCache.getPatternForRegex(currentMetadata.getNationalPrefixForParsing());
546      Matcher m = nationalPrefixForParsing.matcher(nationalNumber);
547      // Since some national prefix patterns are entirely optional, check that a national prefix
548      // could actually be extracted.
549      if (m.lookingAt() && m.end() > 0) {
550        // When the national prefix is detected, we use international formatting rules instead of
551        // national ones, because national formatting rules could contain local formatting rules
552        // for numbers entered without area code.
553        isCompleteNumber = true;
554        startOfNationalNumber = m.end();
555        prefixBeforeNationalNumber.append(nationalNumber.substring(0, startOfNationalNumber));
556      }
557    }
558    String nationalPrefix = nationalNumber.substring(0, startOfNationalNumber);
559    nationalNumber.delete(0, startOfNationalNumber);
560    return nationalPrefix;
561  }
562
563  /**
564   * Extracts IDD and plus sign to prefixBeforeNationalNumber when they are available, and places
565   * the remaining input into nationalNumber.
566   *
567   * @return  true when accruedInputWithoutFormatting begins with the plus sign or valid IDD for
568   *     defaultCountry.
569   */
570  private boolean attemptToExtractIdd() {
571    Pattern internationalPrefix =
572        regexCache.getPatternForRegex("\\" + PhoneNumberUtil.PLUS_SIGN + "|"
573            + currentMetadata.getInternationalPrefix());
574    Matcher iddMatcher = internationalPrefix.matcher(accruedInputWithoutFormatting);
575    if (iddMatcher.lookingAt()) {
576      isCompleteNumber = true;
577      int startOfCountryCallingCode = iddMatcher.end();
578      nationalNumber.setLength(0);
579      nationalNumber.append(accruedInputWithoutFormatting.substring(startOfCountryCallingCode));
580      prefixBeforeNationalNumber.setLength(0);
581      prefixBeforeNationalNumber.append(
582          accruedInputWithoutFormatting.substring(0, startOfCountryCallingCode));
583      if (accruedInputWithoutFormatting.charAt(0) != PhoneNumberUtil.PLUS_SIGN) {
584        prefixBeforeNationalNumber.append(SEPARATOR_BEFORE_NATIONAL_NUMBER);
585      }
586      return true;
587    }
588    return false;
589  }
590
591  /**
592   * Extracts the country calling code from the beginning of nationalNumber to
593   * prefixBeforeNationalNumber when they are available, and places the remaining input into
594   * nationalNumber.
595   *
596   * @return  true when a valid country calling code can be found.
597   */
598  private boolean attemptToExtractCountryCallingCode() {
599    if (nationalNumber.length() == 0) {
600      return false;
601    }
602    StringBuilder numberWithoutCountryCallingCode = new StringBuilder();
603    int countryCode = phoneUtil.extractCountryCode(nationalNumber, numberWithoutCountryCallingCode);
604    if (countryCode == 0) {
605      return false;
606    }
607    nationalNumber.setLength(0);
608    nationalNumber.append(numberWithoutCountryCallingCode);
609    String newRegionCode = phoneUtil.getRegionCodeForCountryCode(countryCode);
610    if (PhoneNumberUtil.REGION_CODE_FOR_NON_GEO_ENTITY.equals(newRegionCode)) {
611      currentMetadata = phoneUtil.getMetadataForNonGeographicalRegion(countryCode);
612    } else if (!newRegionCode.equals(defaultCountry)) {
613      currentMetadata = getMetadataForRegion(newRegionCode);
614    }
615    String countryCodeString = Integer.toString(countryCode);
616    prefixBeforeNationalNumber.append(countryCodeString).append(SEPARATOR_BEFORE_NATIONAL_NUMBER);
617    // When we have successfully extracted the IDD, the previously extracted NDD should be cleared
618    // because it is no longer valid.
619    extractedNationalPrefix = "";
620    return true;
621  }
622
623  // Accrues digits and the plus sign to accruedInputWithoutFormatting for later use. If nextChar
624  // contains a digit in non-ASCII format (e.g. the full-width version of digits), it is first
625  // normalized to the ASCII version. The return value is nextChar itself, or its normalized
626  // version, if nextChar is a digit in non-ASCII format. This method assumes its input is either a
627  // digit or the plus sign.
628  private char normalizeAndAccrueDigitsAndPlusSign(char nextChar, boolean rememberPosition) {
629    char normalizedChar;
630    if (nextChar == PhoneNumberUtil.PLUS_SIGN) {
631      normalizedChar = nextChar;
632      accruedInputWithoutFormatting.append(nextChar);
633    } else {
634      int radix = 10;
635      normalizedChar = Character.forDigit(Character.digit(nextChar, radix), radix);
636      accruedInputWithoutFormatting.append(normalizedChar);
637      nationalNumber.append(normalizedChar);
638    }
639    if (rememberPosition) {
640      positionToRemember = accruedInputWithoutFormatting.length();
641    }
642    return normalizedChar;
643  }
644
645  private String inputDigitHelper(char nextChar) {
646    // Note that formattingTemplate is not guaranteed to have a value, it could be empty, e.g.
647    // when the next digit is entered after extracting an IDD or NDD.
648    Matcher digitMatcher = DIGIT_PATTERN.matcher(formattingTemplate);
649    if (digitMatcher.find(lastMatchPosition)) {
650      String tempTemplate = digitMatcher.replaceFirst(Character.toString(nextChar));
651      formattingTemplate.replace(0, tempTemplate.length(), tempTemplate);
652      lastMatchPosition = digitMatcher.start();
653      return formattingTemplate.substring(0, lastMatchPosition + 1);
654    } else {
655      if (possibleFormats.size() == 1) {
656        // More digits are entered than we could handle, and there are no other valid patterns to
657        // try.
658        ableToFormat = false;
659      }  // else, we just reset the formatting pattern.
660      currentFormattingPattern = "";
661      return accruedInput.toString();
662    }
663  }
664}
665