JAVA/JS/CPP:libphonenumber v7.0 last changes
[platform/upstream/libphonenumber.git] / javascript / i18n / phonenumbers / phonenumberutil.js
1 /**
2  * @license
3  * Copyright (C) 2010 The Libphonenumber Authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 /**
19  * @fileoverview  Utility for international phone numbers.
20  * Functionality includes formatting, parsing and validation.
21  * (based on the java implementation).
22  *
23  * NOTE: A lot of methods in this class require Region Code strings. These must
24  * be provided using ISO 3166-1 two-letter country-code format. These should be
25  * in upper-case (but for compatibility lower-case is also allowed). The list of
26  * the codes can be found here:
27  * http://www.iso.org/iso/english_country_names_and_code_elements
28  *
29  * @author Nikolaos Trogkanis
30  */
31
32 goog.provide('i18n.phonenumbers.Error');
33 goog.provide('i18n.phonenumbers.PhoneNumberFormat');
34 goog.provide('i18n.phonenumbers.PhoneNumberType');
35 goog.provide('i18n.phonenumbers.PhoneNumberUtil');
36 goog.provide('i18n.phonenumbers.PhoneNumberUtil.MatchType');
37 goog.provide('i18n.phonenumbers.PhoneNumberUtil.ValidationResult');
38
39 goog.require('goog.array');
40 goog.require('goog.proto2.PbLiteSerializer');
41 goog.require('goog.string');
42 goog.require('goog.string.StringBuffer');
43 goog.require('i18n.phonenumbers.NumberFormat');
44 goog.require('i18n.phonenumbers.PhoneMetadata');
45 goog.require('i18n.phonenumbers.PhoneMetadataCollection');
46 goog.require('i18n.phonenumbers.PhoneNumber');
47 goog.require('i18n.phonenumbers.PhoneNumber.CountryCodeSource');
48 goog.require('i18n.phonenumbers.PhoneNumberDesc');
49 goog.require('i18n.phonenumbers.metadata');
50
51
52
53 /**
54  * @constructor
55  * @private
56  */
57 i18n.phonenumbers.PhoneNumberUtil = function() {
58   /**
59    * A mapping from a region code to the PhoneMetadata for that region.
60    * @type {Object.<string, i18n.phonenumbers.PhoneMetadata>}
61    */
62   this.regionToMetadataMap = {};
63 };
64 goog.addSingletonGetter(i18n.phonenumbers.PhoneNumberUtil);
65
66
67 /**
68  * Errors encountered when parsing phone numbers.
69  *
70  * @enum {string}
71  */
72 i18n.phonenumbers.Error = {
73   INVALID_COUNTRY_CODE: 'Invalid country calling code',
74   // This generally indicates the string passed in had less than 3 digits in it.
75   // More specifically, the number failed to match the regular expression
76   // VALID_PHONE_NUMBER.
77   NOT_A_NUMBER: 'The string supplied did not seem to be a phone number',
78   // This indicates the string started with an international dialing prefix, but
79   // after this was stripped from the number, had less digits than any valid
80   // phone number (including country calling code) could have.
81   TOO_SHORT_AFTER_IDD: 'Phone number too short after IDD',
82   // This indicates the string, after any country calling code has been
83   // stripped, had less digits than any valid phone number could have.
84   TOO_SHORT_NSN: 'The string supplied is too short to be a phone number',
85   // This indicates the string had more digits than any valid phone number could
86   // have.
87   TOO_LONG: 'The string supplied is too long to be a phone number'
88 };
89
90
91 /**
92  * @const
93  * @type {number}
94  * @private
95  */
96 i18n.phonenumbers.PhoneNumberUtil.NANPA_COUNTRY_CODE_ = 1;
97
98
99 /**
100  * The minimum length of the national significant number.
101  *
102  * @const
103  * @type {number}
104  * @private
105  */
106 i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_ = 2;
107
108
109 /**
110  * The ITU says the maximum length should be 15, but we have found longer
111  * numbers in Germany.
112  *
113  * @const
114  * @type {number}
115  * @private
116  */
117 i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_FOR_NSN_ = 17;
118
119
120 /**
121  * The maximum length of the country calling code.
122  *
123  * @const
124  * @type {number}
125  * @private
126  */
127 i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_COUNTRY_CODE_ = 3;
128
129
130 /**
131  * We don't allow input strings for parsing to be longer than 250 chars. This
132  * prevents malicious input from consuming CPU.
133  *
134  * @const
135  * @type {number}
136  * @private
137  */
138 i18n.phonenumbers.PhoneNumberUtil.MAX_INPUT_STRING_LENGTH_ = 250;
139
140
141 /**
142  * Region-code for the unknown region.
143  *
144  * @const
145  * @type {string}
146  * @private
147  */
148 i18n.phonenumbers.PhoneNumberUtil.UNKNOWN_REGION_ = 'ZZ';
149
150
151 /**
152  * The prefix that needs to be inserted in front of a Colombian landline number
153  * when dialed from a mobile phone in Colombia.
154  *
155  * @const
156  * @type {string}
157  * @private
158  */
159 i18n.phonenumbers.PhoneNumberUtil.COLOMBIA_MOBILE_TO_FIXED_LINE_PREFIX_ = '3';
160
161
162 /**
163  * Map of country calling codes that use a mobile token before the area code.
164  * One example of when this is relevant is when determining the length of the
165  * national destination code, which should be the length of the area code plus
166  * the length of the mobile token.
167  *
168  * @const
169  * @type {!Object.<number, string>}
170  * @private
171  */
172 i18n.phonenumbers.PhoneNumberUtil.MOBILE_TOKEN_MAPPINGS_ = {
173   52: '1',
174   54: '9'
175 };
176
177
178 /**
179  * The PLUS_SIGN signifies the international prefix.
180  *
181  * @const
182  * @type {string}
183  */
184 i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN = '+';
185
186
187 /**
188  * @const
189  * @type {string}
190  * @private
191  */
192 i18n.phonenumbers.PhoneNumberUtil.STAR_SIGN_ = '*';
193
194
195 /**
196  * The RFC 3966 format for extensions.
197  *
198  * @const
199  * @type {string}
200  * @private
201  */
202 i18n.phonenumbers.PhoneNumberUtil.RFC3966_EXTN_PREFIX_ = ';ext=';
203
204
205 /**
206  * @const
207  * @type {string}
208  * @private
209  */
210 i18n.phonenumbers.PhoneNumberUtil.RFC3966_PREFIX_ = 'tel:';
211
212
213 /**
214  * @const
215  * @type {string}
216  * @private
217  */
218 i18n.phonenumbers.PhoneNumberUtil.RFC3966_PHONE_CONTEXT_ = ';phone-context=';
219
220
221 /**
222  * @const
223  * @type {string}
224  * @private
225  */
226 i18n.phonenumbers.PhoneNumberUtil.RFC3966_ISDN_SUBADDRESS_ = ';isub=';
227
228
229 /**
230  * These mappings map a character (key) to a specific digit that should replace
231  * it for normalization purposes. Non-European digits that may be used in phone
232  * numbers are mapped to a European equivalent.
233  *
234  * @const
235  * @type {!Object.<string, string>}
236  */
237 i18n.phonenumbers.PhoneNumberUtil.DIGIT_MAPPINGS = {
238   '0': '0',
239   '1': '1',
240   '2': '2',
241   '3': '3',
242   '4': '4',
243   '5': '5',
244   '6': '6',
245   '7': '7',
246   '8': '8',
247   '9': '9',
248   '\uFF10': '0', // Fullwidth digit 0
249   '\uFF11': '1', // Fullwidth digit 1
250   '\uFF12': '2', // Fullwidth digit 2
251   '\uFF13': '3', // Fullwidth digit 3
252   '\uFF14': '4', // Fullwidth digit 4
253   '\uFF15': '5', // Fullwidth digit 5
254   '\uFF16': '6', // Fullwidth digit 6
255   '\uFF17': '7', // Fullwidth digit 7
256   '\uFF18': '8', // Fullwidth digit 8
257   '\uFF19': '9', // Fullwidth digit 9
258   '\u0660': '0', // Arabic-indic digit 0
259   '\u0661': '1', // Arabic-indic digit 1
260   '\u0662': '2', // Arabic-indic digit 2
261   '\u0663': '3', // Arabic-indic digit 3
262   '\u0664': '4', // Arabic-indic digit 4
263   '\u0665': '5', // Arabic-indic digit 5
264   '\u0666': '6', // Arabic-indic digit 6
265   '\u0667': '7', // Arabic-indic digit 7
266   '\u0668': '8', // Arabic-indic digit 8
267   '\u0669': '9', // Arabic-indic digit 9
268   '\u06F0': '0', // Eastern-Arabic digit 0
269   '\u06F1': '1', // Eastern-Arabic digit 1
270   '\u06F2': '2', // Eastern-Arabic digit 2
271   '\u06F3': '3', // Eastern-Arabic digit 3
272   '\u06F4': '4', // Eastern-Arabic digit 4
273   '\u06F5': '5', // Eastern-Arabic digit 5
274   '\u06F6': '6', // Eastern-Arabic digit 6
275   '\u06F7': '7', // Eastern-Arabic digit 7
276   '\u06F8': '8', // Eastern-Arabic digit 8
277   '\u06F9': '9'  // Eastern-Arabic digit 9
278 };
279
280
281 /**
282  * A map that contains characters that are essential when dialling. That means
283  * any of the characters in this map must not be removed from a number when
284  * dialling, otherwise the call will not reach the intended destination.
285  *
286  * @const
287  * @type {!Object.<string, string>}
288  * @private
289  */
290 i18n.phonenumbers.PhoneNumberUtil.DIALLABLE_CHAR_MAPPINGS_ = {
291   '0': '0',
292   '1': '1',
293   '2': '2',
294   '3': '3',
295   '4': '4',
296   '5': '5',
297   '6': '6',
298   '7': '7',
299   '8': '8',
300   '9': '9',
301   '+': i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN,
302   '*': '*'
303 };
304
305
306 /**
307  * Only upper-case variants of alpha characters are stored.
308  *
309  * @const
310  * @type {!Object.<string, string>}
311  * @private
312  */
313 i18n.phonenumbers.PhoneNumberUtil.ALPHA_MAPPINGS_ = {
314   'A': '2',
315   'B': '2',
316   'C': '2',
317   'D': '3',
318   'E': '3',
319   'F': '3',
320   'G': '4',
321   'H': '4',
322   'I': '4',
323   'J': '5',
324   'K': '5',
325   'L': '5',
326   'M': '6',
327   'N': '6',
328   'O': '6',
329   'P': '7',
330   'Q': '7',
331   'R': '7',
332   'S': '7',
333   'T': '8',
334   'U': '8',
335   'V': '8',
336   'W': '9',
337   'X': '9',
338   'Y': '9',
339   'Z': '9'
340 };
341
342
343 /**
344  * For performance reasons, amalgamate both into one map.
345  *
346  * @const
347  * @type {!Object.<string, string>}
348  * @private
349  */
350 i18n.phonenumbers.PhoneNumberUtil.ALL_NORMALIZATION_MAPPINGS_ = {
351   '0': '0',
352   '1': '1',
353   '2': '2',
354   '3': '3',
355   '4': '4',
356   '5': '5',
357   '6': '6',
358   '7': '7',
359   '8': '8',
360   '9': '9',
361   '\uFF10': '0', // Fullwidth digit 0
362   '\uFF11': '1', // Fullwidth digit 1
363   '\uFF12': '2', // Fullwidth digit 2
364   '\uFF13': '3', // Fullwidth digit 3
365   '\uFF14': '4', // Fullwidth digit 4
366   '\uFF15': '5', // Fullwidth digit 5
367   '\uFF16': '6', // Fullwidth digit 6
368   '\uFF17': '7', // Fullwidth digit 7
369   '\uFF18': '8', // Fullwidth digit 8
370   '\uFF19': '9', // Fullwidth digit 9
371   '\u0660': '0', // Arabic-indic digit 0
372   '\u0661': '1', // Arabic-indic digit 1
373   '\u0662': '2', // Arabic-indic digit 2
374   '\u0663': '3', // Arabic-indic digit 3
375   '\u0664': '4', // Arabic-indic digit 4
376   '\u0665': '5', // Arabic-indic digit 5
377   '\u0666': '6', // Arabic-indic digit 6
378   '\u0667': '7', // Arabic-indic digit 7
379   '\u0668': '8', // Arabic-indic digit 8
380   '\u0669': '9', // Arabic-indic digit 9
381   '\u06F0': '0', // Eastern-Arabic digit 0
382   '\u06F1': '1', // Eastern-Arabic digit 1
383   '\u06F2': '2', // Eastern-Arabic digit 2
384   '\u06F3': '3', // Eastern-Arabic digit 3
385   '\u06F4': '4', // Eastern-Arabic digit 4
386   '\u06F5': '5', // Eastern-Arabic digit 5
387   '\u06F6': '6', // Eastern-Arabic digit 6
388   '\u06F7': '7', // Eastern-Arabic digit 7
389   '\u06F8': '8', // Eastern-Arabic digit 8
390   '\u06F9': '9', // Eastern-Arabic digit 9
391   'A': '2',
392   'B': '2',
393   'C': '2',
394   'D': '3',
395   'E': '3',
396   'F': '3',
397   'G': '4',
398   'H': '4',
399   'I': '4',
400   'J': '5',
401   'K': '5',
402   'L': '5',
403   'M': '6',
404   'N': '6',
405   'O': '6',
406   'P': '7',
407   'Q': '7',
408   'R': '7',
409   'S': '7',
410   'T': '8',
411   'U': '8',
412   'V': '8',
413   'W': '9',
414   'X': '9',
415   'Y': '9',
416   'Z': '9'
417 };
418
419
420 /**
421  * Separate map of all symbols that we wish to retain when formatting alpha
422  * numbers. This includes digits, ASCII letters and number grouping symbols such
423  * as '-' and ' '.
424  *
425  * @const
426  * @type {!Object.<string, string>}
427  * @private
428  */
429 i18n.phonenumbers.PhoneNumberUtil.ALL_PLUS_NUMBER_GROUPING_SYMBOLS_ = {
430   '0': '0',
431   '1': '1',
432   '2': '2',
433   '3': '3',
434   '4': '4',
435   '5': '5',
436   '6': '6',
437   '7': '7',
438   '8': '8',
439   '9': '9',
440   'A': 'A',
441   'B': 'B',
442   'C': 'C',
443   'D': 'D',
444   'E': 'E',
445   'F': 'F',
446   'G': 'G',
447   'H': 'H',
448   'I': 'I',
449   'J': 'J',
450   'K': 'K',
451   'L': 'L',
452   'M': 'M',
453   'N': 'N',
454   'O': 'O',
455   'P': 'P',
456   'Q': 'Q',
457   'R': 'R',
458   'S': 'S',
459   'T': 'T',
460   'U': 'U',
461   'V': 'V',
462   'W': 'W',
463   'X': 'X',
464   'Y': 'Y',
465   'Z': 'Z',
466   'a': 'A',
467   'b': 'B',
468   'c': 'C',
469   'd': 'D',
470   'e': 'E',
471   'f': 'F',
472   'g': 'G',
473   'h': 'H',
474   'i': 'I',
475   'j': 'J',
476   'k': 'K',
477   'l': 'L',
478   'm': 'M',
479   'n': 'N',
480   'o': 'O',
481   'p': 'P',
482   'q': 'Q',
483   'r': 'R',
484   's': 'S',
485   't': 'T',
486   'u': 'U',
487   'v': 'V',
488   'w': 'W',
489   'x': 'X',
490   'y': 'Y',
491   'z': 'Z',
492   '-': '-',
493   '\uFF0D': '-',
494   '\u2010': '-',
495   '\u2011': '-',
496   '\u2012': '-',
497   '\u2013': '-',
498   '\u2014': '-',
499   '\u2015': '-',
500   '\u2212': '-',
501   '/': '/',
502   '\uFF0F': '/',
503   ' ': ' ',
504   '\u3000': ' ',
505   '\u2060': ' ',
506   '.': '.',
507   '\uFF0E': '.'
508 };
509
510
511 /**
512  * Pattern that makes it easy to distinguish whether a region has a unique
513  * international dialing prefix or not. If a region has a unique international
514  * prefix (e.g. 011 in USA), it will be represented as a string that contains a
515  * sequence of ASCII digits. If there are multiple available international
516  * prefixes in a region, they will be represented as a regex string that always
517  * contains character(s) other than ASCII digits. Note this regex also includes
518  * tilde, which signals waiting for the tone.
519  *
520  * @const
521  * @type {!RegExp}
522  * @private
523  */
524 i18n.phonenumbers.PhoneNumberUtil.UNIQUE_INTERNATIONAL_PREFIX_ =
525     /[\d]+(?:[~\u2053\u223C\uFF5E][\d]+)?/;
526
527
528 /**
529  * Regular expression of acceptable punctuation found in phone numbers. This
530  * excludes punctuation found as a leading character only. This consists of dash
531  * characters, white space characters, full stops, slashes, square brackets,
532  * parentheses and tildes. It also includes the letter 'x' as that is found as a
533  * placeholder for carrier information in some phone numbers. Full-width
534  * variants are also present.
535  *
536  * @const
537  * @type {string}
538  */
539 i18n.phonenumbers.PhoneNumberUtil.VALID_PUNCTUATION =
540     '-x\u2010-\u2015\u2212\u30FC\uFF0D-\uFF0F \u00A0\u00AD\u200B\u2060\u3000' +
541     '()\uFF08\uFF09\uFF3B\uFF3D.\\[\\]/~\u2053\u223C\uFF5E';
542
543
544 /**
545  * Digits accepted in phone numbers (ascii, fullwidth, arabic-indic, and eastern
546  * arabic digits).
547  *
548  * @const
549  * @type {string}
550  * @private
551  */
552 i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ =
553     '0-9\uFF10-\uFF19\u0660-\u0669\u06F0-\u06F9';
554
555
556 /**
557  * We accept alpha characters in phone numbers, ASCII only, upper and lower
558  * case.
559  *
560  * @const
561  * @type {string}
562  * @private
563  */
564 i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_ = 'A-Za-z';
565
566
567 /**
568  * @const
569  * @type {string}
570  * @private
571  */
572 i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ = '+\uFF0B';
573
574
575 /**
576  * @const
577  * @type {!RegExp}
578  */
579 i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_PATTERN =
580     new RegExp('[' + i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ + ']+');
581
582
583 /**
584  * @const
585  * @type {!RegExp}
586  * @private
587  */
588 i18n.phonenumbers.PhoneNumberUtil.LEADING_PLUS_CHARS_PATTERN_ =
589     new RegExp('^[' + i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ + ']+');
590
591
592 /**
593  * @const
594  * @type {string}
595  * @private
596  */
597 i18n.phonenumbers.PhoneNumberUtil.SEPARATOR_PATTERN_ =
598     '[' + i18n.phonenumbers.PhoneNumberUtil.VALID_PUNCTUATION + ']+';
599
600
601 /**
602  * @const
603  * @type {!RegExp}
604  */
605 i18n.phonenumbers.PhoneNumberUtil.CAPTURING_DIGIT_PATTERN =
606     new RegExp('([' + i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + '])');
607
608
609 /**
610  * Regular expression of acceptable characters that may start a phone number for
611  * the purposes of parsing. This allows us to strip away meaningless prefixes to
612  * phone numbers that may be mistakenly given to us. This consists of digits,
613  * the plus symbol and arabic-indic digits. This does not contain alpha
614  * characters, although they may be used later in the number. It also does not
615  * include other punctuation, as this will be stripped later during parsing and
616  * is of no information value when parsing a number.
617  *
618  * @const
619  * @type {!RegExp}
620  * @private
621  */
622 i18n.phonenumbers.PhoneNumberUtil.VALID_START_CHAR_PATTERN_ =
623     new RegExp('[' + i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ +
624                i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']');
625
626
627 /**
628  * Regular expression of characters typically used to start a second phone
629  * number for the purposes of parsing. This allows us to strip off parts of the
630  * number that are actually the start of another number, such as for:
631  * (530) 583-6985 x302/x2303 -> the second extension here makes this actually
632  * two phone numbers, (530) 583-6985 x302 and (530) 583-6985 x2303. We remove
633  * the second extension so that the first number is parsed correctly.
634  *
635  * @const
636  * @type {!RegExp}
637  * @private
638  */
639 i18n.phonenumbers.PhoneNumberUtil.SECOND_NUMBER_START_PATTERN_ = /[\\\/] *x/;
640
641
642 /**
643  * Regular expression of trailing characters that we want to remove. We remove
644  * all characters that are not alpha or numerical characters. The hash character
645  * is retained here, as it may signify the previous block was an extension.
646  *
647  * @const
648  * @type {!RegExp}
649  * @private
650  */
651 i18n.phonenumbers.PhoneNumberUtil.UNWANTED_END_CHAR_PATTERN_ =
652     new RegExp('[^' + i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ +
653                i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_ + '#]+$');
654
655
656 /**
657  * We use this pattern to check if the phone number has at least three letters
658  * in it - if so, then we treat it as a number where some phone-number digits
659  * are represented by letters.
660  *
661  * @const
662  * @type {!RegExp}
663  * @private
664  */
665 i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_PHONE_PATTERN_ =
666     /(?:.*?[A-Za-z]){3}.*/;
667
668
669 /**
670  * Regular expression of viable phone numbers. This is location independent.
671  * Checks we have at least three leading digits, and only valid punctuation,
672  * alpha characters and digits in the phone number. Does not include extension
673  * data. The symbol 'x' is allowed here as valid punctuation since it is often
674  * used as a placeholder for carrier codes, for example in Brazilian phone
675  * numbers. We also allow multiple '+' characters at the start.
676  * Corresponds to the following:
677  * [digits]{minLengthNsn}|
678  * plus_sign*
679  * (([punctuation]|[star])*[digits]){3,}([punctuation]|[star]|[digits]|[alpha])*
680  *
681  * The first reg-ex is to allow short numbers (two digits long) to be parsed if
682  * they are entered as "15" etc, but only if there is no punctuation in them.
683  * The second expression restricts the number of digits to three or more, but
684  * then allows them to be in international form, and to have alpha-characters
685  * and punctuation. We split up the two reg-exes here and combine them when
686  * creating the reg-ex VALID_PHONE_NUMBER_PATTERN_ itself so we can prefix it
687  * with ^ and append $ to each branch.
688  *
689  * Note VALID_PUNCTUATION starts with a -, so must be the first in the range.
690  *
691  * @const
692  * @type {string}
693  * @private
694  */
695 i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_PHONE_NUMBER_PATTERN_ =
696     '[' + i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']{' +
697     i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_ + '}';
698
699
700 /**
701  * See MIN_LENGTH_PHONE_NUMBER_PATTERN_ for a full description of this reg-exp.
702  *
703  * @const
704  * @type {string}
705  * @private
706  */
707 i18n.phonenumbers.PhoneNumberUtil.VALID_PHONE_NUMBER_ =
708     '[' + i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ + ']*(?:[' +
709     i18n.phonenumbers.PhoneNumberUtil.VALID_PUNCTUATION +
710     i18n.phonenumbers.PhoneNumberUtil.STAR_SIGN_ + ']*[' +
711     i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']){3,}[' +
712     i18n.phonenumbers.PhoneNumberUtil.VALID_PUNCTUATION +
713     i18n.phonenumbers.PhoneNumberUtil.STAR_SIGN_ +
714     i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_ +
715     i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']*';
716
717
718 /**
719  * Default extension prefix to use when formatting. This will be put in front of
720  * any extension component of the number, after the main national number is
721  * formatted. For example, if you wish the default extension formatting to be
722  * ' extn: 3456', then you should specify ' extn: ' here as the default
723  * extension prefix. This can be overridden by region-specific preferences.
724  *
725  * @const
726  * @type {string}
727  * @private
728  */
729 i18n.phonenumbers.PhoneNumberUtil.DEFAULT_EXTN_PREFIX_ = ' ext. ';
730
731
732 /**
733  * Pattern to capture digits used in an extension.
734  * Places a maximum length of '7' for an extension.
735  *
736  * @const
737  * @type {string}
738  * @private
739  */
740 i18n.phonenumbers.PhoneNumberUtil.CAPTURING_EXTN_DIGITS_ =
741     '([' + i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']{1,7})';
742
743
744 /**
745  * Regexp of all possible ways to write extensions, for use when parsing. This
746  * will be run as a case-insensitive regexp match. Wide character versions are
747  * also provided after each ASCII version. There are three regular expressions
748  * here. The first covers RFC 3966 format, where the extension is added using
749  * ';ext='. The second more generic one starts with optional white space and
750  * ends with an optional full stop (.), followed by zero or more spaces/tabs and
751  * then the numbers themselves. The other one covers the special case of
752  * American numbers where the extension is written with a hash at the end, such
753  * as '- 503#'. Note that the only capturing groups should be around the digits
754  * that you want to capture as part of the extension, or else parsing will fail!
755  * We allow two options for representing the accented o - the character itself,
756  * and one in the unicode decomposed form with the combining acute accent.
757  *
758  * @const
759  * @type {string}
760  * @private
761  */
762 i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERNS_FOR_PARSING_ =
763     i18n.phonenumbers.PhoneNumberUtil.RFC3966_EXTN_PREFIX_ +
764     i18n.phonenumbers.PhoneNumberUtil.CAPTURING_EXTN_DIGITS_ + '|' +
765     '[ \u00A0\\t,]*' +
766     '(?:e?xt(?:ensi(?:o\u0301?|\u00F3))?n?|\uFF45?\uFF58\uFF54\uFF4E?|' +
767     '[,x\uFF58#\uFF03~\uFF5E]|int|anexo|\uFF49\uFF4E\uFF54)' +
768     '[:\\.\uFF0E]?[ \u00A0\\t,-]*' +
769     i18n.phonenumbers.PhoneNumberUtil.CAPTURING_EXTN_DIGITS_ + '#?|' +
770     '[- ]+([' + i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']{1,5})#';
771
772
773 /**
774  * Regexp of all known extension prefixes used by different regions followed by
775  * 1 or more valid digits, for use when parsing.
776  *
777  * @const
778  * @type {!RegExp}
779  * @private
780  */
781 i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERN_ =
782     new RegExp('(?:' +
783                i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERNS_FOR_PARSING_ +
784                ')$', 'i');
785
786
787 /**
788  * We append optionally the extension pattern to the end here, as a valid phone
789  * number may have an extension prefix appended, followed by 1 or more digits.
790  *
791  * @const
792  * @type {!RegExp}
793  * @private
794  */
795 i18n.phonenumbers.PhoneNumberUtil.VALID_PHONE_NUMBER_PATTERN_ =
796     new RegExp(
797         '^' +
798         i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_PHONE_NUMBER_PATTERN_ +
799         '$|' +
800         '^' + i18n.phonenumbers.PhoneNumberUtil.VALID_PHONE_NUMBER_ +
801         '(?:' + i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERNS_FOR_PARSING_ +
802         ')?' + '$', 'i');
803
804
805 /**
806  * @const
807  * @type {!RegExp}
808  * @private
809  */
810 i18n.phonenumbers.PhoneNumberUtil.NON_DIGITS_PATTERN_ = /\D+/;
811
812
813 /**
814  * This was originally set to $1 but there are some countries for which the
815  * first group is not used in the national pattern (e.g. Argentina) so the $1
816  * group does not match correctly.  Therefore, we use \d, so that the first
817  * group actually used in the pattern will be matched.
818  * @const
819  * @type {!RegExp}
820  * @private
821  */
822 i18n.phonenumbers.PhoneNumberUtil.FIRST_GROUP_PATTERN_ = /(\$\d)/;
823
824
825 /**
826  * @const
827  * @type {!RegExp}
828  * @private
829  */
830 i18n.phonenumbers.PhoneNumberUtil.NP_PATTERN_ = /\$NP/;
831
832
833 /**
834  * @const
835  * @type {!RegExp}
836  * @private
837  */
838 i18n.phonenumbers.PhoneNumberUtil.FG_PATTERN_ = /\$FG/;
839
840
841 /**
842  * @const
843  * @type {!RegExp}
844  * @private
845  */
846 i18n.phonenumbers.PhoneNumberUtil.CC_PATTERN_ = /\$CC/;
847
848
849 /**
850  * A pattern that is used to determine if the national prefix formatting rule
851  * has the first group only, i.e., does not start with the national prefix.
852  * Note that the pattern explicitly allows for unbalanced parentheses.
853  * @const
854  * @type {!RegExp}
855  * @private
856  */
857 i18n.phonenumbers.PhoneNumberUtil.FIRST_GROUP_ONLY_PREFIX_PATTERN_ =
858     /^\(?\$1\)?$/;
859
860
861 /**
862  * @const
863  * @type {string}
864  */
865 i18n.phonenumbers.PhoneNumberUtil.REGION_CODE_FOR_NON_GEO_ENTITY = '001';
866
867
868 /**
869  * INTERNATIONAL and NATIONAL formats are consistent with the definition in
870  * ITU-T Recommendation E123. For example, the number of the Google Switzerland
871  * office will be written as '+41 44 668 1800' in INTERNATIONAL format, and as
872  * '044 668 1800' in NATIONAL format. E164 format is as per INTERNATIONAL format
873  * but with no formatting applied, e.g. '+41446681800'. RFC3966 is as per
874  * INTERNATIONAL format, but with all spaces and other separating symbols
875  * replaced with a hyphen, and with any phone number extension appended with
876  * ';ext='. It also will have a prefix of 'tel:' added, e.g.
877  * 'tel:+41-44-668-1800'.
878  *
879  * Note: If you are considering storing the number in a neutral format, you are
880  * highly advised to use the PhoneNumber class.
881  * @enum {number}
882  */
883 i18n.phonenumbers.PhoneNumberFormat = {
884   E164: 0,
885   INTERNATIONAL: 1,
886   NATIONAL: 2,
887   RFC3966: 3
888 };
889
890
891 /**
892  * Type of phone numbers.
893  *
894  * @enum {number}
895  */
896 i18n.phonenumbers.PhoneNumberType = {
897   FIXED_LINE: 0,
898   MOBILE: 1,
899   // In some regions (e.g. the USA), it is impossible to distinguish between
900   // fixed-line and mobile numbers by looking at the phone number itself.
901   FIXED_LINE_OR_MOBILE: 2,
902   // Freephone lines
903   TOLL_FREE: 3,
904   PREMIUM_RATE: 4,
905   // The cost of this call is shared between the caller and the recipient, and
906   // is hence typically less than PREMIUM_RATE calls. See
907   // http://en.wikipedia.org/wiki/Shared_Cost_Service for more information.
908   SHARED_COST: 5,
909   // Voice over IP numbers. This includes TSoIP (Telephony Service over IP).
910   VOIP: 6,
911   // A personal number is associated with a particular person, and may be routed
912   // to either a MOBILE or FIXED_LINE number. Some more information can be found
913   // here: http://en.wikipedia.org/wiki/Personal_Numbers
914   PERSONAL_NUMBER: 7,
915   PAGER: 8,
916   // Used for 'Universal Access Numbers' or 'Company Numbers'. They may be
917   // further routed to specific offices, but allow one number to be used for a
918   // company.
919   UAN: 9,
920   // Used for 'Voice Mail Access Numbers'.
921   VOICEMAIL: 10,
922   // A phone number is of type UNKNOWN when it does not fit any of the known
923   // patterns for a specific region.
924   UNKNOWN: -1
925 };
926
927
928 /**
929  * Types of phone number matches. See detailed description beside the
930  * isNumberMatch() method.
931  *
932  * @enum {number}
933  */
934 i18n.phonenumbers.PhoneNumberUtil.MatchType = {
935   NOT_A_NUMBER: 0,
936   NO_MATCH: 1,
937   SHORT_NSN_MATCH: 2,
938   NSN_MATCH: 3,
939   EXACT_MATCH: 4
940 };
941
942
943 /**
944  * Possible outcomes when testing if a PhoneNumber is possible.
945  *
946  * @enum {number}
947  */
948 i18n.phonenumbers.PhoneNumberUtil.ValidationResult = {
949   IS_POSSIBLE: 0,
950   INVALID_COUNTRY_CODE: 1,
951   TOO_SHORT: 2,
952   TOO_LONG: 3
953 };
954
955
956 /**
957  * Attempts to extract a possible number from the string passed in. This
958  * currently strips all leading characters that cannot be used to start a phone
959  * number. Characters that can be used to start a phone number are defined in
960  * the VALID_START_CHAR_PATTERN. If none of these characters are found in the
961  * number passed in, an empty string is returned. This function also attempts to
962  * strip off any alternative extensions or endings if two or more are present,
963  * such as in the case of: (530) 583-6985 x302/x2303. The second extension here
964  * makes this actually two phone numbers, (530) 583-6985 x302 and (530) 583-6985
965  * x2303. We remove the second extension so that the first number is parsed
966  * correctly.
967  *
968  * @param {string} number the string that might contain a phone number.
969  * @return {string} the number, stripped of any non-phone-number prefix (such as
970  *     'Tel:') or an empty string if no character used to start phone numbers
971  *     (such as + or any digit) is found in the number.
972  */
973 i18n.phonenumbers.PhoneNumberUtil.extractPossibleNumber = function(number) {
974   /** @type {string} */
975   var possibleNumber;
976
977   /** @type {number} */
978   var start = number
979       .search(i18n.phonenumbers.PhoneNumberUtil.VALID_START_CHAR_PATTERN_);
980   if (start >= 0) {
981     possibleNumber = number.substring(start);
982     // Remove trailing non-alpha non-numerical characters.
983     possibleNumber = possibleNumber.replace(
984         i18n.phonenumbers.PhoneNumberUtil.UNWANTED_END_CHAR_PATTERN_, '');
985
986     // Check for extra numbers at the end.
987     /** @type {number} */
988     var secondNumberStart = possibleNumber
989         .search(i18n.phonenumbers.PhoneNumberUtil.SECOND_NUMBER_START_PATTERN_);
990     if (secondNumberStart >= 0) {
991       possibleNumber = possibleNumber.substring(0, secondNumberStart);
992     }
993   } else {
994     possibleNumber = '';
995   }
996   return possibleNumber;
997 };
998
999
1000 /**
1001  * Checks to see if the string of characters could possibly be a phone number at
1002  * all. At the moment, checks to see that the string begins with at least 2
1003  * digits, ignoring any punctuation commonly found in phone numbers. This method
1004  * does not require the number to be normalized in advance - but does assume
1005  * that leading non-number symbols have been removed, such as by the method
1006  * extractPossibleNumber.
1007  *
1008  * @param {string} number string to be checked for viability as a phone number.
1009  * @return {boolean} true if the number could be a phone number of some sort,
1010  *     otherwise false.
1011  */
1012 i18n.phonenumbers.PhoneNumberUtil.isViablePhoneNumber = function(number) {
1013   if (number.length < i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_) {
1014     return false;
1015   }
1016   return i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
1017       i18n.phonenumbers.PhoneNumberUtil.VALID_PHONE_NUMBER_PATTERN_, number);
1018 };
1019
1020
1021 /**
1022  * Normalizes a string of characters representing a phone number. This performs
1023  * the following conversions:
1024  *   Punctuation is stripped.
1025  *   For ALPHA/VANITY numbers:
1026  *   Letters are converted to their numeric representation on a telephone
1027  *       keypad. The keypad used here is the one defined in ITU Recommendation
1028  *       E.161. This is only done if there are 3 or more letters in the number,
1029  *       to lessen the risk that such letters are typos.
1030  *   For other numbers:
1031  *   Wide-ascii digits are converted to normal ASCII (European) digits.
1032  *   Arabic-Indic numerals are converted to European numerals.
1033  *   Spurious alpha characters are stripped.
1034  *
1035  * @param {string} number a string of characters representing a phone number.
1036  * @return {string} the normalized string version of the phone number.
1037  */
1038 i18n.phonenumbers.PhoneNumberUtil.normalize = function(number) {
1039   if (i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
1040       i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_PHONE_PATTERN_, number)) {
1041     return i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(number,
1042         i18n.phonenumbers.PhoneNumberUtil.ALL_NORMALIZATION_MAPPINGS_, true);
1043   } else {
1044     return i18n.phonenumbers.PhoneNumberUtil.normalizeDigitsOnly(number);
1045   }
1046 };
1047
1048
1049 /**
1050  * Normalizes a string of characters representing a phone number. This is a
1051  * wrapper for normalize(String number) but does in-place normalization of the
1052  * StringBuffer provided.
1053  *
1054  * @param {!goog.string.StringBuffer} number a StringBuffer of characters
1055  *     representing a phone number that will be normalized in place.
1056  * @private
1057  */
1058 i18n.phonenumbers.PhoneNumberUtil.normalizeSB_ = function(number) {
1059   /** @type {string} */
1060   var normalizedNumber = i18n.phonenumbers.PhoneNumberUtil.normalize(number
1061       .toString());
1062   number.clear();
1063   number.append(normalizedNumber);
1064 };
1065
1066
1067 /**
1068  * Normalizes a string of characters representing a phone number. This converts
1069  * wide-ascii and arabic-indic numerals to European numerals, and strips
1070  * punctuation and alpha characters.
1071  *
1072  * @param {string} number a string of characters representing a phone number.
1073  * @return {string} the normalized string version of the phone number.
1074  */
1075 i18n.phonenumbers.PhoneNumberUtil.normalizeDigitsOnly = function(number) {
1076   return i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(number,
1077       i18n.phonenumbers.PhoneNumberUtil.DIGIT_MAPPINGS, true);
1078 };
1079
1080
1081 /**
1082  * Converts all alpha characters in a number to their respective digits on a
1083  * keypad, but retains existing formatting. Also converts wide-ascii digits to
1084  * normal ascii digits, and converts Arabic-Indic numerals to European numerals.
1085  *
1086  * @param {string} number a string of characters representing a phone number.
1087  * @return {string} the normalized string version of the phone number.
1088  */
1089 i18n.phonenumbers.PhoneNumberUtil.convertAlphaCharactersInNumber =
1090     function(number) {
1091
1092   return i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(number,
1093       i18n.phonenumbers.PhoneNumberUtil.ALL_NORMALIZATION_MAPPINGS_, false);
1094 };
1095
1096
1097 /**
1098  * Gets the length of the geographical area code from the
1099  * {@code national_number} field of the PhoneNumber object passed in, so that
1100  * clients could use it to split a national significant number into geographical
1101  * area code and subscriber number. It works in such a way that the resultant
1102  * subscriber number should be diallable, at least on some devices. An example
1103  * of how this could be used:
1104  *
1105  * <pre>
1106  * var phoneUtil = i18n.phonenumbers.PhoneNumberUtil.getInstance();
1107  * var number = phoneUtil.parse('16502530000', 'US');
1108  * var nationalSignificantNumber =
1109  *     phoneUtil.getNationalSignificantNumber(number);
1110  * var areaCode;
1111  * var subscriberNumber;
1112  *
1113  * var areaCodeLength = phoneUtil.getLengthOfGeographicalAreaCode(number);
1114  * if (areaCodeLength > 0) {
1115  *   areaCode = nationalSignificantNumber.substring(0, areaCodeLength);
1116  *   subscriberNumber = nationalSignificantNumber.substring(areaCodeLength);
1117  * } else {
1118  *   areaCode = '';
1119  *   subscriberNumber = nationalSignificantNumber;
1120  * }
1121  * </pre>
1122  *
1123  * N.B.: area code is a very ambiguous concept, so the I18N team generally
1124  * recommends against using it for most purposes, but recommends using the more
1125  * general {@code national_number} instead. Read the following carefully before
1126  * deciding to use this method:
1127  * <ul>
1128  *  <li> geographical area codes change over time, and this method honors those
1129  *    changes; therefore, it doesn't guarantee the stability of the result it
1130  *    produces.
1131  *  <li> subscriber numbers may not be diallable from all devices (notably
1132  *    mobile devices, which typically requires the full national_number to be
1133  *    dialled in most regions).
1134  *  <li> most non-geographical numbers have no area codes, including numbers
1135  *    from non-geographical entities.
1136  *  <li> some geographical numbers have no area codes.
1137  * </ul>
1138  *
1139  * @param {i18n.phonenumbers.PhoneNumber} number the PhoneNumber object for
1140  *     which clients want to know the length of the area code.
1141  * @return {number} the length of area code of the PhoneNumber object passed in.
1142  */
1143 i18n.phonenumbers.PhoneNumberUtil.prototype.getLengthOfGeographicalAreaCode =
1144     function(number) {
1145   /** @type {i18n.phonenumbers.PhoneMetadata} */
1146   var metadata = this.getMetadataForRegion(this.getRegionCodeForNumber(number));
1147   if (metadata == null) {
1148     return 0;
1149   }
1150   // If a country doesn't use a national prefix, and this number doesn't have
1151   // an Italian leading zero, we assume it is a closed dialling plan with no
1152   // area codes.
1153   if (!metadata.hasNationalPrefix() && !number.hasItalianLeadingZero()) {
1154     return 0;
1155   }
1156
1157   if (!this.isNumberGeographical(number)) {
1158     return 0;
1159   }
1160
1161   return this.getLengthOfNationalDestinationCode(number);
1162 };
1163
1164
1165 /**
1166  * Gets the length of the national destination code (NDC) from the PhoneNumber
1167  * object passed in, so that clients could use it to split a national
1168  * significant number into NDC and subscriber number. The NDC of a phone number
1169  * is normally the first group of digit(s) right after the country calling code
1170  * when the number is formatted in the international format, if there is a
1171  * subscriber number part that follows. An example of how this could be used:
1172  *
1173  * <pre>
1174  * var phoneUtil = i18n.phonenumbers.PhoneNumberUtil.getInstance();
1175  * var number = phoneUtil.parse('18002530000', 'US');
1176  * var nationalSignificantNumber =
1177  *     phoneUtil.getNationalSignificantNumber(number);
1178  * var nationalDestinationCode;
1179  * var subscriberNumber;
1180  *
1181  * var nationalDestinationCodeLength =
1182  *     phoneUtil.getLengthOfNationalDestinationCode(number);
1183  * if (nationalDestinationCodeLength > 0) {
1184  *   nationalDestinationCode =
1185  *       nationalSignificantNumber.substring(0, nationalDestinationCodeLength);
1186  *   subscriberNumber =
1187  *       nationalSignificantNumber.substring(nationalDestinationCodeLength);
1188  * } else {
1189  *   nationalDestinationCode = '';
1190  *   subscriberNumber = nationalSignificantNumber;
1191  * }
1192  * </pre>
1193  *
1194  * Refer to the unittests to see the difference between this function and
1195  * {@link #getLengthOfGeographicalAreaCode}.
1196  *
1197  * @param {i18n.phonenumbers.PhoneNumber} number the PhoneNumber object for
1198  *     which clients want to know the length of the NDC.
1199  * @return {number} the length of NDC of the PhoneNumber object passed in.
1200  */
1201 i18n.phonenumbers.PhoneNumberUtil.prototype.getLengthOfNationalDestinationCode =
1202     function(number) {
1203
1204   /** @type {i18n.phonenumbers.PhoneNumber} */
1205   var copiedProto;
1206   if (number.hasExtension()) {
1207     // We don't want to alter the proto given to us, but we don't want to
1208     // include the extension when we format it, so we copy it and clear the
1209     // extension here.
1210     copiedProto = number.clone();
1211     copiedProto.clearExtension();
1212   } else {
1213     copiedProto = number;
1214   }
1215
1216   /** @type {string} */
1217   var nationalSignificantNumber = this.format(copiedProto,
1218       i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL);
1219   /** @type {!Array.<string>} */
1220   var numberGroups = nationalSignificantNumber.split(
1221       i18n.phonenumbers.PhoneNumberUtil.NON_DIGITS_PATTERN_);
1222   // The pattern will start with '+COUNTRY_CODE ' so the first group will always
1223   // be the empty string (before the + symbol) and the second group will be the
1224   // country calling code. The third group will be area code if it is not the
1225   // last group.
1226   // NOTE: On IE the first group that is supposed to be the empty string does
1227   // not appear in the array of number groups... so make the result on non-IE
1228   // browsers to be that of IE.
1229   if (numberGroups[0].length == 0) {
1230     numberGroups.shift();
1231   }
1232   if (numberGroups.length <= 2) {
1233     return 0;
1234   }
1235
1236   if (this.getNumberType(number) == i18n.phonenumbers.PhoneNumberType.MOBILE) {
1237     // For example Argentinian mobile numbers, when formatted in the
1238     // international format, are in the form of +54 9 NDC XXXX.... As a result,
1239     // we take the length of the third group (NDC) and add the length of the
1240     // mobile token, which also forms part of the national significant number.
1241     // This assumes that the mobile token is always formatted separately from
1242     // the rest of the phone number.
1243     /** @type {string} */
1244     var mobileToken = i18n.phonenumbers.PhoneNumberUtil.getCountryMobileToken(
1245         number.getCountryCodeOrDefault());
1246     if (mobileToken != '') {
1247       return numberGroups[2].length + mobileToken.length;
1248     }
1249   }
1250   return numberGroups[1].length;
1251 };
1252
1253
1254 /**
1255  * Returns the mobile token for the provided country calling code if it has
1256  * one, otherwise returns an empty string. A mobile token is a number inserted
1257  * before the area code when dialing a mobile number from that country from
1258  * abroad.
1259  *
1260  * @param {number} countryCallingCode the country calling code for which we
1261  *     want the mobile token.
1262  * @return {string} the mobile token for the given country calling code.
1263  */
1264 i18n.phonenumbers.PhoneNumberUtil.getCountryMobileToken =
1265     function(countryCallingCode) {
1266   return i18n.phonenumbers.PhoneNumberUtil.MOBILE_TOKEN_MAPPINGS_[
1267       countryCallingCode] || '';
1268 };
1269
1270
1271 /**
1272  * Convenience method to get a list of what regions the library has metadata
1273  * for.
1274  *
1275  * @return {!Array<string>} region codes supported by the library.
1276  */
1277 i18n.phonenumbers.PhoneNumberUtil.prototype.getSupportedRegions = function() {
1278   return goog.array.filter(
1279       Object.keys(i18n.phonenumbers.metadata.countryToMetadata),
1280       function(regionCode) {
1281         return isNaN(regionCode);
1282       });
1283 };
1284
1285
1286 /**
1287  * Convenience method to get a list of what global network calling codes the
1288  * library has metadata for.
1289  *
1290  * @return {!Array<number>} global network calling codes supported by the
1291  *     library.
1292  */
1293 i18n.phonenumbers.PhoneNumberUtil.prototype.
1294     getSupportedGlobalNetworkCallingCodes = function() {
1295   var callingCodesAsStrings = goog.array.filter(
1296       Object.keys(i18n.phonenumbers.metadata.countryToMetadata),
1297       function(regionCode) {
1298         return !isNaN(regionCode);
1299       });
1300   return goog.array.map(callingCodesAsStrings,
1301       function(callingCode) {
1302         return parseInt(callingCode, 10);
1303       });
1304 };
1305
1306
1307 /**
1308  * Normalizes a string of characters representing a phone number by replacing
1309  * all characters found in the accompanying map with the values therein, and
1310  * stripping all other characters if removeNonMatches is true.
1311  *
1312  * @param {string} number a string of characters representing a phone number.
1313  * @param {!Object.<string, string>} normalizationReplacements a mapping of
1314  *     characters to what they should be replaced by in the normalized version
1315  *     of the phone number.
1316  * @param {boolean} removeNonMatches indicates whether characters that are not
1317  *     able to be replaced should be stripped from the number. If this is false,
1318  *     they will be left unchanged in the number.
1319  * @return {string} the normalized string version of the phone number.
1320  * @private
1321  */
1322 i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_ =
1323     function(number, normalizationReplacements, removeNonMatches) {
1324
1325   /** @type {!goog.string.StringBuffer} */
1326   var normalizedNumber = new goog.string.StringBuffer();
1327   /** @type {string} */
1328   var character;
1329   /** @type {string} */
1330   var newDigit;
1331   /** @type {number} */
1332   var numberLength = number.length;
1333   for (var i = 0; i < numberLength; ++i) {
1334     character = number.charAt(i);
1335     newDigit = normalizationReplacements[character.toUpperCase()];
1336     if (newDigit != null) {
1337       normalizedNumber.append(newDigit);
1338     } else if (!removeNonMatches) {
1339       normalizedNumber.append(character);
1340     }
1341     // If neither of the above are true, we remove this character.
1342   }
1343   return normalizedNumber.toString();
1344 };
1345
1346
1347 /**
1348  * Helper function to check if the national prefix formatting rule has the first
1349  * group only, i.e., does not start with the national prefix.
1350  *
1351  * @param {string} nationalPrefixFormattingRule The formatting rule for the
1352  *     national prefix.
1353  * @return {boolean} true if the national prefix formatting rule has the first
1354  *     group only.
1355  */
1356 i18n.phonenumbers.PhoneNumberUtil.prototype.formattingRuleHasFirstGroupOnly =
1357     function(nationalPrefixFormattingRule) {
1358   return nationalPrefixFormattingRule.length == 0 ||
1359       i18n.phonenumbers.PhoneNumberUtil.FIRST_GROUP_ONLY_PREFIX_PATTERN_.
1360           test(nationalPrefixFormattingRule);
1361 };
1362
1363
1364 /**
1365  * Tests whether a phone number has a geographical association. It checks if
1366  * the number is associated to a certain region in the country where it belongs
1367  * to. Note that this doesn't verify if the number is actually in use.
1368  *
1369  * @param {i18n.phonenumbers.PhoneNumber} phoneNumber The phone number to test.
1370  * @return {boolean} true if the phone number has a geographical association.
1371  */
1372 i18n.phonenumbers.PhoneNumberUtil.prototype.isNumberGeographical =
1373     function(phoneNumber) {
1374   /** @type {i18n.phonenumbers.PhoneNumberType} */
1375   var numberType = this.getNumberType(phoneNumber);
1376   // TODO: Include mobile phone numbers from countries like Indonesia, which
1377   // has some mobile numbers that are geographical.
1378   return numberType == i18n.phonenumbers.PhoneNumberType.FIXED_LINE ||
1379       numberType == i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE;
1380 };
1381
1382
1383 /**
1384  * Helper function to check region code is not unknown or null.
1385  *
1386  * @param {?string} regionCode the ISO 3166-1 two-letter region code.
1387  * @return {boolean} true if region code is valid.
1388  * @private
1389  */
1390 i18n.phonenumbers.PhoneNumberUtil.prototype.isValidRegionCode_ =
1391     function(regionCode) {
1392
1393   // In Java we check whether the regionCode is contained in supportedRegions
1394   // that is built out of all the values of countryCallingCodeToRegionCodeMap
1395   // (countryCodeToRegionCodeMap in JS) minus REGION_CODE_FOR_NON_GEO_ENTITY.
1396   // In JS we check whether the regionCode is contained in the keys of
1397   // countryToMetadata but since for non-geographical country calling codes
1398   // (e.g. +800) we use the country calling codes instead of the region code as
1399   // key in the map we have to make sure regionCode is not a number to prevent
1400   // returning true for non-geographical country calling codes.
1401   return regionCode != null &&
1402       isNaN(regionCode) &&
1403       regionCode.toUpperCase() in i18n.phonenumbers.metadata.countryToMetadata;
1404 };
1405
1406
1407 /**
1408  * Helper function to check the country calling code is valid.
1409  *
1410  * @param {number} countryCallingCode the country calling code.
1411  * @return {boolean} true if country calling code code is valid.
1412  * @private
1413  */
1414 i18n.phonenumbers.PhoneNumberUtil.prototype.hasValidCountryCallingCode_ =
1415     function(countryCallingCode) {
1416
1417   return countryCallingCode in
1418       i18n.phonenumbers.metadata.countryCodeToRegionCodeMap;
1419 };
1420
1421
1422 /**
1423  * Formats a phone number in the specified format using default rules. Note that
1424  * this does not promise to produce a phone number that the user can dial from
1425  * where they are - although we do format in either 'national' or
1426  * 'international' format depending on what the client asks for, we do not
1427  * currently support a more abbreviated format, such as for users in the same
1428  * 'area' who could potentially dial the number without area code. Note that if
1429  * the phone number has a country calling code of 0 or an otherwise invalid
1430  * country calling code, we cannot work out which formatting rules to apply so
1431  * we return the national significant number with no formatting applied.
1432  *
1433  * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be
1434  *     formatted.
1435  * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
1436  *     phone number should be formatted into.
1437  * @return {string} the formatted phone number.
1438  */
1439 i18n.phonenumbers.PhoneNumberUtil.prototype.format =
1440     function(number, numberFormat) {
1441
1442   if (number.getNationalNumber() == 0 && number.hasRawInput()) {
1443     // Unparseable numbers that kept their raw input just use that.
1444     // This is the only case where a number can be formatted as E164 without a
1445     // leading '+' symbol (but the original number wasn't parseable anyway).
1446     // TODO: Consider removing the 'if' above so that unparseable strings
1447     // without raw input format to the empty string instead of "+00"
1448     /** @type {string} */
1449     var rawInput = number.getRawInputOrDefault();
1450     if (rawInput.length > 0) {
1451       return rawInput;
1452     }
1453   }
1454   /** @type {number} */
1455   var countryCallingCode = number.getCountryCodeOrDefault();
1456   /** @type {string} */
1457   var nationalSignificantNumber = this.getNationalSignificantNumber(number);
1458   if (numberFormat == i18n.phonenumbers.PhoneNumberFormat.E164) {
1459     // Early exit for E164 case (even if the country calling code is invalid)
1460     // since no formatting of the national number needs to be applied.
1461     // Extensions are not formatted.
1462     return this.prefixNumberWithCountryCallingCode_(
1463         countryCallingCode, i18n.phonenumbers.PhoneNumberFormat.E164,
1464         nationalSignificantNumber, '');
1465   }
1466   if (!this.hasValidCountryCallingCode_(countryCallingCode)) {
1467     return nationalSignificantNumber;
1468   }
1469   // Note getRegionCodeForCountryCode() is used because formatting information
1470   // for regions which share a country calling code is contained by only one
1471   // region for performance reasons. For example, for NANPA regions it will be
1472   // contained in the metadata for US.
1473   /** @type {string} */
1474   var regionCode = this.getRegionCodeForCountryCode(countryCallingCode);
1475
1476   // Metadata cannot be null because the country calling code is valid (which
1477   // means that the region code cannot be ZZ and must be one of our supported
1478   // region codes).
1479   /** @type {i18n.phonenumbers.PhoneMetadata} */
1480   var metadata =
1481       this.getMetadataForRegionOrCallingCode_(countryCallingCode, regionCode);
1482   /** @type {string} */
1483   var formattedExtension =
1484       this.maybeGetFormattedExtension_(number, metadata, numberFormat);
1485   /** @type {string} */
1486   var formattedNationalNumber =
1487       this.formatNsn_(nationalSignificantNumber, metadata, numberFormat);
1488   return this.prefixNumberWithCountryCallingCode_(countryCallingCode,
1489                                                   numberFormat,
1490                                                   formattedNationalNumber,
1491                                                   formattedExtension);
1492 };
1493
1494
1495 /**
1496  * Formats a phone number in the specified format using client-defined
1497  * formatting rules. Note that if the phone number has a country calling code of
1498  * zero or an otherwise invalid country calling code, we cannot work out things
1499  * like whether there should be a national prefix applied, or how to format
1500  * extensions, so we return the national significant number with no formatting
1501  * applied.
1502  *
1503  * @param {i18n.phonenumbers.PhoneNumber} number the phone  number to be
1504  *     formatted.
1505  * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
1506  *     phone number should be formatted into.
1507  * @param {Array.<i18n.phonenumbers.NumberFormat>} userDefinedFormats formatting
1508  *     rules specified by clients.
1509  * @return {string} the formatted phone number.
1510  */
1511 i18n.phonenumbers.PhoneNumberUtil.prototype.formatByPattern =
1512     function(number, numberFormat, userDefinedFormats) {
1513
1514   /** @type {number} */
1515   var countryCallingCode = number.getCountryCodeOrDefault();
1516   /** @type {string} */
1517   var nationalSignificantNumber = this.getNationalSignificantNumber(number);
1518   if (!this.hasValidCountryCallingCode_(countryCallingCode)) {
1519     return nationalSignificantNumber;
1520   }
1521   // Note getRegionCodeForCountryCode() is used because formatting information
1522   // for regions which share a country calling code is contained by only one
1523   // region for performance reasons. For example, for NANPA regions it will be
1524   // contained in the metadata for US.
1525   /** @type {string} */
1526   var regionCode = this.getRegionCodeForCountryCode(countryCallingCode);
1527   // Metadata cannot be null because the country calling code is valid
1528   /** @type {i18n.phonenumbers.PhoneMetadata} */
1529   var metadata =
1530       this.getMetadataForRegionOrCallingCode_(countryCallingCode, regionCode);
1531
1532   /** @type {string} */
1533   var formattedNumber = '';
1534
1535   /** @type {i18n.phonenumbers.NumberFormat} */
1536   var formattingPattern = this.chooseFormattingPatternForNumber_(
1537       userDefinedFormats, nationalSignificantNumber);
1538   if (formattingPattern == null) {
1539     // If no pattern above is matched, we format the number as a whole.
1540     formattedNumber = nationalSignificantNumber;
1541   } else {
1542     // Before we do a replacement of the national prefix pattern $NP with the
1543     // national prefix, we need to copy the rule so that subsequent replacements
1544     // for different numbers have the appropriate national prefix.
1545     /** @type {i18n.phonenumbers.NumberFormat} */
1546     var numFormatCopy = formattingPattern.clone();
1547     /** @type {string} */
1548     var nationalPrefixFormattingRule =
1549         formattingPattern.getNationalPrefixFormattingRuleOrDefault();
1550     if (nationalPrefixFormattingRule.length > 0) {
1551       /** @type {string} */
1552       var nationalPrefix = metadata.getNationalPrefixOrDefault();
1553       if (nationalPrefix.length > 0) {
1554         // Replace $NP with national prefix and $FG with the first group ($1).
1555         nationalPrefixFormattingRule = nationalPrefixFormattingRule
1556             .replace(i18n.phonenumbers.PhoneNumberUtil.NP_PATTERN_,
1557                      nationalPrefix)
1558             .replace(i18n.phonenumbers.PhoneNumberUtil.FG_PATTERN_, '$1');
1559         numFormatCopy.setNationalPrefixFormattingRule(
1560             nationalPrefixFormattingRule);
1561       } else {
1562         // We don't want to have a rule for how to format the national prefix if
1563         // there isn't one.
1564         numFormatCopy.clearNationalPrefixFormattingRule();
1565       }
1566     }
1567     formattedNumber = this.formatNsnUsingPattern_(
1568         nationalSignificantNumber, numFormatCopy, numberFormat);
1569   }
1570
1571   /** @type {string} */
1572   var formattedExtension =
1573       this.maybeGetFormattedExtension_(number, metadata, numberFormat);
1574   return this.prefixNumberWithCountryCallingCode_(countryCallingCode,
1575                                                   numberFormat,
1576                                                   formattedNumber,
1577                                                   formattedExtension);
1578 };
1579
1580
1581 /**
1582  * Formats a phone number in national format for dialing using the carrier as
1583  * specified in the {@code carrierCode}. The {@code carrierCode} will always be
1584  * used regardless of whether the phone number already has a preferred domestic
1585  * carrier code stored. If {@code carrierCode} contains an empty string, returns
1586  * the number in national format without any carrier code.
1587  *
1588  * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be
1589  *     formatted.
1590  * @param {string} carrierCode the carrier selection code to be used.
1591  * @return {string} the formatted phone number in national format for dialing
1592  *     using the carrier as specified in the {@code carrierCode}.
1593  */
1594 i18n.phonenumbers.PhoneNumberUtil.prototype.
1595     formatNationalNumberWithCarrierCode = function(number, carrierCode) {
1596
1597   /** @type {number} */
1598   var countryCallingCode = number.getCountryCodeOrDefault();
1599   /** @type {string} */
1600   var nationalSignificantNumber = this.getNationalSignificantNumber(number);
1601   if (!this.hasValidCountryCallingCode_(countryCallingCode)) {
1602     return nationalSignificantNumber;
1603   }
1604
1605   // Note getRegionCodeForCountryCode() is used because formatting information
1606   // for regions which share a country calling code is contained by only one
1607   // region for performance reasons. For example, for NANPA regions it will be
1608   // contained in the metadata for US.
1609   /** @type {string} */
1610   var regionCode = this.getRegionCodeForCountryCode(countryCallingCode);
1611   // Metadata cannot be null because the country calling code is valid.
1612   /** @type {i18n.phonenumbers.PhoneMetadata} */
1613   var metadata =
1614       this.getMetadataForRegionOrCallingCode_(countryCallingCode, regionCode);
1615   /** @type {string} */
1616   var formattedExtension = this.maybeGetFormattedExtension_(
1617       number, metadata, i18n.phonenumbers.PhoneNumberFormat.NATIONAL);
1618   /** @type {string} */
1619   var formattedNationalNumber = this.formatNsn_(
1620       nationalSignificantNumber, metadata,
1621       i18n.phonenumbers.PhoneNumberFormat.NATIONAL, carrierCode);
1622   return this.prefixNumberWithCountryCallingCode_(
1623       countryCallingCode, i18n.phonenumbers.PhoneNumberFormat.NATIONAL,
1624       formattedNationalNumber, formattedExtension);
1625 };
1626
1627
1628 /**
1629  * @param {number} countryCallingCode
1630  * @param {?string} regionCode
1631  * @return {i18n.phonenumbers.PhoneMetadata}
1632  * @private
1633  */
1634 i18n.phonenumbers.PhoneNumberUtil.prototype.getMetadataForRegionOrCallingCode_ =
1635     function(countryCallingCode, regionCode) {
1636   return i18n.phonenumbers.PhoneNumberUtil.REGION_CODE_FOR_NON_GEO_ENTITY ==
1637       regionCode ?
1638       this.getMetadataForNonGeographicalRegion(countryCallingCode) :
1639       this.getMetadataForRegion(regionCode);
1640 };
1641
1642
1643 /**
1644  * Formats a phone number in national format for dialing using the carrier as
1645  * specified in the preferred_domestic_carrier_code field of the PhoneNumber
1646  * object passed in. If that is missing, use the {@code fallbackCarrierCode}
1647  * passed in instead. If there is no {@code preferred_domestic_carrier_code},
1648  * and the {@code fallbackCarrierCode} contains an empty string, return the
1649  * number in national format without any carrier code.
1650  *
1651  * <p>Use {@link #formatNationalNumberWithCarrierCode} instead if the carrier
1652  * code passed in should take precedence over the number's
1653  * {@code preferred_domestic_carrier_code} when formatting.
1654  *
1655  * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be
1656  *     formatted.
1657  * @param {string} fallbackCarrierCode the carrier selection code to be used, if
1658  *     none is found in the phone number itself.
1659  * @return {string} the formatted phone number in national format for dialing
1660  *     using the number's preferred_domestic_carrier_code, or the
1661  *     {@code fallbackCarrierCode} passed in if none is found.
1662  */
1663 i18n.phonenumbers.PhoneNumberUtil.prototype.
1664     formatNationalNumberWithPreferredCarrierCode = function(
1665         number, fallbackCarrierCode) {
1666   return this.formatNationalNumberWithCarrierCode(
1667       number,
1668       number.hasPreferredDomesticCarrierCode() ?
1669           number.getPreferredDomesticCarrierCodeOrDefault() :
1670           fallbackCarrierCode);
1671 };
1672
1673
1674 /**
1675  * Returns a number formatted in such a way that it can be dialed from a mobile
1676  * phone in a specific region. If the number cannot be reached from the region
1677  * (e.g. some countries block toll-free numbers from being called outside of the
1678  * country), the method returns an empty string.
1679  *
1680  * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be
1681  *     formatted.
1682  * @param {string} regionCallingFrom the region where the call is being placed.
1683  * @param {boolean} withFormatting whether the number should be returned with
1684  *     formatting symbols, such as spaces and dashes.
1685  * @return {string} the formatted phone number.
1686  */
1687 i18n.phonenumbers.PhoneNumberUtil.prototype.formatNumberForMobileDialing =
1688     function(number, regionCallingFrom, withFormatting) {
1689
1690   /** @type {number} */
1691   var countryCallingCode = number.getCountryCodeOrDefault();
1692   if (!this.hasValidCountryCallingCode_(countryCallingCode)) {
1693     return number.hasRawInput() ? number.getRawInputOrDefault() : '';
1694   }
1695
1696   /** @type {string} */
1697   var formattedNumber = '';
1698   // Clear the extension, as that part cannot normally be dialed together with
1699   // the main number.
1700   /** @type {i18n.phonenumbers.PhoneNumber} */
1701   var numberNoExt = number.clone();
1702   numberNoExt.clearExtension();
1703   /** @type {string} */
1704   var regionCode = this.getRegionCodeForCountryCode(countryCallingCode);
1705   /** @type {i18n.phonenumbers.PhoneNumberType} */
1706   var numberType = this.getNumberType(numberNoExt);
1707   /** @type {boolean} */
1708   var isValidNumber = (numberType != i18n.phonenumbers.PhoneNumberType.UNKNOWN);
1709   if (regionCallingFrom == regionCode) {
1710     /** @type {boolean} */
1711     var isFixedLineOrMobile =
1712         (numberType == i18n.phonenumbers.PhoneNumberType.FIXED_LINE) ||
1713         (numberType == i18n.phonenumbers.PhoneNumberType.MOBILE) ||
1714         (numberType == i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE);
1715     // Carrier codes may be needed in some countries. We handle this here.
1716     if (regionCode == 'CO' &&
1717         numberType == i18n.phonenumbers.PhoneNumberType.FIXED_LINE) {
1718       formattedNumber = this.formatNationalNumberWithCarrierCode(
1719           numberNoExt,
1720           i18n.phonenumbers.PhoneNumberUtil
1721               .COLOMBIA_MOBILE_TO_FIXED_LINE_PREFIX_);
1722     } else if (regionCode == 'BR' && isFixedLineOrMobile) {
1723       formattedNumber = numberNoExt.hasPreferredDomesticCarrierCode() ?
1724           this.formatNationalNumberWithPreferredCarrierCode(numberNoExt, '') :
1725           // Brazilian fixed line and mobile numbers need to be dialed with a
1726           // carrier code when called within Brazil. Without that, most of the
1727           // carriers won't connect the call. Because of that, we return an
1728           // empty string here.
1729           '';
1730     } else if (isValidNumber && regionCode == 'HU') {
1731       // The national format for HU numbers doesn't contain the national prefix,
1732       // because that is how numbers are normally written down. However, the
1733       // national prefix is obligatory when dialing from a mobile phone. As a
1734       // result, we add it back here if it is a valid regular length phone
1735       // number.
1736       formattedNumber =
1737           this.getNddPrefixForRegion(regionCode, true /* strip non-digits */) +
1738           ' ' + this.format(numberNoExt,
1739               i18n.phonenumbers.PhoneNumberFormat.NATIONAL);
1740     } else if (countryCallingCode ==
1741                i18n.phonenumbers.PhoneNumberUtil.NANPA_COUNTRY_CODE_) {
1742       // For NANPA countries, we output international format for numbers that
1743       // can be dialed internationally, since that always works, except for
1744       // numbers which might potentially be short numbers, which are always
1745       // dialled in national format.
1746       /** @type {i18n.phonenumbers.PhoneMetadata} */
1747       var regionMetadata = this.getMetadataForRegion(regionCallingFrom);
1748       if (this.canBeInternationallyDialled(numberNoExt) &&
1749           !this.isShorterThanPossibleNormalNumber_(
1750               regionMetadata, this.getNationalSignificantNumber(numberNoExt))) {
1751         formattedNumber = this.format(
1752             numberNoExt, i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL);
1753       } else {
1754         formattedNumber = this.format(
1755             numberNoExt, i18n.phonenumbers.PhoneNumberFormat.NATIONAL);
1756       }
1757     } else {
1758       // For non-geographical countries, Mexican and Chilean fixed line and
1759       // mobile numbers, we output international format for numbers that can be
1760       // dialed internationally, as that always works.
1761       if ((regionCode ==
1762            i18n.phonenumbers.PhoneNumberUtil.REGION_CODE_FOR_NON_GEO_ENTITY ||
1763           // MX fixed line and mobile numbers should always be formatted in
1764           // international format, even when dialed within MX. For national
1765           // format to work, a carrier code needs to be used, and the correct
1766           // carrier code depends on if the caller and callee are from the
1767           // same local area. It is trickier to get that to work correctly than
1768           // using international format, which is tested to work fine on all
1769           // carriers.
1770           // CL fixed line numbers need the national prefix when dialing in the
1771           // national format, but don't have it when used for display. The
1772           // reverse is true for mobile numbers. As a result, we output them in
1773           // the international format to make it work.
1774           ((regionCode == 'MX' || regionCode == 'CL') &&
1775               isFixedLineOrMobile)) &&
1776           this.canBeInternationallyDialled(numberNoExt)) {
1777         formattedNumber = this.format(
1778             numberNoExt, i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL);
1779       } else {
1780         formattedNumber = this.format(
1781             numberNoExt, i18n.phonenumbers.PhoneNumberFormat.NATIONAL);
1782       }
1783     }
1784   } else if (isValidNumber && this.canBeInternationallyDialled(numberNoExt)) {
1785     // We assume that short numbers are not diallable from outside their region,
1786     // so if a number is not a valid regular length phone number, we treat it as
1787     // if it cannot be internationally dialled.
1788     return withFormatting ?
1789         this.format(numberNoExt,
1790                     i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL) :
1791         this.format(numberNoExt, i18n.phonenumbers.PhoneNumberFormat.E164);
1792   }
1793   return withFormatting ?
1794       formattedNumber :
1795       i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(formattedNumber,
1796           i18n.phonenumbers.PhoneNumberUtil.DIALLABLE_CHAR_MAPPINGS_, true);
1797 };
1798
1799
1800 /**
1801  * Formats a phone number for out-of-country dialing purposes. If no
1802  * regionCallingFrom is supplied, we format the number in its INTERNATIONAL
1803  * format. If the country calling code is the same as that of the region where
1804  * the number is from, then NATIONAL formatting will be applied.
1805  *
1806  * <p>If the number itself has a country calling code of zero or an otherwise
1807  * invalid country calling code, then we return the number with no formatting
1808  * applied.
1809  *
1810  * <p>Note this function takes care of the case for calling inside of NANPA and
1811  * between Russia and Kazakhstan (who share the same country calling code). In
1812  * those cases, no international prefix is used. For regions which have multiple
1813  * international prefixes, the number in its INTERNATIONAL format will be
1814  * returned instead.
1815  *
1816  * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be
1817  *     formatted.
1818  * @param {string} regionCallingFrom the region where the call is being placed.
1819  * @return {string} the formatted phone number.
1820  */
1821 i18n.phonenumbers.PhoneNumberUtil.prototype.formatOutOfCountryCallingNumber =
1822     function(number, regionCallingFrom) {
1823
1824   if (!this.isValidRegionCode_(regionCallingFrom)) {
1825     return this.format(number,
1826                        i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL);
1827   }
1828   /** @type {number} */
1829   var countryCallingCode = number.getCountryCodeOrDefault();
1830   /** @type {string} */
1831   var nationalSignificantNumber = this.getNationalSignificantNumber(number);
1832   if (!this.hasValidCountryCallingCode_(countryCallingCode)) {
1833     return nationalSignificantNumber;
1834   }
1835   if (countryCallingCode ==
1836           i18n.phonenumbers.PhoneNumberUtil.NANPA_COUNTRY_CODE_) {
1837     if (this.isNANPACountry(regionCallingFrom)) {
1838       // For NANPA regions, return the national format for these regions but
1839       // prefix it with the country calling code.
1840       return countryCallingCode + ' ' +
1841           this.format(number, i18n.phonenumbers.PhoneNumberFormat.NATIONAL);
1842     }
1843   } else if (countryCallingCode ==
1844                  this.getCountryCodeForValidRegion_(regionCallingFrom)) {
1845     // If regions share a country calling code, the country calling code need
1846     // not be dialled. This also applies when dialling within a region, so this
1847     // if clause covers both these cases. Technically this is the case for
1848     // dialling from La Reunion to other overseas departments of France (French
1849     // Guiana, Martinique, Guadeloupe), but not vice versa - so we don't cover
1850     // this edge case for now and for those cases return the version including
1851     // country calling code. Details here:
1852     // http://www.petitfute.com/voyage/225-info-pratiques-reunion
1853     return this.format(number,
1854                        i18n.phonenumbers.PhoneNumberFormat.NATIONAL);
1855   }
1856   // Metadata cannot be null because we checked 'isValidRegionCode()' above.
1857   /** @type {i18n.phonenumbers.PhoneMetadata} */
1858   var metadataForRegionCallingFrom =
1859       this.getMetadataForRegion(regionCallingFrom);
1860   /** @type {string} */
1861   var internationalPrefix =
1862       metadataForRegionCallingFrom.getInternationalPrefixOrDefault();
1863
1864   // For regions that have multiple international prefixes, the international
1865   // format of the number is returned, unless there is a preferred international
1866   // prefix.
1867   /** @type {string} */
1868   var internationalPrefixForFormatting = '';
1869   if (i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
1870       i18n.phonenumbers.PhoneNumberUtil.UNIQUE_INTERNATIONAL_PREFIX_,
1871       internationalPrefix)) {
1872     internationalPrefixForFormatting = internationalPrefix;
1873   } else if (metadataForRegionCallingFrom.hasPreferredInternationalPrefix()) {
1874     internationalPrefixForFormatting =
1875         metadataForRegionCallingFrom.getPreferredInternationalPrefixOrDefault();
1876   }
1877
1878   /** @type {string} */
1879   var regionCode = this.getRegionCodeForCountryCode(countryCallingCode);
1880   // Metadata cannot be null because the country calling code is valid.
1881   /** @type {i18n.phonenumbers.PhoneMetadata} */
1882   var metadataForRegion =
1883       this.getMetadataForRegionOrCallingCode_(countryCallingCode, regionCode);
1884   /** @type {string} */
1885   var formattedNationalNumber = this.formatNsn_(
1886       nationalSignificantNumber, metadataForRegion,
1887       i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL);
1888   /** @type {string} */
1889   var formattedExtension = this.maybeGetFormattedExtension_(number,
1890       metadataForRegion, i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL);
1891   return internationalPrefixForFormatting.length > 0 ?
1892       internationalPrefixForFormatting + ' ' + countryCallingCode + ' ' +
1893           formattedNationalNumber + formattedExtension :
1894       this.prefixNumberWithCountryCallingCode_(
1895           countryCallingCode, i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL,
1896           formattedNationalNumber, formattedExtension);
1897 };
1898
1899
1900 /**
1901  * Formats a phone number using the original phone number format that the number
1902  * is parsed from. The original format is embedded in the country_code_source
1903  * field of the PhoneNumber object passed in. If such information is missing,
1904  * the number will be formatted into the NATIONAL format by default. When the
1905  * number contains a leading zero and this is unexpected for this country, or we
1906  * don't have a formatting pattern for the number, the method returns the raw
1907  * input when it is available.
1908  *
1909  * Note this method guarantees no digit will be inserted, removed or modified as
1910  * a result of formatting.
1911  *
1912  * @param {i18n.phonenumbers.PhoneNumber} number the phone number that needs to
1913  *     be formatted in its original number format.
1914  * @param {string} regionCallingFrom the region whose IDD needs to be prefixed
1915  *     if the original number has one.
1916  * @return {string} the formatted phone number in its original number format.
1917  */
1918 i18n.phonenumbers.PhoneNumberUtil.prototype.formatInOriginalFormat =
1919     function(number, regionCallingFrom) {
1920
1921   if (number.hasRawInput() &&
1922       (this.hasUnexpectedItalianLeadingZero_(number) ||
1923        !this.hasFormattingPatternForNumber_(number))) {
1924     // We check if we have the formatting pattern because without that, we might
1925     // format the number as a group without national prefix.
1926     return number.getRawInputOrDefault();
1927   }
1928   if (!number.hasCountryCodeSource()) {
1929     return this.format(number, i18n.phonenumbers.PhoneNumberFormat.NATIONAL);
1930   }
1931   /** @type {string} */
1932   var formattedNumber;
1933   switch (number.getCountryCodeSource()) {
1934     case i18n.phonenumbers.PhoneNumber.CountryCodeSource
1935         .FROM_NUMBER_WITH_PLUS_SIGN:
1936       formattedNumber = this.format(number,
1937           i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL);
1938       break;
1939     case i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_IDD:
1940       formattedNumber =
1941           this.formatOutOfCountryCallingNumber(number, regionCallingFrom);
1942       break;
1943     case i18n.phonenumbers.PhoneNumber.CountryCodeSource
1944         .FROM_NUMBER_WITHOUT_PLUS_SIGN:
1945       formattedNumber = this.format(number,
1946           i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL).substring(1);
1947       break;
1948     case i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_DEFAULT_COUNTRY:
1949       // Fall-through to default case.
1950     default:
1951       /** @type {string} */
1952       var regionCode =
1953           this.getRegionCodeForCountryCode(number.getCountryCodeOrDefault());
1954       // We strip non-digits from the NDD here, and from the raw input later,
1955       // so that we can compare them easily.
1956       /** @type {?string} */
1957       var nationalPrefix = this.getNddPrefixForRegion(regionCode, true);
1958       /** @type {string} */
1959       var nationalFormat =
1960           this.format(number, i18n.phonenumbers.PhoneNumberFormat.NATIONAL);
1961       if (nationalPrefix == null || nationalPrefix.length == 0) {
1962         // If the region doesn't have a national prefix at all, we can safely
1963         // return the national format without worrying about a national prefix
1964         // being added.
1965         formattedNumber = nationalFormat;
1966         break;
1967       }
1968       // Otherwise, we check if the original number was entered with a national
1969       // prefix.
1970       if (this.rawInputContainsNationalPrefix_(
1971           number.getRawInputOrDefault(), nationalPrefix, regionCode)) {
1972         // If so, we can safely return the national format.
1973         formattedNumber = nationalFormat;
1974         break;
1975       }
1976       // Metadata cannot be null here because getNddPrefixForRegion() (above)
1977       // returns null if there is no metadata for the region.
1978       /** @type {i18n.phonenumbers.PhoneMetadata} */
1979       var metadata = this.getMetadataForRegion(regionCode);
1980       /** @type {string} */
1981       var nationalNumber = this.getNationalSignificantNumber(number);
1982       /** @type {i18n.phonenumbers.NumberFormat} */
1983       var formatRule = this.chooseFormattingPatternForNumber_(
1984           metadata.numberFormatArray(), nationalNumber);
1985       // The format rule could still be null here if the national number was 0
1986       // and there was no raw input (this should not be possible for numbers
1987       // generated by the phonenumber library as they would also not have a
1988       // country calling code and we would have exited earlier).
1989       if (formatRule == null) {
1990         formattedNumber = nationalFormat;
1991         break;
1992       }
1993       // When the format we apply to this number doesn't contain national
1994       // prefix, we can just return the national format.
1995       // TODO: Refactor the code below with the code in
1996       // isNationalPrefixPresentIfRequired.
1997       /** @type {string} */
1998       var candidateNationalPrefixRule =
1999           formatRule.getNationalPrefixFormattingRuleOrDefault();
2000       // We assume that the first-group symbol will never be _before_ the
2001       // national prefix.
2002       /** @type {number} */
2003       var indexOfFirstGroup = candidateNationalPrefixRule.indexOf('$1');
2004       if (indexOfFirstGroup <= 0) {
2005         formattedNumber = nationalFormat;
2006         break;
2007       }
2008       candidateNationalPrefixRule =
2009           candidateNationalPrefixRule.substring(0, indexOfFirstGroup);
2010       candidateNationalPrefixRule = i18n.phonenumbers.PhoneNumberUtil
2011           .normalizeDigitsOnly(candidateNationalPrefixRule);
2012       if (candidateNationalPrefixRule.length == 0) {
2013         // National prefix not used when formatting this number.
2014         formattedNumber = nationalFormat;
2015         break;
2016       }
2017       // Otherwise, we need to remove the national prefix from our output.
2018       /** @type {i18n.phonenumbers.NumberFormat} */
2019       var numFormatCopy = formatRule.clone();
2020       numFormatCopy.clearNationalPrefixFormattingRule();
2021       formattedNumber = this.formatByPattern(number,
2022           i18n.phonenumbers.PhoneNumberFormat.NATIONAL, [numFormatCopy]);
2023       break;
2024   }
2025   /** @type {string} */
2026   var rawInput = number.getRawInputOrDefault();
2027   // If no digit is inserted/removed/modified as a result of our formatting, we
2028   // return the formatted phone number; otherwise we return the raw input the
2029   // user entered.
2030   if (formattedNumber != null && rawInput.length > 0) {
2031     /** @type {string} */
2032     var normalizedFormattedNumber =
2033         i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(formattedNumber,
2034             i18n.phonenumbers.PhoneNumberUtil.DIALLABLE_CHAR_MAPPINGS_,
2035             true /* remove non matches */);
2036     /** @type {string} */
2037     var normalizedRawInput =
2038         i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(rawInput,
2039             i18n.phonenumbers.PhoneNumberUtil.DIALLABLE_CHAR_MAPPINGS_,
2040             true /* remove non matches */);
2041     if (normalizedFormattedNumber != normalizedRawInput) {
2042       formattedNumber = rawInput;
2043     }
2044   }
2045   return formattedNumber;
2046 };
2047
2048
2049 /**
2050  * Check if rawInput, which is assumed to be in the national format, has a
2051  * national prefix. The national prefix is assumed to be in digits-only form.
2052  * @param {string} rawInput
2053  * @param {string} nationalPrefix
2054  * @param {string} regionCode
2055  * @return {boolean}
2056  * @private
2057  */
2058 i18n.phonenumbers.PhoneNumberUtil.prototype.rawInputContainsNationalPrefix_ =
2059     function(rawInput, nationalPrefix, regionCode) {
2060
2061   /** @type {string} */
2062   var normalizedNationalNumber =
2063       i18n.phonenumbers.PhoneNumberUtil.normalizeDigitsOnly(rawInput);
2064   if (goog.string.startsWith(normalizedNationalNumber, nationalPrefix)) {
2065     try {
2066       // Some Japanese numbers (e.g. 00777123) might be mistaken to contain the
2067       // national prefix when written without it (e.g. 0777123) if we just do
2068       // prefix matching. To tackle that, we check the validity of the number if
2069       // the assumed national prefix is removed (777123 won't be valid in
2070       // Japan).
2071       return this.isValidNumber(
2072           this.parse(normalizedNationalNumber.substring(nationalPrefix.length),
2073                      regionCode));
2074     } catch (e) {
2075       return false;
2076     }
2077   }
2078   return false;
2079 };
2080
2081
2082 /**
2083  * Returns true if a number is from a region whose national significant number
2084  * couldn't contain a leading zero, but has the italian_leading_zero field set
2085  * to true.
2086  * @param {i18n.phonenumbers.PhoneNumber} number
2087  * @return {boolean}
2088  * @private
2089  */
2090 i18n.phonenumbers.PhoneNumberUtil.prototype.hasUnexpectedItalianLeadingZero_ =
2091     function(number) {
2092
2093   return number.hasItalianLeadingZero() &&
2094       !this.isLeadingZeroPossible(number.getCountryCodeOrDefault());
2095 };
2096
2097
2098 /**
2099  * @param {i18n.phonenumbers.PhoneNumber} number
2100  * @return {boolean}
2101  * @private
2102  */
2103 i18n.phonenumbers.PhoneNumberUtil.prototype.hasFormattingPatternForNumber_ =
2104     function(number) {
2105
2106   /** @type {number} */
2107   var countryCallingCode = number.getCountryCodeOrDefault();
2108   /** @type {string} */
2109   var phoneNumberRegion = this.getRegionCodeForCountryCode(countryCallingCode);
2110   /** @type {i18n.phonenumbers.PhoneMetadata} */
2111   var metadata = this.getMetadataForRegionOrCallingCode_(
2112       countryCallingCode, phoneNumberRegion);
2113   if (metadata == null) {
2114     return false;
2115   }
2116   /** @type {string} */
2117   var nationalNumber = this.getNationalSignificantNumber(number);
2118   /** @type {i18n.phonenumbers.NumberFormat} */
2119   var formatRule = this.chooseFormattingPatternForNumber_(
2120       metadata.numberFormatArray(), nationalNumber);
2121   return formatRule != null;
2122 };
2123
2124
2125 /**
2126  * Formats a phone number for out-of-country dialing purposes.
2127  *
2128  * Note that in this version, if the number was entered originally using alpha
2129  * characters and this version of the number is stored in raw_input, this
2130  * representation of the number will be used rather than the digit
2131  * representation. Grouping information, as specified by characters such as '-'
2132  * and ' ', will be retained.
2133  *
2134  * <p><b>Caveats:</b></p>
2135  * <ul>
2136  * <li>This will not produce good results if the country calling code is both
2137  * present in the raw input _and_ is the start of the national number. This is
2138  * not a problem in the regions which typically use alpha numbers.
2139  * <li>This will also not produce good results if the raw input has any grouping
2140  * information within the first three digits of the national number, and if the
2141  * function needs to strip preceding digits/words in the raw input before these
2142  * digits. Normally people group the first three digits together so this is not
2143  * a huge problem - and will be fixed if it proves to be so.
2144  * </ul>
2145  *
2146  * @param {i18n.phonenumbers.PhoneNumber} number the phone number that needs to
2147  *     be formatted.
2148  * @param {string} regionCallingFrom the region where the call is being placed.
2149  * @return {string} the formatted phone number.
2150  */
2151 i18n.phonenumbers.PhoneNumberUtil.prototype.
2152     formatOutOfCountryKeepingAlphaChars = function(number, regionCallingFrom) {
2153   /** @type {string} */
2154   var rawInput = number.getRawInputOrDefault();
2155   // If there is no raw input, then we can't keep alpha characters because there
2156   // aren't any. In this case, we return formatOutOfCountryCallingNumber.
2157   if (rawInput.length == 0) {
2158     return this.formatOutOfCountryCallingNumber(number, regionCallingFrom);
2159   }
2160   /** @type {number} */
2161   var countryCode = number.getCountryCodeOrDefault();
2162   if (!this.hasValidCountryCallingCode_(countryCode)) {
2163     return rawInput;
2164   }
2165   // Strip any prefix such as country calling code, IDD, that was present. We do
2166   // this by comparing the number in raw_input with the parsed number. To do
2167   // this, first we normalize punctuation. We retain number grouping symbols
2168   // such as ' ' only.
2169   rawInput = i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(
2170       rawInput,
2171       i18n.phonenumbers.PhoneNumberUtil.ALL_PLUS_NUMBER_GROUPING_SYMBOLS_,
2172       true);
2173   // Now we trim everything before the first three digits in the parsed number.
2174   // We choose three because all valid alpha numbers have 3 digits at the start
2175   // - if it does not, then we don't trim anything at all. Similarly, if the
2176   // national number was less than three digits, we don't trim anything at all.
2177   /** @type {string} */
2178   var nationalNumber = this.getNationalSignificantNumber(number);
2179   if (nationalNumber.length > 3) {
2180     /** @type {number} */
2181     var firstNationalNumberDigit =
2182         rawInput.indexOf(nationalNumber.substring(0, 3));
2183     if (firstNationalNumberDigit != -1) {
2184       rawInput = rawInput.substring(firstNationalNumberDigit);
2185     }
2186   }
2187   /** @type {i18n.phonenumbers.PhoneMetadata} */
2188   var metadataForRegionCallingFrom =
2189       this.getMetadataForRegion(regionCallingFrom);
2190   if (countryCode == i18n.phonenumbers.PhoneNumberUtil.NANPA_COUNTRY_CODE_) {
2191     if (this.isNANPACountry(regionCallingFrom)) {
2192       return countryCode + ' ' + rawInput;
2193     }
2194   } else if (metadataForRegionCallingFrom != null &&
2195       countryCode == this.getCountryCodeForValidRegion_(regionCallingFrom)) {
2196     /** @type {i18n.phonenumbers.NumberFormat} */
2197     var formattingPattern = this.chooseFormattingPatternForNumber_(
2198         metadataForRegionCallingFrom.numberFormatArray(), nationalNumber);
2199     if (formattingPattern == null) {
2200       // If no pattern above is matched, we format the original input.
2201       return rawInput;
2202     }
2203     /** @type {i18n.phonenumbers.NumberFormat} */
2204     var newFormat = formattingPattern.clone();
2205     // The first group is the first group of digits that the user wrote
2206     // together.
2207     newFormat.setPattern('(\\d+)(.*)');
2208     // Here we just concatenate them back together after the national prefix
2209     // has been fixed.
2210     newFormat.setFormat('$1$2');
2211     // Now we format using this pattern instead of the default pattern, but
2212     // with the national prefix prefixed if necessary.
2213     // This will not work in the cases where the pattern (and not the leading
2214     // digits) decide whether a national prefix needs to be used, since we have
2215     // overridden the pattern to match anything, but that is not the case in the
2216     // metadata to date.
2217     return this.formatNsnUsingPattern_(rawInput, newFormat,
2218         i18n.phonenumbers.PhoneNumberFormat.NATIONAL);
2219   }
2220   /** @type {string} */
2221   var internationalPrefixForFormatting = '';
2222   // If an unsupported region-calling-from is entered, or a country with
2223   // multiple international prefixes, the international format of the number is
2224   // returned, unless there is a preferred international prefix.
2225   if (metadataForRegionCallingFrom != null) {
2226     /** @type {string} */
2227     var internationalPrefix =
2228         metadataForRegionCallingFrom.getInternationalPrefixOrDefault();
2229     internationalPrefixForFormatting =
2230         i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
2231             i18n.phonenumbers.PhoneNumberUtil.UNIQUE_INTERNATIONAL_PREFIX_,
2232             internationalPrefix) ?
2233         internationalPrefix :
2234         metadataForRegionCallingFrom.getPreferredInternationalPrefixOrDefault();
2235   }
2236   /** @type {string} */
2237   var regionCode = this.getRegionCodeForCountryCode(countryCode);
2238   // Metadata cannot be null because the country calling code is valid.
2239   /** @type {i18n.phonenumbers.PhoneMetadata} */
2240   var metadataForRegion =
2241       this.getMetadataForRegionOrCallingCode_(countryCode, regionCode);
2242   /** @type {string} */
2243   var formattedExtension = this.maybeGetFormattedExtension_(
2244       number, metadataForRegion,
2245       i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL);
2246   if (internationalPrefixForFormatting.length > 0) {
2247     return internationalPrefixForFormatting + ' ' + countryCode + ' ' +
2248         rawInput + formattedExtension;
2249   } else {
2250     // Invalid region entered as country-calling-from (so no metadata was found
2251     // for it) or the region chosen has multiple international dialling
2252     // prefixes.
2253     return this.prefixNumberWithCountryCallingCode_(
2254         countryCode, i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL,
2255         rawInput, formattedExtension);
2256   }
2257 };
2258
2259
2260 /**
2261  * Gets the national significant number of the a phone number. Note a national
2262  * significant number doesn't contain a national prefix or any formatting.
2263  *
2264  * @param {i18n.phonenumbers.PhoneNumber} number the phone number for which the
2265  *     national significant number is needed.
2266  * @return {string} the national significant number of the PhoneNumber object
2267  *     passed in.
2268  */
2269 i18n.phonenumbers.PhoneNumberUtil.prototype.getNationalSignificantNumber =
2270     function(number) {
2271
2272   // If leading zero(s) have been set, we prefix this now. Note this is not a
2273   // national prefix.
2274   /** @type {string} */
2275   var nationalNumber = '' + number.getNationalNumber();
2276   if (number.hasItalianLeadingZero() && number.getItalianLeadingZero()) {
2277     return Array(number.getNumberOfLeadingZerosOrDefault() + 1).join('0') +
2278         nationalNumber;
2279   }
2280   return nationalNumber;
2281 };
2282
2283
2284 /**
2285  * A helper function that is used by format and formatByPattern.
2286  *
2287  * @param {number} countryCallingCode the country calling code.
2288  * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
2289  *     phone number should be formatted into.
2290  * @param {string} formattedNationalNumber
2291  * @param {string} formattedExtension
2292  * @return {string} the formatted phone number.
2293  * @private
2294  */
2295 i18n.phonenumbers.PhoneNumberUtil.prototype.
2296     prefixNumberWithCountryCallingCode_ = function(countryCallingCode,
2297                                                    numberFormat,
2298                                                    formattedNationalNumber,
2299                                                    formattedExtension) {
2300
2301   switch (numberFormat) {
2302     case i18n.phonenumbers.PhoneNumberFormat.E164:
2303       return i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN + countryCallingCode +
2304           formattedNationalNumber + formattedExtension;
2305     case i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL:
2306       return i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN + countryCallingCode +
2307           ' ' + formattedNationalNumber + formattedExtension;
2308     case i18n.phonenumbers.PhoneNumberFormat.RFC3966:
2309       return i18n.phonenumbers.PhoneNumberUtil.RFC3966_PREFIX_ +
2310           i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN + countryCallingCode +
2311           '-' + formattedNationalNumber + formattedExtension;
2312     case i18n.phonenumbers.PhoneNumberFormat.NATIONAL:
2313     default:
2314       return formattedNationalNumber + formattedExtension;
2315   }
2316 };
2317
2318
2319 /**
2320  * Note in some regions, the national number can be written in two completely
2321  * different ways depending on whether it forms part of the NATIONAL format or
2322  * INTERNATIONAL format. The numberFormat parameter here is used to specify
2323  * which format to use for those cases. If a carrierCode is specified, this will
2324  * be inserted into the formatted string to replace $CC.
2325  *
2326  * @param {string} number a string of characters representing a phone number.
2327  * @param {i18n.phonenumbers.PhoneMetadata} metadata the metadata for the
2328  *     region that we think this number is from.
2329  * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
2330  *     phone number should be formatted into.
2331  * @param {string=} opt_carrierCode
2332  * @return {string} the formatted phone number.
2333  * @private
2334  */
2335 i18n.phonenumbers.PhoneNumberUtil.prototype.formatNsn_ =
2336     function(number, metadata, numberFormat, opt_carrierCode) {
2337
2338   /** @type {Array.<i18n.phonenumbers.NumberFormat>} */
2339   var intlNumberFormats = metadata.intlNumberFormatArray();
2340   // When the intlNumberFormats exists, we use that to format national number
2341   // for the INTERNATIONAL format instead of using the numberDesc.numberFormats.
2342   /** @type {Array.<i18n.phonenumbers.NumberFormat>} */
2343   var availableFormats =
2344       (intlNumberFormats.length == 0 ||
2345           numberFormat == i18n.phonenumbers.PhoneNumberFormat.NATIONAL) ?
2346       metadata.numberFormatArray() : metadata.intlNumberFormatArray();
2347   /** @type {i18n.phonenumbers.NumberFormat} */
2348   var formattingPattern = this.chooseFormattingPatternForNumber_(
2349       availableFormats, number);
2350   return (formattingPattern == null) ?
2351       number :
2352       this.formatNsnUsingPattern_(number, formattingPattern,
2353                                   numberFormat, opt_carrierCode);
2354 };
2355
2356
2357 /**
2358  * @param {Array.<i18n.phonenumbers.NumberFormat>} availableFormats the
2359  *     available formats the phone number could be formatted into.
2360  * @param {string} nationalNumber a string of characters representing a phone
2361  *     number.
2362  * @return {i18n.phonenumbers.NumberFormat}
2363  * @private
2364  */
2365 i18n.phonenumbers.PhoneNumberUtil.prototype.chooseFormattingPatternForNumber_ =
2366     function(availableFormats, nationalNumber) {
2367
2368   /** @type {i18n.phonenumbers.NumberFormat} */
2369   var numFormat;
2370   /** @type {number} */
2371   var l = availableFormats.length;
2372   for (var i = 0; i < l; ++i) {
2373     numFormat = availableFormats[i];
2374     /** @type {number} */
2375     var size = numFormat.leadingDigitsPatternCount();
2376     if (size == 0 ||
2377         // We always use the last leading_digits_pattern, as it is the most
2378         // detailed.
2379         nationalNumber
2380             .search(numFormat.getLeadingDigitsPattern(size - 1)) == 0) {
2381       /** @type {!RegExp} */
2382       var patternToMatch = new RegExp(numFormat.getPattern());
2383       if (i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(patternToMatch,
2384                                                              nationalNumber)) {
2385         return numFormat;
2386       }
2387     }
2388   }
2389   return null;
2390 };
2391
2392
2393 /**
2394  * Note that carrierCode is optional - if null or an empty string, no carrier
2395  * code replacement will take place.
2396  *
2397  * @param {string} nationalNumber a string of characters representing a phone
2398  *     number.
2399  * @param {i18n.phonenumbers.NumberFormat} formattingPattern the formatting rule
2400  *     the phone number should be formatted into.
2401  * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
2402  *     phone number should be formatted into.
2403  * @param {string=} opt_carrierCode
2404  * @return {string} the formatted phone number.
2405  * @private
2406  */
2407 i18n.phonenumbers.PhoneNumberUtil.prototype.formatNsnUsingPattern_ =
2408     function(nationalNumber, formattingPattern, numberFormat, opt_carrierCode) {
2409
2410   /** @type {string} */
2411   var numberFormatRule = formattingPattern.getFormatOrDefault();
2412   /** @type {!RegExp} */
2413   var patternToMatch = new RegExp(formattingPattern.getPattern());
2414   /** @type {string} */
2415   var domesticCarrierCodeFormattingRule =
2416       formattingPattern.getDomesticCarrierCodeFormattingRuleOrDefault();
2417   /** @type {string} */
2418   var formattedNationalNumber = '';
2419   if (numberFormat == i18n.phonenumbers.PhoneNumberFormat.NATIONAL &&
2420       opt_carrierCode != null && opt_carrierCode.length > 0 &&
2421       domesticCarrierCodeFormattingRule.length > 0) {
2422     // Replace the $CC in the formatting rule with the desired carrier code.
2423     /** @type {string} */
2424     var carrierCodeFormattingRule = domesticCarrierCodeFormattingRule
2425         .replace(i18n.phonenumbers.PhoneNumberUtil.CC_PATTERN_,
2426                  opt_carrierCode);
2427     // Now replace the $FG in the formatting rule with the first group and
2428     // the carrier code combined in the appropriate way.
2429     numberFormatRule = numberFormatRule.replace(
2430         i18n.phonenumbers.PhoneNumberUtil.FIRST_GROUP_PATTERN_,
2431         carrierCodeFormattingRule);
2432     formattedNationalNumber =
2433         nationalNumber.replace(patternToMatch, numberFormatRule);
2434   } else {
2435     // Use the national prefix formatting rule instead.
2436     /** @type {string} */
2437     var nationalPrefixFormattingRule =
2438         formattingPattern.getNationalPrefixFormattingRuleOrDefault();
2439     if (numberFormat == i18n.phonenumbers.PhoneNumberFormat.NATIONAL &&
2440         nationalPrefixFormattingRule != null &&
2441         nationalPrefixFormattingRule.length > 0) {
2442       formattedNationalNumber = nationalNumber.replace(patternToMatch,
2443           numberFormatRule.replace(
2444               i18n.phonenumbers.PhoneNumberUtil.FIRST_GROUP_PATTERN_,
2445               nationalPrefixFormattingRule));
2446     } else {
2447       formattedNationalNumber =
2448           nationalNumber.replace(patternToMatch, numberFormatRule);
2449     }
2450   }
2451   if (numberFormat == i18n.phonenumbers.PhoneNumberFormat.RFC3966) {
2452     // Strip any leading punctuation.
2453     formattedNationalNumber = formattedNationalNumber.replace(
2454         new RegExp('^' + i18n.phonenumbers.PhoneNumberUtil.SEPARATOR_PATTERN_),
2455         '');
2456     // Replace the rest with a dash between each number group.
2457     formattedNationalNumber = formattedNationalNumber.replace(
2458         new RegExp(i18n.phonenumbers.PhoneNumberUtil.SEPARATOR_PATTERN_, 'g'),
2459         '-');
2460   }
2461   return formattedNationalNumber;
2462 };
2463
2464
2465 /**
2466  * Gets a valid number for the specified region.
2467  *
2468  * @param {string} regionCode the region for which an example number is needed.
2469  * @return {i18n.phonenumbers.PhoneNumber} a valid fixed-line number for the
2470  *     specified region. Returns null when the metadata does not contain such
2471  *     information, or the region 001 is passed in. For 001 (representing non-
2472  *     geographical numbers), call {@link #getExampleNumberForNonGeoEntity}
2473  *     instead.
2474  */
2475 i18n.phonenumbers.PhoneNumberUtil.prototype.getExampleNumber =
2476     function(regionCode) {
2477
2478   return this.getExampleNumberForType(regionCode,
2479       i18n.phonenumbers.PhoneNumberType.FIXED_LINE);
2480 };
2481
2482
2483 /**
2484  * Gets a valid number for the specified region and number type.
2485  *
2486  * @param {string} regionCode the region for which an example number is needed.
2487  * @param {i18n.phonenumbers.PhoneNumberType} type the type of number that is
2488  *     needed.
2489  * @return {i18n.phonenumbers.PhoneNumber} a valid number for the specified
2490  *     region and type. Returns null when the metadata does not contain such
2491  *     information or if an invalid region or region 001 was entered.
2492  *     For 001 (representing non-geographical numbers), call
2493  *     {@link #getExampleNumberForNonGeoEntity} instead.
2494  */
2495 i18n.phonenumbers.PhoneNumberUtil.prototype.getExampleNumberForType =
2496     function(regionCode, type) {
2497
2498   // Check the region code is valid.
2499   if (!this.isValidRegionCode_(regionCode)) {
2500     return null;
2501   }
2502   /** @type {i18n.phonenumbers.PhoneNumberDesc} */
2503   var desc = this.getNumberDescByType_(
2504       this.getMetadataForRegion(regionCode), type);
2505   try {
2506     if (desc.hasExampleNumber()) {
2507       return this.parse(desc.getExampleNumberOrDefault(), regionCode);
2508     }
2509   } catch (e) {
2510   }
2511   return null;
2512 };
2513
2514
2515 /**
2516  * Gets a valid number for the specified country calling code for a
2517  * non-geographical entity.
2518  *
2519  * @param {number} countryCallingCode the country calling code for a
2520  *     non-geographical entity.
2521  * @return {i18n.phonenumbers.PhoneNumber} a valid number for the
2522  *     non-geographical entity. Returns null when the metadata does not contain
2523  *     such information, or the country calling code passed in does not belong
2524  *     to a non-geographical entity.
2525  */
2526 i18n.phonenumbers.PhoneNumberUtil.prototype.getExampleNumberForNonGeoEntity =
2527     function(countryCallingCode) {
2528   /** @type {i18n.phonenumbers.PhoneMetadata} */
2529   var metadata =
2530       this.getMetadataForNonGeographicalRegion(countryCallingCode);
2531   if (metadata != null) {
2532     /** @type {i18n.phonenumbers.PhoneNumberDesc} */
2533     var desc = metadata.getGeneralDesc();
2534     try {
2535       if (desc.hasExampleNumber()) {
2536         return this.parse('+' + countryCallingCode + desc.getExampleNumber(),
2537                           'ZZ');
2538       }
2539     } catch (e) {
2540     }
2541   }
2542   return null;
2543 };
2544
2545
2546 /**
2547  * Gets the formatted extension of a phone number, if the phone number had an
2548  * extension specified. If not, it returns an empty string.
2549  *
2550  * @param {i18n.phonenumbers.PhoneNumber} number the PhoneNumber that might have
2551  *     an extension.
2552  * @param {i18n.phonenumbers.PhoneMetadata} metadata the metadata for the
2553  *     region that we think this number is from.
2554  * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
2555  *     phone number should be formatted into.
2556  * @return {string} the formatted extension if any.
2557  * @private
2558  */
2559 i18n.phonenumbers.PhoneNumberUtil.prototype.maybeGetFormattedExtension_ =
2560     function(number, metadata, numberFormat) {
2561
2562   if (!number.hasExtension() || number.getExtension().length == 0) {
2563     return '';
2564   } else {
2565     if (numberFormat == i18n.phonenumbers.PhoneNumberFormat.RFC3966) {
2566       return i18n.phonenumbers.PhoneNumberUtil.RFC3966_EXTN_PREFIX_ +
2567           number.getExtension();
2568     } else {
2569       if (metadata.hasPreferredExtnPrefix()) {
2570         return metadata.getPreferredExtnPrefix() +
2571             number.getExtensionOrDefault();
2572       } else {
2573         return i18n.phonenumbers.PhoneNumberUtil.DEFAULT_EXTN_PREFIX_ +
2574             number.getExtensionOrDefault();
2575       }
2576     }
2577   }
2578 };
2579
2580
2581 /**
2582  * @param {i18n.phonenumbers.PhoneMetadata} metadata
2583  * @param {i18n.phonenumbers.PhoneNumberType} type
2584  * @return {i18n.phonenumbers.PhoneNumberDesc}
2585  * @private
2586  */
2587 i18n.phonenumbers.PhoneNumberUtil.prototype.getNumberDescByType_ =
2588     function(metadata, type) {
2589
2590   switch (type) {
2591     case i18n.phonenumbers.PhoneNumberType.PREMIUM_RATE:
2592       return metadata.getPremiumRate();
2593     case i18n.phonenumbers.PhoneNumberType.TOLL_FREE:
2594       return metadata.getTollFree();
2595     case i18n.phonenumbers.PhoneNumberType.MOBILE:
2596       return metadata.getMobile();
2597     case i18n.phonenumbers.PhoneNumberType.FIXED_LINE:
2598     case i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE:
2599       return metadata.getFixedLine();
2600     case i18n.phonenumbers.PhoneNumberType.SHARED_COST:
2601       return metadata.getSharedCost();
2602     case i18n.phonenumbers.PhoneNumberType.VOIP:
2603       return metadata.getVoip();
2604     case i18n.phonenumbers.PhoneNumberType.PERSONAL_NUMBER:
2605       return metadata.getPersonalNumber();
2606     case i18n.phonenumbers.PhoneNumberType.PAGER:
2607       return metadata.getPager();
2608     case i18n.phonenumbers.PhoneNumberType.UAN:
2609       return metadata.getUan();
2610     case i18n.phonenumbers.PhoneNumberType.VOICEMAIL:
2611       return metadata.getVoicemail();
2612     default:
2613       return metadata.getGeneralDesc();
2614   }
2615 };
2616
2617
2618 /**
2619  * Gets the type of a phone number.
2620  *
2621  * @param {i18n.phonenumbers.PhoneNumber} number the phone number that we want
2622  *     to know the type.
2623  * @return {i18n.phonenumbers.PhoneNumberType} the type of the phone number.
2624  */
2625 i18n.phonenumbers.PhoneNumberUtil.prototype.getNumberType =
2626     function(number) {
2627
2628   /** @type {?string} */
2629   var regionCode = this.getRegionCodeForNumber(number);
2630   /** @type {i18n.phonenumbers.PhoneMetadata} */
2631   var metadata = this.getMetadataForRegionOrCallingCode_(
2632       number.getCountryCodeOrDefault(), regionCode);
2633   if (metadata == null) {
2634     return i18n.phonenumbers.PhoneNumberType.UNKNOWN;
2635   }
2636   /** @type {string} */
2637   var nationalSignificantNumber = this.getNationalSignificantNumber(number);
2638   return this.getNumberTypeHelper_(nationalSignificantNumber, metadata);
2639 };
2640
2641
2642 /**
2643  * @param {string} nationalNumber
2644  * @param {i18n.phonenumbers.PhoneMetadata} metadata
2645  * @return {i18n.phonenumbers.PhoneNumberType}
2646  * @private
2647  */
2648 i18n.phonenumbers.PhoneNumberUtil.prototype.getNumberTypeHelper_ =
2649     function(nationalNumber, metadata) {
2650
2651   if (!this.isNumberMatchingDesc_(nationalNumber, metadata.getGeneralDesc())) {
2652     return i18n.phonenumbers.PhoneNumberType.UNKNOWN;
2653   }
2654
2655   if (this.isNumberMatchingDesc_(nationalNumber, metadata.getPremiumRate())) {
2656     return i18n.phonenumbers.PhoneNumberType.PREMIUM_RATE;
2657   }
2658   if (this.isNumberMatchingDesc_(nationalNumber, metadata.getTollFree())) {
2659     return i18n.phonenumbers.PhoneNumberType.TOLL_FREE;
2660   }
2661   if (this.isNumberMatchingDesc_(nationalNumber, metadata.getSharedCost())) {
2662     return i18n.phonenumbers.PhoneNumberType.SHARED_COST;
2663   }
2664   if (this.isNumberMatchingDesc_(nationalNumber, metadata.getVoip())) {
2665     return i18n.phonenumbers.PhoneNumberType.VOIP;
2666   }
2667   if (this.isNumberMatchingDesc_(nationalNumber,
2668                                  metadata.getPersonalNumber())) {
2669     return i18n.phonenumbers.PhoneNumberType.PERSONAL_NUMBER;
2670   }
2671   if (this.isNumberMatchingDesc_(nationalNumber, metadata.getPager())) {
2672     return i18n.phonenumbers.PhoneNumberType.PAGER;
2673   }
2674   if (this.isNumberMatchingDesc_(nationalNumber, metadata.getUan())) {
2675     return i18n.phonenumbers.PhoneNumberType.UAN;
2676   }
2677   if (this.isNumberMatchingDesc_(nationalNumber, metadata.getVoicemail())) {
2678     return i18n.phonenumbers.PhoneNumberType.VOICEMAIL;
2679   }
2680
2681   /** @type {boolean} */
2682   var isFixedLine = this.isNumberMatchingDesc_(nationalNumber, metadata
2683       .getFixedLine());
2684   if (isFixedLine) {
2685     if (metadata.getSameMobileAndFixedLinePattern()) {
2686       return i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE;
2687     } else if (this.isNumberMatchingDesc_(nationalNumber,
2688                                           metadata.getMobile())) {
2689       return i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE;
2690     }
2691     return i18n.phonenumbers.PhoneNumberType.FIXED_LINE;
2692   }
2693   // Otherwise, test to see if the number is mobile. Only do this if certain
2694   // that the patterns for mobile and fixed line aren't the same.
2695   if (!metadata.getSameMobileAndFixedLinePattern() &&
2696       this.isNumberMatchingDesc_(nationalNumber, metadata.getMobile())) {
2697     return i18n.phonenumbers.PhoneNumberType.MOBILE;
2698   }
2699   return i18n.phonenumbers.PhoneNumberType.UNKNOWN;
2700 };
2701
2702
2703 /**
2704  * Returns the metadata for the given region code or {@code null} if the region
2705  * code is invalid or unknown.
2706  *
2707  * @param {?string} regionCode
2708  * @return {i18n.phonenumbers.PhoneMetadata}
2709  */
2710 i18n.phonenumbers.PhoneNumberUtil.prototype.getMetadataForRegion =
2711     function(regionCode) {
2712
2713   if (regionCode == null) {
2714     return null;
2715   }
2716   regionCode = regionCode.toUpperCase();
2717   /** @type {i18n.phonenumbers.PhoneMetadata} */
2718   var metadata = this.regionToMetadataMap[regionCode];
2719   if (metadata == null) {
2720     /** @type {goog.proto2.PbLiteSerializer} */
2721     var serializer = new goog.proto2.PbLiteSerializer();
2722     /** @type {Array} */
2723     var metadataSerialized =
2724         i18n.phonenumbers.metadata.countryToMetadata[regionCode];
2725     if (metadataSerialized == null) {
2726       return null;
2727     }
2728     metadata = /** @type {i18n.phonenumbers.PhoneMetadata} */ (
2729         serializer.deserialize(i18n.phonenumbers.PhoneMetadata.getDescriptor(),
2730             metadataSerialized));
2731     this.regionToMetadataMap[regionCode] = metadata;
2732   }
2733   return metadata;
2734 };
2735
2736
2737 /**
2738  * @param {number} countryCallingCode
2739  * @return {i18n.phonenumbers.PhoneMetadata}
2740  */
2741 i18n.phonenumbers.PhoneNumberUtil.prototype.
2742     getMetadataForNonGeographicalRegion = function(countryCallingCode) {
2743
2744   return this.getMetadataForRegion('' + countryCallingCode);
2745 };
2746
2747
2748 /**
2749  * @param {string} nationalNumber
2750  * @param {i18n.phonenumbers.PhoneNumberDesc} numberDesc
2751  * @return {boolean}
2752  * @private
2753  */
2754 i18n.phonenumbers.PhoneNumberUtil.prototype.isNumberMatchingDesc_ =
2755     function(nationalNumber, numberDesc) {
2756
2757   return i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
2758       numberDesc.getPossibleNumberPatternOrDefault(), nationalNumber) &&
2759       i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
2760           numberDesc.getNationalNumberPatternOrDefault(), nationalNumber);
2761 };
2762
2763
2764 /**
2765  * Tests whether a phone number matches a valid pattern. Note this doesn't
2766  * verify the number is actually in use, which is impossible to tell by just
2767  * looking at a number itself.
2768  *
2769  * @param {i18n.phonenumbers.PhoneNumber} number the phone number that we want
2770  *     to validate.
2771  * @return {boolean} a boolean that indicates whether the number is of a valid
2772  *     pattern.
2773  */
2774 i18n.phonenumbers.PhoneNumberUtil.prototype.isValidNumber = function(number) {
2775   /** @type {?string} */
2776   var regionCode = this.getRegionCodeForNumber(number);
2777   return this.isValidNumberForRegion(number, regionCode);
2778 };
2779
2780
2781 /**
2782  * Tests whether a phone number is valid for a certain region. Note this doesn't
2783  * verify the number is actually in use, which is impossible to tell by just
2784  * looking at a number itself. If the country calling code is not the same as
2785  * the country calling code for the region, this immediately exits with false.
2786  * After this, the specific number pattern rules for the region are examined.
2787  * This is useful for determining for example whether a particular number is
2788  * valid for Canada, rather than just a valid NANPA number.
2789  * Warning: In most cases, you want to use {@link #isValidNumber} instead. For
2790  * example, this method will mark numbers from British Crown dependencies such
2791  * as the Isle of Man as invalid for the region "GB" (United Kingdom), since it
2792  * has its own region code, "IM", which may be undesirable.
2793  *
2794  * @param {i18n.phonenumbers.PhoneNumber} number the phone number that we want
2795  *     to validate.
2796  * @param {?string} regionCode the region that we want to validate the phone
2797  *     number for.
2798  * @return {boolean} a boolean that indicates whether the number is of a valid
2799  *     pattern.
2800  */
2801 i18n.phonenumbers.PhoneNumberUtil.prototype.isValidNumberForRegion =
2802     function(number, regionCode) {
2803
2804   /** @type {number} */
2805   var countryCode = number.getCountryCodeOrDefault();
2806   /** @type {i18n.phonenumbers.PhoneMetadata} */
2807   var metadata =
2808       this.getMetadataForRegionOrCallingCode_(countryCode, regionCode);
2809   if (metadata == null ||
2810       (i18n.phonenumbers.PhoneNumberUtil.REGION_CODE_FOR_NON_GEO_ENTITY !=
2811        regionCode &&
2812        countryCode != this.getCountryCodeForValidRegion_(regionCode))) {
2813     // Either the region code was invalid, or the country calling code for this
2814     // number does not match that of the region code.
2815     return false;
2816   }
2817   /** @type {string} */
2818   var nationalSignificantNumber = this.getNationalSignificantNumber(number);
2819
2820   return this.getNumberTypeHelper_(nationalSignificantNumber, metadata) !=
2821       i18n.phonenumbers.PhoneNumberType.UNKNOWN;
2822 };
2823
2824
2825 /**
2826  * Returns the region where a phone number is from. This could be used for
2827  * geocoding at the region level.
2828  *
2829  * @param {i18n.phonenumbers.PhoneNumber} number the phone number whose origin
2830  *     we want to know.
2831  * @return {?string} the region where the phone number is from, or null
2832  *     if no region matches this calling code.
2833  */
2834 i18n.phonenumbers.PhoneNumberUtil.prototype.getRegionCodeForNumber =
2835     function(number) {
2836
2837   if (number == null) {
2838     return null;
2839   }
2840   /** @type {number} */
2841   var countryCode = number.getCountryCodeOrDefault();
2842   /** @type {Array.<string>} */
2843   var regions =
2844       i18n.phonenumbers.metadata.countryCodeToRegionCodeMap[countryCode];
2845   if (regions == null) {
2846     return null;
2847   }
2848   if (regions.length == 1) {
2849     return regions[0];
2850   } else {
2851     return this.getRegionCodeForNumberFromRegionList_(number, regions);
2852   }
2853 };
2854
2855
2856 /**
2857  * @param {i18n.phonenumbers.PhoneNumber} number
2858  * @param {Array.<string>} regionCodes
2859  * @return {?string}
2860  * @private
2861  */
2862 i18n.phonenumbers.PhoneNumberUtil.prototype.
2863     getRegionCodeForNumberFromRegionList_ = function(number, regionCodes) {
2864
2865   /** @type {string} */
2866   var nationalNumber = this.getNationalSignificantNumber(number);
2867   /** @type {string} */
2868   var regionCode;
2869   /** @type {number} */
2870   var regionCodesLength = regionCodes.length;
2871   for (var i = 0; i < regionCodesLength; i++) {
2872     regionCode = regionCodes[i];
2873     // If leadingDigits is present, use this. Otherwise, do full validation.
2874     // Metadata cannot be null because the region codes come from the country
2875     // calling code map.
2876     /** @type {i18n.phonenumbers.PhoneMetadata} */
2877     var metadata = this.getMetadataForRegion(regionCode);
2878     if (metadata.hasLeadingDigits()) {
2879       if (nationalNumber.search(metadata.getLeadingDigits()) == 0) {
2880         return regionCode;
2881       }
2882     } else if (this.getNumberTypeHelper_(nationalNumber, metadata) !=
2883         i18n.phonenumbers.PhoneNumberType.UNKNOWN) {
2884       return regionCode;
2885     }
2886   }
2887   return null;
2888 };
2889
2890
2891 /**
2892  * Returns the region code that matches the specific country calling code. In
2893  * the case of no region code being found, ZZ will be returned. In the case of
2894  * multiple regions, the one designated in the metadata as the 'main' region for
2895  * this calling code will be returned.
2896  *
2897  * @param {number} countryCallingCode the country calling code.
2898  * @return {string}
2899  */
2900 i18n.phonenumbers.PhoneNumberUtil.prototype.getRegionCodeForCountryCode =
2901     function(countryCallingCode) {
2902
2903   /** @type {Array.<string>} */
2904   var regionCodes =
2905       i18n.phonenumbers.metadata.countryCodeToRegionCodeMap[countryCallingCode];
2906   return regionCodes == null ?
2907       i18n.phonenumbers.PhoneNumberUtil.UNKNOWN_REGION_ : regionCodes[0];
2908 };
2909
2910
2911 /**
2912  * Returns a list with the region codes that match the specific country calling
2913  * code. For non-geographical country calling codes, the region code 001 is
2914  * returned. Also, in the case of no region code being found, an empty list is
2915  * returned.
2916  *
2917  * @param {number} countryCallingCode the country calling code.
2918  * @return {Array.<string>}
2919  */
2920 i18n.phonenumbers.PhoneNumberUtil.prototype.getRegionCodesForCountryCode =
2921     function(countryCallingCode) {
2922
2923   /** @type {Array.<string>} */
2924   var regionCodes =
2925       i18n.phonenumbers.metadata.countryCodeToRegionCodeMap[countryCallingCode];
2926   return regionCodes == null ? [] : regionCodes;
2927 };
2928
2929
2930 /**
2931  * Returns the country calling code for a specific region. For example, this
2932  * would be 1 for the United States, and 64 for New Zealand.
2933  *
2934  * @param {?string} regionCode the region that we want to get the country
2935  *     calling code for.
2936  * @return {number} the country calling code for the region denoted by
2937  *     regionCode.
2938  */
2939 i18n.phonenumbers.PhoneNumberUtil.prototype.getCountryCodeForRegion =
2940     function(regionCode) {
2941
2942   if (!this.isValidRegionCode_(regionCode)) {
2943     return 0;
2944   }
2945   return this.getCountryCodeForValidRegion_(regionCode);
2946 };
2947
2948
2949 /**
2950  * Returns the country calling code for a specific region. For example, this
2951  * would be 1 for the United States, and 64 for New Zealand. Assumes the region
2952  * is already valid.
2953  *
2954  * @param {?string} regionCode the region that we want to get the country
2955  *     calling code for.
2956  * @return {number} the country calling code for the region denoted by
2957  *     regionCode.
2958  * @throws {string} if the region is invalid
2959  * @private
2960  */
2961 i18n.phonenumbers.PhoneNumberUtil.prototype.getCountryCodeForValidRegion_ =
2962     function(regionCode) {
2963
2964   /** @type {i18n.phonenumbers.PhoneMetadata} */
2965   var metadata = this.getMetadataForRegion(regionCode);
2966   if (metadata == null) {
2967     throw 'Invalid region code: ' + regionCode;
2968   }
2969   return metadata.getCountryCodeOrDefault();
2970 };
2971
2972
2973 /**
2974  * Returns the national dialling prefix for a specific region. For example, this
2975  * would be 1 for the United States, and 0 for New Zealand. Set stripNonDigits
2976  * to true to strip symbols like '~' (which indicates a wait for a dialling
2977  * tone) from the prefix returned. If no national prefix is present, we return
2978  * null.
2979  *
2980  * <p>Warning: Do not use this method for do-your-own formatting - for some
2981  * regions, the national dialling prefix is used only for certain types of
2982  * numbers. Use the library's formatting functions to prefix the national prefix
2983  * when required.
2984  *
2985  * @param {?string} regionCode the region that we want to get the dialling
2986  *     prefix for.
2987  * @param {boolean} stripNonDigits true to strip non-digits from the national
2988  *     dialling prefix.
2989  * @return {?string} the dialling prefix for the region denoted by
2990  *     regionCode.
2991  */
2992 i18n.phonenumbers.PhoneNumberUtil.prototype.getNddPrefixForRegion = function(
2993     regionCode, stripNonDigits) {
2994   /** @type {i18n.phonenumbers.PhoneMetadata} */
2995   var metadata = this.getMetadataForRegion(regionCode);
2996   if (metadata == null) {
2997     return null;
2998   }
2999   /** @type {string} */
3000   var nationalPrefix = metadata.getNationalPrefixOrDefault();
3001   // If no national prefix was found, we return null.
3002   if (nationalPrefix.length == 0) {
3003     return null;
3004   }
3005   if (stripNonDigits) {
3006     // Note: if any other non-numeric symbols are ever used in national
3007     // prefixes, these would have to be removed here as well.
3008     nationalPrefix = nationalPrefix.replace('~', '');
3009   }
3010   return nationalPrefix;
3011 };
3012
3013
3014 /**
3015  * Checks if this is a region under the North American Numbering Plan
3016  * Administration (NANPA).
3017  *
3018  * @param {?string} regionCode the ISO 3166-1 two-letter region code.
3019  * @return {boolean} true if regionCode is one of the regions under NANPA.
3020  */
3021 i18n.phonenumbers.PhoneNumberUtil.prototype.isNANPACountry =
3022     function(regionCode) {
3023
3024   return regionCode != null && goog.array.contains(
3025       i18n.phonenumbers.metadata.countryCodeToRegionCodeMap[
3026           i18n.phonenumbers.PhoneNumberUtil.NANPA_COUNTRY_CODE_],
3027       regionCode.toUpperCase());
3028 };
3029
3030
3031 /**
3032  * Checks whether countryCode represents the country calling code from a region
3033  * whose national significant number could contain a leading zero. An example of
3034  * such a region is Italy. Returns false if no metadata for the country is
3035  * found.
3036  *
3037  * @param {number} countryCallingCode the country calling code.
3038  * @return {boolean}
3039  */
3040 i18n.phonenumbers.PhoneNumberUtil.prototype.isLeadingZeroPossible =
3041     function(countryCallingCode) {
3042   /** @type {i18n.phonenumbers.PhoneMetadata} */
3043   var mainMetadataForCallingCode = this.getMetadataForRegionOrCallingCode_(
3044       countryCallingCode,
3045       this.getRegionCodeForCountryCode(countryCallingCode));
3046   return mainMetadataForCallingCode != null &&
3047       mainMetadataForCallingCode.getLeadingZeroPossibleOrDefault();
3048 };
3049
3050
3051 /**
3052  * Checks if the number is a valid vanity (alpha) number such as 800 MICROSOFT.
3053  * A valid vanity number will start with at least 3 digits and will have three
3054  * or more alpha characters. This does not do region-specific checks - to work
3055  * out if this number is actually valid for a region, it should be parsed and
3056  * methods such as {@link #isPossibleNumberWithReason} and
3057  * {@link #isValidNumber} should be used.
3058  *
3059  * @param {string} number the number that needs to be checked.
3060  * @return {boolean} true if the number is a valid vanity number.
3061  */
3062 i18n.phonenumbers.PhoneNumberUtil.prototype.isAlphaNumber = function(number) {
3063   if (!i18n.phonenumbers.PhoneNumberUtil.isViablePhoneNumber(number)) {
3064     // Number is too short, or doesn't match the basic phone number pattern.
3065     return false;
3066   }
3067   /** @type {!goog.string.StringBuffer} */
3068   var strippedNumber = new goog.string.StringBuffer(number);
3069   this.maybeStripExtension(strippedNumber);
3070   return i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
3071       i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_PHONE_PATTERN_,
3072       strippedNumber.toString());
3073 };
3074
3075
3076 /**
3077  * Convenience wrapper around {@link #isPossibleNumberWithReason}. Instead of
3078  * returning the reason for failure, this method returns a boolean value.
3079  *
3080  * @param {i18n.phonenumbers.PhoneNumber} number the number that needs to be
3081  *     checked.
3082  * @return {boolean} true if the number is possible.
3083  */
3084 i18n.phonenumbers.PhoneNumberUtil.prototype.isPossibleNumber =
3085     function(number) {
3086
3087   return this.isPossibleNumberWithReason(number) ==
3088       i18n.phonenumbers.PhoneNumberUtil.ValidationResult.IS_POSSIBLE;
3089 };
3090
3091
3092 /**
3093  * Helper method to check a number against a particular pattern and determine
3094  * whether it matches, or is too short or too long. Currently, if a number
3095  * pattern suggests that numbers of length 7 and 10 are possible, and a number
3096  * in between these possible lengths is entered, such as of length 8, this will
3097  * return TOO_LONG.
3098  *
3099  * @param {string} numberPattern
3100  * @param {string} number
3101  * @return {i18n.phonenumbers.PhoneNumberUtil.ValidationResult}
3102  * @private
3103  */
3104 i18n.phonenumbers.PhoneNumberUtil.prototype.testNumberLengthAgainstPattern_ =
3105     function(numberPattern, number) {
3106   if (i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(numberPattern,
3107                                                          number)) {
3108     return i18n.phonenumbers.PhoneNumberUtil.ValidationResult.IS_POSSIBLE;
3109   }
3110   if (number.search(numberPattern) == 0) {
3111     return i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_LONG;
3112   } else {
3113     return i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_SHORT;
3114   }
3115 };
3116
3117
3118 /**
3119  * Helper method to check whether a number is too short to be a regular length
3120  * phone number in a region.
3121  *
3122  * @param {i18n.phonenumbers.PhoneMetadata} regionMetadata
3123  * @param {string} number
3124  * @return {boolean}
3125  * @private
3126  */
3127 i18n.phonenumbers.PhoneNumberUtil.prototype.isShorterThanPossibleNormalNumber_ =
3128     function(regionMetadata, number) {
3129   /** @type {string} */
3130   var possibleNumberPattern =
3131       regionMetadata.getGeneralDesc().getPossibleNumberPatternOrDefault();
3132   return this.testNumberLengthAgainstPattern_(possibleNumberPattern, number) ==
3133       i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_SHORT;
3134 };
3135
3136
3137 /**
3138  * Check whether a phone number is a possible number. It provides a more lenient
3139  * check than {@link #isValidNumber} in the following sense:
3140  * <ol>
3141  * <li>It only checks the length of phone numbers. In particular, it doesn't
3142  * check starting digits of the number.
3143  * <li>It doesn't attempt to figure out the type of the number, but uses general
3144  * rules which applies to all types of phone numbers in a region. Therefore, it
3145  * is much faster than isValidNumber.
3146  * <li>For fixed line numbers, many regions have the concept of area code, which
3147  * together with subscriber number constitute the national significant number.
3148  * It is sometimes okay to dial the subscriber number only when dialing in the
3149  * same area. This function will return true if the subscriber-number-only
3150  * version is passed in. On the other hand, because isValidNumber validates
3151  * using information on both starting digits (for fixed line numbers, that would
3152  * most likely be area codes) and length (obviously includes the length of area
3153  * codes for fixed line numbers), it will return false for the
3154  * subscriber-number-only version.
3155  * </ol>
3156  *
3157  * @param {i18n.phonenumbers.PhoneNumber} number the number that needs to be
3158  *     checked.
3159  * @return {i18n.phonenumbers.PhoneNumberUtil.ValidationResult} a
3160  *     ValidationResult object which indicates whether the number is possible.
3161  */
3162 i18n.phonenumbers.PhoneNumberUtil.prototype.isPossibleNumberWithReason =
3163     function(number) {
3164
3165   /** @type {string} */
3166   var nationalNumber = this.getNationalSignificantNumber(number);
3167   /** @type {number} */
3168   var countryCode = number.getCountryCodeOrDefault();
3169   // Note: For Russian Fed and NANPA numbers, we just use the rules from the
3170   // default region (US or Russia) since the getRegionCodeForNumber will not
3171   // work if the number is possible but not valid. This would need to be
3172   // revisited if the possible number pattern ever differed between various
3173   // regions within those plans.
3174   if (!this.hasValidCountryCallingCode_(countryCode)) {
3175     return i18n.phonenumbers.PhoneNumberUtil.ValidationResult
3176         .INVALID_COUNTRY_CODE;
3177   }
3178   /** @type {string} */
3179   var regionCode = this.getRegionCodeForCountryCode(countryCode);
3180   // Metadata cannot be null because the country calling code is valid.
3181   /** @type {i18n.phonenumbers.PhoneMetadata} */
3182   var metadata =
3183       this.getMetadataForRegionOrCallingCode_(countryCode, regionCode);
3184   /** @type {string} */
3185   var possibleNumberPattern =
3186       metadata.getGeneralDesc().getPossibleNumberPatternOrDefault();
3187   return this.testNumberLengthAgainstPattern_(possibleNumberPattern,
3188                                               nationalNumber);
3189 };
3190
3191
3192 /**
3193  * Check whether a phone number is a possible number given a number in the form
3194  * of a string, and the region where the number could be dialed from. It
3195  * provides a more lenient check than {@link #isValidNumber}. See
3196  * {@link #isPossibleNumber} for details.
3197  *
3198  * <p>This method first parses the number, then invokes
3199  * {@link #isPossibleNumber} with the resultant PhoneNumber object.
3200  *
3201  * @param {string} number the number that needs to be checked, in the form of a
3202  *     string.
3203  * @param {string} regionDialingFrom the region that we are expecting the number
3204  *     to be dialed from.
3205  *     Note this is different from the region where the number belongs.
3206  *     For example, the number +1 650 253 0000 is a number that belongs to US.
3207  *     When written in this form, it can be dialed from any region. When it is
3208  *     written as 00 1 650 253 0000, it can be dialed from any region which uses
3209  *     an international dialling prefix of 00. When it is written as
3210  *     650 253 0000, it can only be dialed from within the US, and when written
3211  *     as 253 0000, it can only be dialed from within a smaller area in the US
3212  *     (Mountain View, CA, to be more specific).
3213  * @return {boolean} true if the number is possible.
3214  */
3215 i18n.phonenumbers.PhoneNumberUtil.prototype.isPossibleNumberString =
3216     function(number, regionDialingFrom) {
3217
3218   try {
3219     return this.isPossibleNumber(this.parse(number, regionDialingFrom));
3220   } catch (e) {
3221     return false;
3222   }
3223 };
3224
3225
3226 /**
3227  * Attempts to extract a valid number from a phone number that is too long to be
3228  * valid, and resets the PhoneNumber object passed in to that valid version. If
3229  * no valid number could be extracted, the PhoneNumber object passed in will not
3230  * be modified.
3231  * @param {i18n.phonenumbers.PhoneNumber} number a PhoneNumber object which
3232  *     contains a number that is too long to be valid.
3233  * @return {boolean} true if a valid phone number can be successfully extracted.
3234  */
3235 i18n.phonenumbers.PhoneNumberUtil.prototype.truncateTooLongNumber =
3236     function(number) {
3237
3238   if (this.isValidNumber(number)) {
3239     return true;
3240   }
3241   /** @type {i18n.phonenumbers.PhoneNumber} */
3242   var numberCopy = number.clone();
3243   /** @type {number} */
3244   var nationalNumber = number.getNationalNumberOrDefault();
3245   do {
3246     nationalNumber = Math.floor(nationalNumber / 10);
3247     numberCopy.setNationalNumber(nationalNumber);
3248     if (nationalNumber == 0 ||
3249         this.isPossibleNumberWithReason(numberCopy) ==
3250             i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_SHORT) {
3251       return false;
3252     }
3253   } while (!this.isValidNumber(numberCopy));
3254   number.setNationalNumber(nationalNumber);
3255   return true;
3256 };
3257
3258
3259 /**
3260  * Extracts country calling code from fullNumber, returns it and places the
3261  * remaining number in nationalNumber. It assumes that the leading plus sign or
3262  * IDD has already been removed. Returns 0 if fullNumber doesn't start with a
3263  * valid country calling code, and leaves nationalNumber unmodified.
3264  *
3265  * @param {!goog.string.StringBuffer} fullNumber
3266  * @param {!goog.string.StringBuffer} nationalNumber
3267  * @return {number}
3268  */
3269 i18n.phonenumbers.PhoneNumberUtil.prototype.extractCountryCode =
3270     function(fullNumber, nationalNumber) {
3271
3272   /** @type {string} */
3273   var fullNumberStr = fullNumber.toString();
3274   if ((fullNumberStr.length == 0) || (fullNumberStr.charAt(0) == '0')) {
3275     // Country codes do not begin with a '0'.
3276     return 0;
3277   }
3278   /** @type {number} */
3279   var potentialCountryCode;
3280   /** @type {number} */
3281   var numberLength = fullNumberStr.length;
3282   for (var i = 1;
3283       i <= i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_COUNTRY_CODE_ &&
3284       i <= numberLength; ++i) {
3285     potentialCountryCode = parseInt(fullNumberStr.substring(0, i), 10);
3286     if (potentialCountryCode in
3287         i18n.phonenumbers.metadata.countryCodeToRegionCodeMap) {
3288       nationalNumber.append(fullNumberStr.substring(i));
3289       return potentialCountryCode;
3290     }
3291   }
3292   return 0;
3293 };
3294
3295
3296 /**
3297  * Tries to extract a country calling code from a number. This method will
3298  * return zero if no country calling code is considered to be present. Country
3299  * calling codes are extracted in the following ways:
3300  * <ul>
3301  * <li>by stripping the international dialing prefix of the region the person is
3302  * dialing from, if this is present in the number, and looking at the next
3303  * digits
3304  * <li>by stripping the '+' sign if present and then looking at the next digits
3305  * <li>by comparing the start of the number and the country calling code of the
3306  * default region. If the number is not considered possible for the numbering
3307  * plan of the default region initially, but starts with the country calling
3308  * code of this region, validation will be reattempted after stripping this
3309  * country calling code. If this number is considered a possible number, then
3310  * the first digits will be considered the country calling code and removed as
3311  * such.
3312  * </ul>
3313  *
3314  * It will throw a i18n.phonenumbers.Error if the number starts with a '+' but
3315  * the country calling code supplied after this does not match that of any known
3316  * region.
3317  *
3318  * @param {string} number non-normalized telephone number that we wish to
3319  *     extract a country calling code from - may begin with '+'.
3320  * @param {i18n.phonenumbers.PhoneMetadata} defaultRegionMetadata metadata
3321  *     about the region this number may be from.
3322  * @param {!goog.string.StringBuffer} nationalNumber a string buffer to store
3323  *     the national significant number in, in the case that a country calling
3324  *     code was extracted. The number is appended to any existing contents. If
3325  *     no country calling code was extracted, this will be left unchanged.
3326  * @param {boolean} keepRawInput true if the country_code_source and
3327  *     preferred_carrier_code fields of phoneNumber should be populated.
3328  * @param {i18n.phonenumbers.PhoneNumber} phoneNumber the PhoneNumber object
3329  *     where the country_code and country_code_source need to be populated.
3330  *     Note the country_code is always populated, whereas country_code_source is
3331  *     only populated when keepCountryCodeSource is true.
3332  * @return {number} the country calling code extracted or 0 if none could be
3333  *     extracted.
3334  * @throws {i18n.phonenumbers.Error}
3335  */
3336 i18n.phonenumbers.PhoneNumberUtil.prototype.maybeExtractCountryCode =
3337     function(number, defaultRegionMetadata, nationalNumber,
3338              keepRawInput, phoneNumber) {
3339
3340   if (number.length == 0) {
3341     return 0;
3342   }
3343   /** @type {!goog.string.StringBuffer} */
3344   var fullNumber = new goog.string.StringBuffer(number);
3345   // Set the default prefix to be something that will never match.
3346   /** @type {?string} */
3347   var possibleCountryIddPrefix;
3348   if (defaultRegionMetadata != null) {
3349     possibleCountryIddPrefix = defaultRegionMetadata.getInternationalPrefix();
3350   }
3351   if (possibleCountryIddPrefix == null) {
3352     possibleCountryIddPrefix = 'NonMatch';
3353   }
3354
3355   /** @type {i18n.phonenumbers.PhoneNumber.CountryCodeSource} */
3356   var countryCodeSource = this.maybeStripInternationalPrefixAndNormalize(
3357       fullNumber, possibleCountryIddPrefix);
3358   if (keepRawInput) {
3359     phoneNumber.setCountryCodeSource(countryCodeSource);
3360   }
3361   if (countryCodeSource !=
3362       i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_DEFAULT_COUNTRY) {
3363     if (fullNumber.getLength() <=
3364         i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_) {
3365       throw i18n.phonenumbers.Error.TOO_SHORT_AFTER_IDD;
3366     }
3367     /** @type {number} */
3368     var potentialCountryCode = this.extractCountryCode(fullNumber,
3369                                                        nationalNumber);
3370     if (potentialCountryCode != 0) {
3371       phoneNumber.setCountryCode(potentialCountryCode);
3372       return potentialCountryCode;
3373     }
3374
3375     // If this fails, they must be using a strange country calling code that we
3376     // don't recognize, or that doesn't exist.
3377     throw i18n.phonenumbers.Error.INVALID_COUNTRY_CODE;
3378   } else if (defaultRegionMetadata != null) {
3379     // Check to see if the number starts with the country calling code for the
3380     // default region. If so, we remove the country calling code, and do some
3381     // checks on the validity of the number before and after.
3382     /** @type {number} */
3383     var defaultCountryCode = defaultRegionMetadata.getCountryCodeOrDefault();
3384     /** @type {string} */
3385     var defaultCountryCodeString = '' + defaultCountryCode;
3386     /** @type {string} */
3387     var normalizedNumber = fullNumber.toString();
3388     if (goog.string.startsWith(normalizedNumber, defaultCountryCodeString)) {
3389       /** @type {!goog.string.StringBuffer} */
3390       var potentialNationalNumber = new goog.string.StringBuffer(
3391           normalizedNumber.substring(defaultCountryCodeString.length));
3392       /** @type {i18n.phonenumbers.PhoneNumberDesc} */
3393       var generalDesc = defaultRegionMetadata.getGeneralDesc();
3394       /** @type {!RegExp} */
3395       var validNumberPattern =
3396           new RegExp(generalDesc.getNationalNumberPatternOrDefault());
3397       // Passing null since we don't need the carrier code.
3398       this.maybeStripNationalPrefixAndCarrierCode(
3399           potentialNationalNumber, defaultRegionMetadata, null);
3400       /** @type {string} */
3401       var potentialNationalNumberStr = potentialNationalNumber.toString();
3402       /** @type {string} */
3403       var possibleNumberPattern =
3404           generalDesc.getPossibleNumberPatternOrDefault();
3405       // If the number was not valid before but is valid now, or if it was too
3406       // long before, we consider the number with the country calling code
3407       // stripped to be a better result and keep that instead.
3408       if ((!i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
3409               validNumberPattern, fullNumber.toString()) &&
3410           i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
3411               validNumberPattern, potentialNationalNumberStr)) ||
3412           this.testNumberLengthAgainstPattern_(possibleNumberPattern,
3413                                                fullNumber.toString()) ==
3414               i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_LONG) {
3415         nationalNumber.append(potentialNationalNumberStr);
3416         if (keepRawInput) {
3417           phoneNumber.setCountryCodeSource(
3418               i18n.phonenumbers.PhoneNumber.CountryCodeSource
3419                   .FROM_NUMBER_WITHOUT_PLUS_SIGN);
3420         }
3421         phoneNumber.setCountryCode(defaultCountryCode);
3422         return defaultCountryCode;
3423       }
3424     }
3425   }
3426   // No country calling code present.
3427   phoneNumber.setCountryCode(0);
3428   return 0;
3429 };
3430
3431
3432 /**
3433  * Strips the IDD from the start of the number if present. Helper function used
3434  * by maybeStripInternationalPrefixAndNormalize.
3435  *
3436  * @param {!RegExp} iddPattern the regular expression for the international
3437  *     prefix.
3438  * @param {!goog.string.StringBuffer} number the phone number that we wish to
3439  *     strip any international dialing prefix from.
3440  * @return {boolean} true if an international prefix was present.
3441  * @private
3442  */
3443 i18n.phonenumbers.PhoneNumberUtil.prototype.parsePrefixAsIdd_ =
3444     function(iddPattern, number) {
3445
3446   /** @type {string} */
3447   var numberStr = number.toString();
3448   if (numberStr.search(iddPattern) == 0) {
3449     /** @type {number} */
3450     var matchEnd = numberStr.match(iddPattern)[0].length;
3451     /** @type {Array.<string>} */
3452     var matchedGroups = numberStr.substring(matchEnd).match(
3453         i18n.phonenumbers.PhoneNumberUtil.CAPTURING_DIGIT_PATTERN);
3454     if (matchedGroups && matchedGroups[1] != null &&
3455         matchedGroups[1].length > 0) {
3456       /** @type {string} */
3457       var normalizedGroup =
3458           i18n.phonenumbers.PhoneNumberUtil.normalizeDigitsOnly(
3459               matchedGroups[1]);
3460       if (normalizedGroup == '0') {
3461         return false;
3462       }
3463     }
3464     number.clear();
3465     number.append(numberStr.substring(matchEnd));
3466     return true;
3467   }
3468   return false;
3469 };
3470
3471
3472 /**
3473  * Strips any international prefix (such as +, 00, 011) present in the number
3474  * provided, normalizes the resulting number, and indicates if an international
3475  * prefix was present.
3476  *
3477  * @param {!goog.string.StringBuffer} number the non-normalized telephone number
3478  *     that we wish to strip any international dialing prefix from.
3479  * @param {string} possibleIddPrefix the international direct dialing prefix
3480  *     from the region we think this number may be dialed in.
3481  * @return {i18n.phonenumbers.PhoneNumber.CountryCodeSource} the corresponding
3482  *     CountryCodeSource if an international dialing prefix could be removed
3483  *     from the number, otherwise CountryCodeSource.FROM_DEFAULT_COUNTRY if
3484  *     the number did not seem to be in international format.
3485  */
3486 i18n.phonenumbers.PhoneNumberUtil.prototype.
3487     maybeStripInternationalPrefixAndNormalize = function(number,
3488                                                          possibleIddPrefix) {
3489   /** @type {string} */
3490   var numberStr = number.toString();
3491   if (numberStr.length == 0) {
3492     return i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_DEFAULT_COUNTRY;
3493   }
3494   // Check to see if the number begins with one or more plus signs.
3495   if (i18n.phonenumbers.PhoneNumberUtil.LEADING_PLUS_CHARS_PATTERN_
3496       .test(numberStr)) {
3497     numberStr = numberStr.replace(
3498         i18n.phonenumbers.PhoneNumberUtil.LEADING_PLUS_CHARS_PATTERN_, '');
3499     // Can now normalize the rest of the number since we've consumed the '+'
3500     // sign at the start.
3501     number.clear();
3502     number.append(i18n.phonenumbers.PhoneNumberUtil.normalize(numberStr));
3503     return i18n.phonenumbers.PhoneNumber.CountryCodeSource
3504         .FROM_NUMBER_WITH_PLUS_SIGN;
3505   }
3506   // Attempt to parse the first digits as an international prefix.
3507   /** @type {!RegExp} */
3508   var iddPattern = new RegExp(possibleIddPrefix);
3509   i18n.phonenumbers.PhoneNumberUtil.normalizeSB_(number);
3510   return this.parsePrefixAsIdd_(iddPattern, number) ?
3511       i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_IDD :
3512       i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_DEFAULT_COUNTRY;
3513 };
3514
3515
3516 /**
3517  * Strips any national prefix (such as 0, 1) present in the number provided.
3518  *
3519  * @param {!goog.string.StringBuffer} number the normalized telephone number
3520  *     that we wish to strip any national dialing prefix from.
3521  * @param {i18n.phonenumbers.PhoneMetadata} metadata the metadata for the
3522  *     region that we think this number is from.
3523  * @param {goog.string.StringBuffer} carrierCode a place to insert the carrier
3524  *     code if one is extracted.
3525  * @return {boolean} true if a national prefix or carrier code (or both) could
3526  *     be extracted.
3527  */
3528 i18n.phonenumbers.PhoneNumberUtil.prototype.
3529     maybeStripNationalPrefixAndCarrierCode = function(number, metadata,
3530                                                       carrierCode) {
3531   /** @type {string} */
3532   var numberStr = number.toString();
3533   /** @type {number} */
3534   var numberLength = numberStr.length;
3535   /** @type {?string} */
3536   var possibleNationalPrefix = metadata.getNationalPrefixForParsing();
3537   if (numberLength == 0 || possibleNationalPrefix == null ||
3538       possibleNationalPrefix.length == 0) {
3539     // Early return for numbers of zero length.
3540     return false;
3541   }
3542   // Attempt to parse the first digits as a national prefix.
3543   /** @type {!RegExp} */
3544   var prefixPattern = new RegExp('^(?:' + possibleNationalPrefix + ')');
3545   /** @type {Array.<string>} */
3546   var prefixMatcher = prefixPattern.exec(numberStr);
3547   if (prefixMatcher) {
3548     /** @type {!RegExp} */
3549     var nationalNumberRule = new RegExp(
3550         metadata.getGeneralDesc().getNationalNumberPatternOrDefault());
3551     // Check if the original number is viable.
3552     /** @type {boolean} */
3553     var isViableOriginalNumber =
3554         i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
3555             nationalNumberRule, numberStr);
3556     // prefixMatcher[numOfGroups] == null implies nothing was captured by the
3557     // capturing groups in possibleNationalPrefix; therefore, no transformation
3558     // is necessary, and we just remove the national prefix.
3559     /** @type {number} */
3560     var numOfGroups = prefixMatcher.length - 1;
3561     /** @type {?string} */
3562     var transformRule = metadata.getNationalPrefixTransformRule();
3563     /** @type {boolean} */
3564     var noTransform = transformRule == null || transformRule.length == 0 ||
3565                       prefixMatcher[numOfGroups] == null ||
3566                       prefixMatcher[numOfGroups].length == 0;
3567     if (noTransform) {
3568       // If the original number was viable, and the resultant number is not,
3569       // we return.
3570       if (isViableOriginalNumber &&
3571           !i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
3572               nationalNumberRule,
3573               numberStr.substring(prefixMatcher[0].length))) {
3574         return false;
3575       }
3576       if (carrierCode != null &&
3577           numOfGroups > 0 && prefixMatcher[numOfGroups] != null) {
3578         carrierCode.append(prefixMatcher[1]);
3579       }
3580       number.set(numberStr.substring(prefixMatcher[0].length));
3581       return true;
3582     } else {
3583       // Check that the resultant number is still viable. If not, return. Check
3584       // this by copying the string buffer and making the transformation on the
3585       // copy first.
3586       /** @type {string} */
3587       var transformedNumber;
3588       transformedNumber = numberStr.replace(prefixPattern, transformRule);
3589       if (isViableOriginalNumber &&
3590           !i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
3591               nationalNumberRule, transformedNumber)) {
3592         return false;
3593       }
3594       if (carrierCode != null && numOfGroups > 0) {
3595         carrierCode.append(prefixMatcher[1]);
3596       }
3597       number.set(transformedNumber);
3598       return true;
3599     }
3600   }
3601   return false;
3602 };
3603
3604
3605 /**
3606  * Strips any extension (as in, the part of the number dialled after the call is
3607  * connected, usually indicated with extn, ext, x or similar) from the end of
3608  * the number, and returns it.
3609  *
3610  * @param {!goog.string.StringBuffer} number the non-normalized telephone number
3611  *     that we wish to strip the extension from.
3612  * @return {string} the phone extension.
3613  */
3614 i18n.phonenumbers.PhoneNumberUtil.prototype.maybeStripExtension =
3615     function(number) {
3616
3617   /** @type {string} */
3618   var numberStr = number.toString();
3619   /** @type {number} */
3620   var mStart =
3621       numberStr.search(i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERN_);
3622   // If we find a potential extension, and the number preceding this is a viable
3623   // number, we assume it is an extension.
3624   if (mStart >= 0 && i18n.phonenumbers.PhoneNumberUtil.isViablePhoneNumber(
3625       numberStr.substring(0, mStart))) {
3626     // The numbers are captured into groups in the regular expression.
3627     /** @type {Array.<string>} */
3628     var matchedGroups =
3629         numberStr.match(i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERN_);
3630     /** @type {number} */
3631     var matchedGroupsLength = matchedGroups.length;
3632     for (var i = 1; i < matchedGroupsLength; ++i) {
3633       if (matchedGroups[i] != null && matchedGroups[i].length > 0) {
3634         // We go through the capturing groups until we find one that captured
3635         // some digits. If none did, then we will return the empty string.
3636         number.clear();
3637         number.append(numberStr.substring(0, mStart));
3638         return matchedGroups[i];
3639       }
3640     }
3641   }
3642   return '';
3643 };
3644
3645
3646 /**
3647  * Checks to see that the region code used is valid, or if it is not valid, that
3648  * the number to parse starts with a + symbol so that we can attempt to infer
3649  * the region from the number.
3650  * @param {string} numberToParse number that we are attempting to parse.
3651  * @param {?string} defaultRegion region that we are expecting the number to be
3652  *     from.
3653  * @return {boolean} false if it cannot use the region provided and the region
3654  *     cannot be inferred.
3655  * @private
3656  */
3657 i18n.phonenumbers.PhoneNumberUtil.prototype.checkRegionForParsing_ = function(
3658     numberToParse, defaultRegion) {
3659   // If the number is null or empty, we can't infer the region.
3660   return this.isValidRegionCode_(defaultRegion) ||
3661       (numberToParse != null && numberToParse.length > 0 &&
3662           i18n.phonenumbers.PhoneNumberUtil.LEADING_PLUS_CHARS_PATTERN_.test(
3663               numberToParse));
3664 };
3665
3666
3667 /**
3668  * Parses a string and returns it in proto buffer format. This method will throw
3669  * a {@link i18n.phonenumbers.Error} if the number is not considered to be a
3670  * possible number. Note that validation of whether the number is actually a
3671  * valid number for a particular region is not performed. This can be done
3672  * separately with {@link #isValidNumber}.
3673  *
3674  * @param {?string} numberToParse number that we are attempting to parse. This
3675  *     can contain formatting such as +, ( and -, as well as a phone number
3676  *     extension. It can also be provided in RFC3966 format.
3677  * @param {?string} defaultRegion region that we are expecting the number to be
3678  *     from. This is only used if the number being parsed is not written in
3679  *     international format. The country_code for the number in this case would
3680  *     be stored as that of the default region supplied. If the number is
3681  *     guaranteed to start with a '+' followed by the country calling code, then
3682  *     'ZZ' or null can be supplied.
3683  * @return {i18n.phonenumbers.PhoneNumber} a phone number proto buffer filled
3684  *     with the parsed number.
3685  * @throws {i18n.phonenumbers.Error} if the string is not considered to be a
3686  *     viable phone number or if no default region was supplied and the number
3687  *     is not in international format (does not start with +).
3688  */
3689 i18n.phonenumbers.PhoneNumberUtil.prototype.parse = function(numberToParse,
3690                                                              defaultRegion) {
3691   return this.parseHelper_(numberToParse, defaultRegion, false, true);
3692 };
3693
3694
3695 /**
3696  * Parses a string and returns it in proto buffer format. This method differs
3697  * from {@link #parse} in that it always populates the raw_input field of the
3698  * protocol buffer with numberToParse as well as the country_code_source field.
3699  *
3700  * @param {string} numberToParse number that we are attempting to parse. This
3701  *     can contain formatting such as +, ( and -, as well as a phone number
3702  *     extension.
3703  * @param {?string} defaultRegion region that we are expecting the number to be
3704  *     from. This is only used if the number being parsed is not written in
3705  *     international format. The country calling code for the number in this
3706  *     case would be stored as that of the default region supplied.
3707  * @return {i18n.phonenumbers.PhoneNumber} a phone number proto buffer filled
3708  *     with the parsed number.
3709  * @throws {i18n.phonenumbers.Error} if the string is not considered to be a
3710  *     viable phone number or if no default region was supplied.
3711  */
3712 i18n.phonenumbers.PhoneNumberUtil.prototype.parseAndKeepRawInput =
3713     function(numberToParse, defaultRegion) {
3714
3715   if (!this.isValidRegionCode_(defaultRegion)) {
3716     if (numberToParse.length > 0 && numberToParse.charAt(0) !=
3717         i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN) {
3718       throw i18n.phonenumbers.Error.INVALID_COUNTRY_CODE;
3719     }
3720   }
3721   return this.parseHelper_(numberToParse, defaultRegion, true, true);
3722 };
3723
3724
3725 /**
3726  * A helper function to set the values related to leading zeros in a
3727  * PhoneNumber.
3728  *
3729  * @param {string} nationalNumber the number we are parsing.
3730  * @param {i18n.phonenumbers.PhoneNumber} phoneNumber a phone number proto
3731  *     buffer to fill in.
3732  * @private
3733  */
3734 i18n.phonenumbers.PhoneNumberUtil.prototype.setItalianLeadingZerosForPhoneNumber_ =
3735     function(nationalNumber, phoneNumber) {
3736   if (nationalNumber.length > 1 && nationalNumber.charAt(0) == '0') {
3737     phoneNumber.setItalianLeadingZero(true);
3738     var numberOfLeadingZeros = 1;
3739     // Note that if the national number is all "0"s, the last "0" is not counted
3740     // as a leading zero.
3741     while (numberOfLeadingZeros < nationalNumber.length - 1 &&
3742            nationalNumber.charAt(numberOfLeadingZeros) == '0') {
3743       numberOfLeadingZeros++;
3744     }
3745     if (numberOfLeadingZeros != 1) {
3746       phoneNumber.setNumberOfLeadingZeros(numberOfLeadingZeros);
3747     }
3748   }
3749 };
3750
3751
3752 /**
3753  * Parses a string and returns it in proto buffer format. This method is the
3754  * same as the public {@link #parse} method, with the exception that it allows
3755  * the default region to be null, for use by {@link #isNumberMatch}.
3756  *
3757  * @param {?string} numberToParse number that we are attempting to parse. This
3758  *     can contain formatting such as +, ( and -, as well as a phone number
3759  *     extension.
3760  * @param {?string} defaultRegion region that we are expecting the number to be
3761  *     from. This is only used if the number being parsed is not written in
3762  *     international format. The country calling code for the number in this
3763  *     case would be stored as that of the default region supplied.
3764  * @param {boolean} keepRawInput whether to populate the raw_input field of the
3765  *     phoneNumber with numberToParse.
3766  * @param {boolean} checkRegion should be set to false if it is permitted for
3767  *     the default coregion to be null or unknown ('ZZ').
3768  * @return {i18n.phonenumbers.PhoneNumber} a phone number proto buffer filled
3769  *     with the parsed number.
3770  * @throws {i18n.phonenumbers.Error}
3771  * @private
3772  */
3773 i18n.phonenumbers.PhoneNumberUtil.prototype.parseHelper_ =
3774     function(numberToParse, defaultRegion, keepRawInput, checkRegion) {
3775
3776   if (numberToParse == null) {
3777     throw i18n.phonenumbers.Error.NOT_A_NUMBER;
3778   } else if (numberToParse.length >
3779       i18n.phonenumbers.PhoneNumberUtil.MAX_INPUT_STRING_LENGTH_) {
3780     throw i18n.phonenumbers.Error.TOO_LONG;
3781   }
3782
3783   /** @type {!goog.string.StringBuffer} */
3784   var nationalNumber = new goog.string.StringBuffer();
3785   this.buildNationalNumberForParsing_(numberToParse, nationalNumber);
3786
3787   if (!i18n.phonenumbers.PhoneNumberUtil.isViablePhoneNumber(
3788       nationalNumber.toString())) {
3789     throw i18n.phonenumbers.Error.NOT_A_NUMBER;
3790   }
3791
3792   // Check the region supplied is valid, or that the extracted number starts
3793   // with some sort of + sign so the number's region can be determined.
3794   if (checkRegion &&
3795       !this.checkRegionForParsing_(nationalNumber.toString(), defaultRegion)) {
3796     throw i18n.phonenumbers.Error.INVALID_COUNTRY_CODE;
3797   }
3798
3799   /** @type {i18n.phonenumbers.PhoneNumber} */
3800   var phoneNumber = new i18n.phonenumbers.PhoneNumber();
3801   if (keepRawInput) {
3802     phoneNumber.setRawInput(numberToParse);
3803   }
3804   // Attempt to parse extension first, since it doesn't require region-specific
3805   // data and we want to have the non-normalised number here.
3806   /** @type {string} */
3807   var extension = this.maybeStripExtension(nationalNumber);
3808   if (extension.length > 0) {
3809     phoneNumber.setExtension(extension);
3810   }
3811
3812   /** @type {i18n.phonenumbers.PhoneMetadata} */
3813   var regionMetadata = this.getMetadataForRegion(defaultRegion);
3814   // Check to see if the number is given in international format so we know
3815   // whether this number is from the default region or not.
3816   /** @type {!goog.string.StringBuffer} */
3817   var normalizedNationalNumber = new goog.string.StringBuffer();
3818   /** @type {number} */
3819   var countryCode = 0;
3820   /** @type {string} */
3821   var nationalNumberStr = nationalNumber.toString();
3822   try {
3823     countryCode = this.maybeExtractCountryCode(nationalNumberStr,
3824         regionMetadata, normalizedNationalNumber, keepRawInput, phoneNumber);
3825   } catch (e) {
3826     if (e == i18n.phonenumbers.Error.INVALID_COUNTRY_CODE &&
3827         i18n.phonenumbers.PhoneNumberUtil.LEADING_PLUS_CHARS_PATTERN_
3828             .test(nationalNumberStr)) {
3829       // Strip the plus-char, and try again.
3830       nationalNumberStr = nationalNumberStr.replace(
3831           i18n.phonenumbers.PhoneNumberUtil.LEADING_PLUS_CHARS_PATTERN_, '');
3832       countryCode = this.maybeExtractCountryCode(nationalNumberStr,
3833           regionMetadata, normalizedNationalNumber, keepRawInput, phoneNumber);
3834       if (countryCode == 0) {
3835         throw e;
3836       }
3837     } else {
3838       throw e;
3839     }
3840   }
3841   if (countryCode != 0) {
3842     /** @type {string} */
3843     var phoneNumberRegion = this.getRegionCodeForCountryCode(countryCode);
3844     if (phoneNumberRegion != defaultRegion) {
3845       // Metadata cannot be null because the country calling code is valid.
3846       regionMetadata = this.getMetadataForRegionOrCallingCode_(
3847           countryCode, phoneNumberRegion);
3848     }
3849   } else {
3850     // If no extracted country calling code, use the region supplied instead.
3851     // The national number is just the normalized version of the number we were
3852     // given to parse.
3853     i18n.phonenumbers.PhoneNumberUtil.normalizeSB_(nationalNumber);
3854     normalizedNationalNumber.append(nationalNumber.toString());
3855     if (defaultRegion != null) {
3856       countryCode = regionMetadata.getCountryCodeOrDefault();
3857       phoneNumber.setCountryCode(countryCode);
3858     } else if (keepRawInput) {
3859       phoneNumber.clearCountryCodeSource();
3860     }
3861   }
3862   if (normalizedNationalNumber.getLength() <
3863       i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_) {
3864     throw i18n.phonenumbers.Error.TOO_SHORT_NSN;
3865   }
3866
3867   if (regionMetadata != null) {
3868     /** @type {!goog.string.StringBuffer} */
3869     var carrierCode = new goog.string.StringBuffer();
3870     /** @type {!goog.string.StringBuffer} */
3871     var potentialNationalNumber =
3872         new goog.string.StringBuffer(normalizedNationalNumber.toString());
3873     this.maybeStripNationalPrefixAndCarrierCode(
3874         potentialNationalNumber, regionMetadata, carrierCode);
3875     if (!this.isShorterThanPossibleNormalNumber_(
3876             regionMetadata, potentialNationalNumber.toString())) {
3877       normalizedNationalNumber = potentialNationalNumber;
3878       if (keepRawInput) {
3879         phoneNumber.setPreferredDomesticCarrierCode(carrierCode.toString());
3880       }
3881     }
3882   }
3883   /** @type {string} */
3884   var normalizedNationalNumberStr = normalizedNationalNumber.toString();
3885   /** @type {number} */
3886   var lengthOfNationalNumber = normalizedNationalNumberStr.length;
3887   if (lengthOfNationalNumber <
3888       i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_) {
3889     throw i18n.phonenumbers.Error.TOO_SHORT_NSN;
3890   }
3891   if (lengthOfNationalNumber >
3892       i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_FOR_NSN_) {
3893     throw i18n.phonenumbers.Error.TOO_LONG;
3894   }
3895   this.setItalianLeadingZerosForPhoneNumber_(
3896       normalizedNationalNumberStr, phoneNumber);
3897   phoneNumber.setNationalNumber(parseInt(normalizedNationalNumberStr, 10));
3898   return phoneNumber;
3899 };
3900
3901
3902 /**
3903  * Converts numberToParse to a form that we can parse and write it to
3904  * nationalNumber if it is written in RFC3966; otherwise extract a possible
3905  * number out of it and write to nationalNumber.
3906  *
3907  * @param {?string} numberToParse number that we are attempting to parse. This
3908  *     can contain formatting such as +, ( and -, as well as a phone number
3909  *     extension.
3910  * @param {!goog.string.StringBuffer} nationalNumber a string buffer for storing
3911  *     the national significant number.
3912  * @private
3913  */
3914 i18n.phonenumbers.PhoneNumberUtil.prototype.buildNationalNumberForParsing_ =
3915     function(numberToParse, nationalNumber) {
3916
3917   /** @type {number} */
3918   var indexOfPhoneContext = numberToParse.indexOf(
3919       i18n.phonenumbers.PhoneNumberUtil.RFC3966_PHONE_CONTEXT_);
3920   if (indexOfPhoneContext > 0) {
3921     var phoneContextStart = indexOfPhoneContext +
3922         i18n.phonenumbers.PhoneNumberUtil.RFC3966_PHONE_CONTEXT_.length;
3923     // If the phone context contains a phone number prefix, we need to capture
3924     // it, whereas domains will be ignored.
3925     if (numberToParse.charAt(phoneContextStart) ==
3926         i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN) {
3927       // Additional parameters might follow the phone context. If so, we will
3928       // remove them here because the parameters after phone context are not
3929       // important for parsing the phone number.
3930       var phoneContextEnd = numberToParse.indexOf(';', phoneContextStart);
3931       if (phoneContextEnd > 0) {
3932         nationalNumber.append(numberToParse.substring(phoneContextStart,
3933             phoneContextEnd));
3934       } else {
3935         nationalNumber.append(numberToParse.substring(phoneContextStart));
3936       }
3937     }
3938
3939     // Now append everything between the "tel:" prefix and the phone-context.
3940     // This should include the national number, an optional extension or
3941     // isdn-subaddress component. Note we also handle the case when "tel:" is
3942     // missing, as we have seen in some of the phone number inputs.
3943     // In that case, we append everything from the beginning.
3944     var indexOfRfc3966Prefix = numberToParse.indexOf(
3945         i18n.phonenumbers.PhoneNumberUtil.RFC3966_PREFIX_);
3946     var indexOfNationalNumber = (indexOfRfc3966Prefix >= 0) ?
3947         indexOfRfc3966Prefix +
3948         i18n.phonenumbers.PhoneNumberUtil.RFC3966_PREFIX_.length : 0;
3949     nationalNumber.append(numberToParse.substring(indexOfNationalNumber,
3950         indexOfPhoneContext));
3951   } else {
3952     // Extract a possible number from the string passed in (this strips leading
3953     // characters that could not be the start of a phone number.)
3954     nationalNumber.append(
3955         i18n.phonenumbers.PhoneNumberUtil.extractPossibleNumber(numberToParse));
3956   }
3957
3958   // Delete the isdn-subaddress and everything after it if it is present.
3959   // Note extension won't appear at the same time with isdn-subaddress
3960   // according to paragraph 5.3 of the RFC3966 spec,
3961   /** @type {string} */
3962   var nationalNumberStr = nationalNumber.toString();
3963   var indexOfIsdn = nationalNumberStr.indexOf(
3964       i18n.phonenumbers.PhoneNumberUtil.RFC3966_ISDN_SUBADDRESS_);
3965   if (indexOfIsdn > 0) {
3966     nationalNumber.clear();
3967     nationalNumber.append(nationalNumberStr.substring(0, indexOfIsdn));
3968   }
3969   // If both phone context and isdn-subaddress are absent but other
3970   // parameters are present, the parameters are left in nationalNumber. This
3971   // is because we are concerned about deleting content from a potential
3972   // number string when there is no strong evidence that the number is
3973   // actually written in RFC3966.
3974 };
3975
3976
3977 /**
3978  * Takes two phone numbers and compares them for equality.
3979  *
3980  * <p>Returns EXACT_MATCH if the country_code, NSN, presence of a leading zero
3981  * for Italian numbers and any extension present are the same. Returns NSN_MATCH
3982  * if either or both has no region specified, and the NSNs and extensions are
3983  * the same. Returns SHORT_NSN_MATCH if either or both has no region specified,
3984  * or the region specified is the same, and one NSN could be a shorter version
3985  * of the other number. This includes the case where one has an extension
3986  * specified, and the other does not. Returns NO_MATCH otherwise. For example,
3987  * the numbers +1 345 657 1234 and 657 1234 are a SHORT_NSN_MATCH. The numbers
3988  * +1 345 657 1234 and 345 657 are a NO_MATCH.
3989  *
3990  * @param {i18n.phonenumbers.PhoneNumber|string} firstNumberIn first number to
3991  *     compare. If it is a string it can contain formatting, and can have
3992  *     country calling code specified with + at the start.
3993  * @param {i18n.phonenumbers.PhoneNumber|string} secondNumberIn second number to
3994  *     compare. If it is a string it can contain formatting, and can have
3995  *     country calling code specified with + at the start.
3996  * @return {i18n.phonenumbers.PhoneNumberUtil.MatchType} NOT_A_NUMBER, NO_MATCH,
3997  *     SHORT_NSN_MATCH, NSN_MATCH or EXACT_MATCH depending on the level of
3998  *     equality of the two numbers, described in the method definition.
3999  */
4000 i18n.phonenumbers.PhoneNumberUtil.prototype.isNumberMatch =
4001     function(firstNumberIn, secondNumberIn) {
4002
4003   // If the input arguements are strings parse them to a proto buffer format.
4004   // Else make copies of the phone numbers so that the numbers passed in are not
4005   // edited.
4006   /** @type {i18n.phonenumbers.PhoneNumber} */
4007   var firstNumber;
4008   /** @type {i18n.phonenumbers.PhoneNumber} */
4009   var secondNumber;
4010   if (typeof firstNumberIn == 'string') {
4011     // First see if the first number has an implicit country calling code, by
4012     // attempting to parse it.
4013     try {
4014       firstNumber = this.parse(
4015           firstNumberIn, i18n.phonenumbers.PhoneNumberUtil.UNKNOWN_REGION_);
4016     } catch (e) {
4017       if (e != i18n.phonenumbers.Error.INVALID_COUNTRY_CODE) {
4018         return i18n.phonenumbers.PhoneNumberUtil.MatchType.NOT_A_NUMBER;
4019       }
4020       // The first number has no country calling code. EXACT_MATCH is no longer
4021       // possible. We parse it as if the region was the same as that for the
4022       // second number, and if EXACT_MATCH is returned, we replace this with
4023       // NSN_MATCH.
4024       if (typeof secondNumberIn != 'string') {
4025         /** @type {string} */
4026         var secondNumberRegion = this.getRegionCodeForCountryCode(
4027             secondNumberIn.getCountryCodeOrDefault());
4028         if (secondNumberRegion !=
4029             i18n.phonenumbers.PhoneNumberUtil.UNKNOWN_REGION_) {
4030           try {
4031             firstNumber = this.parse(firstNumberIn, secondNumberRegion);
4032           } catch (e2) {
4033             return i18n.phonenumbers.PhoneNumberUtil.MatchType.NOT_A_NUMBER;
4034           }
4035           /** @type {i18n.phonenumbers.PhoneNumberUtil.MatchType} */
4036           var match = this.isNumberMatch(firstNumber, secondNumberIn);
4037           if (match ==
4038               i18n.phonenumbers.PhoneNumberUtil.MatchType.EXACT_MATCH) {
4039             return i18n.phonenumbers.PhoneNumberUtil.MatchType.NSN_MATCH;
4040           }
4041           return match;
4042         }
4043       }
4044       // If the second number is a string or doesn't have a valid country
4045       // calling code, we parse the first number without country calling code.
4046       try {
4047         firstNumber = this.parseHelper_(firstNumberIn, null, false, false);
4048       } catch (e2) {
4049         return i18n.phonenumbers.PhoneNumberUtil.MatchType.NOT_A_NUMBER;
4050       }
4051     }
4052   } else {
4053     firstNumber = firstNumberIn.clone();
4054   }
4055   if (typeof secondNumberIn == 'string') {
4056     try {
4057       secondNumber = this.parse(
4058           secondNumberIn, i18n.phonenumbers.PhoneNumberUtil.UNKNOWN_REGION_);
4059       return this.isNumberMatch(firstNumberIn, secondNumber);
4060     } catch (e) {
4061       if (e != i18n.phonenumbers.Error.INVALID_COUNTRY_CODE) {
4062         return i18n.phonenumbers.PhoneNumberUtil.MatchType.NOT_A_NUMBER;
4063       }
4064       return this.isNumberMatch(secondNumberIn, firstNumber);
4065     }
4066   } else {
4067     secondNumber = secondNumberIn.clone();
4068   }
4069   // First clear raw_input, country_code_source and
4070   // preferred_domestic_carrier_code fields and any empty-string extensions so
4071   // that we can use the proto-buffer equality method.
4072   firstNumber.clearRawInput();
4073   firstNumber.clearCountryCodeSource();
4074   firstNumber.clearPreferredDomesticCarrierCode();
4075   secondNumber.clearRawInput();
4076   secondNumber.clearCountryCodeSource();
4077   secondNumber.clearPreferredDomesticCarrierCode();
4078   if (firstNumber.hasExtension() && firstNumber.getExtension().length == 0) {
4079     firstNumber.clearExtension();
4080   }
4081   if (secondNumber.hasExtension() && secondNumber.getExtension().length == 0) {
4082     secondNumber.clearExtension();
4083   }
4084
4085   // Early exit if both had extensions and these are different.
4086   if (firstNumber.hasExtension() && secondNumber.hasExtension() &&
4087       firstNumber.getExtension() != secondNumber.getExtension()) {
4088     return i18n.phonenumbers.PhoneNumberUtil.MatchType.NO_MATCH;
4089   }
4090   /** @type {number} */
4091   var firstNumberCountryCode = firstNumber.getCountryCodeOrDefault();
4092   /** @type {number} */
4093   var secondNumberCountryCode = secondNumber.getCountryCodeOrDefault();
4094   // Both had country_code specified.
4095   if (firstNumberCountryCode != 0 && secondNumberCountryCode != 0) {
4096     if (firstNumber.equals(secondNumber)) {
4097       return i18n.phonenumbers.PhoneNumberUtil.MatchType.EXACT_MATCH;
4098     } else if (firstNumberCountryCode == secondNumberCountryCode &&
4099         this.isNationalNumberSuffixOfTheOther_(firstNumber, secondNumber)) {
4100       // A SHORT_NSN_MATCH occurs if there is a difference because of the
4101       // presence or absence of an 'Italian leading zero', the presence or
4102       // absence of an extension, or one NSN being a shorter variant of the
4103       // other.
4104       return i18n.phonenumbers.PhoneNumberUtil.MatchType.SHORT_NSN_MATCH;
4105     }
4106     // This is not a match.
4107     return i18n.phonenumbers.PhoneNumberUtil.MatchType.NO_MATCH;
4108   }
4109   // Checks cases where one or both country_code fields were not specified. To
4110   // make equality checks easier, we first set the country_code fields to be
4111   // equal.
4112   firstNumber.setCountryCode(0);
4113   secondNumber.setCountryCode(0);
4114   // If all else was the same, then this is an NSN_MATCH.
4115   if (firstNumber.equals(secondNumber)) {
4116     return i18n.phonenumbers.PhoneNumberUtil.MatchType.NSN_MATCH;
4117   }
4118   if (this.isNationalNumberSuffixOfTheOther_(firstNumber, secondNumber)) {
4119     return i18n.phonenumbers.PhoneNumberUtil.MatchType.SHORT_NSN_MATCH;
4120   }
4121   return i18n.phonenumbers.PhoneNumberUtil.MatchType.NO_MATCH;
4122 };
4123
4124
4125 /**
4126  * Returns true when one national number is the suffix of the other or both are
4127  * the same.
4128  *
4129  * @param {i18n.phonenumbers.PhoneNumber} firstNumber the first PhoneNumber
4130  *     object.
4131  * @param {i18n.phonenumbers.PhoneNumber} secondNumber the second PhoneNumber
4132  *     object.
4133  * @return {boolean} true if one PhoneNumber is the suffix of the other one.
4134  * @private
4135  */
4136 i18n.phonenumbers.PhoneNumberUtil.prototype.isNationalNumberSuffixOfTheOther_ =
4137     function(firstNumber, secondNumber) {
4138
4139   /** @type {string} */
4140   var firstNumberNationalNumber = '' + firstNumber.getNationalNumber();
4141   /** @type {string} */
4142   var secondNumberNationalNumber = '' + secondNumber.getNationalNumber();
4143   // Note that endsWith returns true if the numbers are equal.
4144   return goog.string.endsWith(firstNumberNationalNumber,
4145                               secondNumberNationalNumber) ||
4146          goog.string.endsWith(secondNumberNationalNumber,
4147                               firstNumberNationalNumber);
4148 };
4149
4150
4151 /**
4152  * Returns true if the number can be dialled from outside the region, or
4153  * unknown. If the number can only be dialled from within the region, returns
4154  * false. Does not check the number is a valid number.
4155  * TODO: Make this method public when we have enough metadata to make it
4156  * worthwhile. Currently visible for testing purposes only.
4157  *
4158  * @param {i18n.phonenumbers.PhoneNumber} number the phone-number for which we
4159  *     want to know whether it is diallable from outside the region.
4160  * @return {boolean} true if the number can only be dialled from within the
4161  *     country.
4162  */
4163 i18n.phonenumbers.PhoneNumberUtil.prototype.canBeInternationallyDialled =
4164     function(number) {
4165   /** @type {i18n.phonenumbers.PhoneMetadata} */
4166   var metadata = this.getMetadataForRegion(this.getRegionCodeForNumber(number));
4167   if (metadata == null) {
4168     // Note numbers belonging to non-geographical entities (e.g. +800 numbers)
4169     // are always internationally diallable, and will be caught here.
4170     return true;
4171   }
4172   /** @type {string} */
4173   var nationalSignificantNumber = this.getNationalSignificantNumber(number);
4174   return !this.isNumberMatchingDesc_(nationalSignificantNumber,
4175                                      metadata.getNoInternationalDialling());
4176 };
4177
4178
4179 /**
4180  * Check whether the entire input sequence can be matched against the regular
4181  * expression.
4182  *
4183  * @param {!RegExp|string} regex the regular expression to match against.
4184  * @param {string} str the string to test.
4185  * @return {boolean} true if str can be matched entirely against regex.
4186  * @private
4187  */
4188 i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_ = function(regex, str) {
4189   /** @type {Array.<string>} */
4190   var matchedGroups = (typeof regex == 'string') ?
4191       str.match('^(?:' + regex + ')$') : str.match(regex);
4192   if (matchedGroups && matchedGroups[0].length == str.length) {
4193     return true;
4194   }
4195   return false;
4196 };