Update JS code to revision 76. Patch contributed by tronikos.
[platform/upstream/libphonenumber.git] / javascript / i18n / phonenumbers / phonenumberutil.js
1 /*
2  * @license
3  * Copyright (C) 2010 Google Inc.
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  * @author Nikolaos Trogkanis
24  */
25
26 goog.provide('i18n.phonenumbers.PhoneNumberUtil');
27
28 goog.require('goog.array');
29 goog.require('goog.proto2.PbLiteSerializer');
30 goog.require('goog.string');
31 goog.require('goog.string.StringBuffer');
32 goog.require('i18n.phonenumbers.NumberFormat');
33 goog.require('i18n.phonenumbers.PhoneMetadata');
34 goog.require('i18n.phonenumbers.PhoneMetadataCollection');
35 goog.require('i18n.phonenumbers.PhoneNumber');
36 goog.require('i18n.phonenumbers.PhoneNumber.CountryCodeSource');
37 goog.require('i18n.phonenumbers.PhoneNumberDesc');
38 goog.require('i18n.phonenumbers.metadata');
39
40
41
42 /**
43  * @constructor
44  * @private
45  */
46 i18n.phonenumbers.PhoneNumberUtil = function() {
47   /**
48    * A mapping from a region code to the PhoneMetadata for that region.
49    * @type {Object.<string, i18n.phonenumbers.PhoneMetadata>}
50    */
51   this.countryToMetadata = {};
52 };
53 goog.addSingletonGetter(i18n.phonenumbers.PhoneNumberUtil);
54
55
56 /**
57  * Errors encountered when parsing phone numbers.
58  *
59  * @enum {string}
60  */
61 i18n.phonenumbers.Error = {
62   INVALID_COUNTRY_CODE: 'Invalid country code',
63   // This generally indicates the string passed in had less than 3 digits in it.
64   // More specifically, the number failed to match the regular expression
65   // VALID_PHONE_NUMBER.
66   NOT_A_NUMBER: 'The string supplied did not seem to be a phone number',
67   // This indicates the string started with an international dialing prefix, but
68   // after this was stripped from the number, had less digits than any valid
69   // phone number (including country code) could have.
70   TOO_SHORT_AFTER_IDD: 'Phone number too short after IDD',
71   // This indicates the string, after any country code has been stripped, had
72   // less digits than any
73   // valid phone number could have.
74   TOO_SHORT_NSN: 'The string supplied is too short to be a phone number',
75   // This indicates the string had more digits than any valid phone number could
76   // have.
77   TOO_LONG: 'The string supplied is too long to be a phone number'
78 };
79
80
81 /**
82  * @const
83  * @type {number}
84  * @private
85  */
86 i18n.phonenumbers.PhoneNumberUtil.NANPA_COUNTRY_CODE_ = 1;
87
88
89 /**
90  * The minimum length of the national significant number.
91  *
92  * @const
93  * @type {number}
94  * @private
95  */
96 i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_ = 3;
97
98
99 /**
100  * The maximum length of the national significant number.
101  *
102  * @const
103  * @type {number}
104  * @private
105  */
106 i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_FOR_NSN_ = 15;
107
108
109 /**
110  * The maximum length of the country code.
111  *
112  * @const
113  * @type {number}
114  * @private
115  */
116 i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_COUNTRY_CODE_ = 3;
117
118
119 /**
120  * Region-code for the unknown region.
121  *
122  * @const
123  * @type {string}
124  * @private
125  */
126 i18n.phonenumbers.PhoneNumberUtil.UNKNOWN_REGION_ = 'ZZ';
127
128
129 /**
130  * The PLUS_SIGN signifies the international prefix.
131  *
132  * @const
133  * @type {string}
134  */
135 i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN = '+';
136
137
138 /**
139  * These mappings map a character (key) to a specific digit that should replace
140  * it for normalization purposes. Non-European digits that may be used in phone
141  * numbers are mapped to a European equivalent.
142  *
143  * @const
144  */
145 i18n.phonenumbers.PhoneNumberUtil.DIGIT_MAPPINGS = {
146   '0': '0',
147   '1': '1',
148   '2': '2',
149   '3': '3',
150   '4': '4',
151   '5': '5',
152   '6': '6',
153   '7': '7',
154   '8': '8',
155   '9': '9',
156   '\uFF10': '0', // Fullwidth digit 0
157   '\uFF11': '1', // Fullwidth digit 1
158   '\uFF12': '2', // Fullwidth digit 2
159   '\uFF13': '3', // Fullwidth digit 3
160   '\uFF14': '4', // Fullwidth digit 4
161   '\uFF15': '5', // Fullwidth digit 5
162   '\uFF16': '6', // Fullwidth digit 6
163   '\uFF17': '7', // Fullwidth digit 7
164   '\uFF18': '8', // Fullwidth digit 8
165   '\uFF19': '9', // Fullwidth digit 9
166   '\u0660': '0', // Arabic-indic digit 0
167   '\u0661': '1', // Arabic-indic digit 1
168   '\u0662': '2', // Arabic-indic digit 2
169   '\u0663': '3', // Arabic-indic digit 3
170   '\u0664': '4', // Arabic-indic digit 4
171   '\u0665': '5', // Arabic-indic digit 5
172   '\u0666': '6', // Arabic-indic digit 6
173   '\u0667': '7', // Arabic-indic digit 7
174   '\u0668': '8', // Arabic-indic digit 8
175   '\u0669': '9', // Arabic-indic digit 9
176   '\u06F0': '0', // Eastern-Arabic digit 0
177   '\u06F1': '1', // Eastern-Arabic digit 1
178   '\u06F2': '2', // Eastern-Arabic digit 2
179   '\u06F3': '3', // Eastern-Arabic digit 3
180   '\u06F4': '4', // Eastern-Arabic digit 4
181   '\u06F5': '5', // Eastern-Arabic digit 5
182   '\u06F6': '6', // Eastern-Arabic digit 6
183   '\u06F7': '7', // Eastern-Arabic digit 7
184   '\u06F8': '8', // Eastern-Arabic digit 8
185   '\u06F9': '9'  // Eastern-Arabic digit 9
186 };
187
188
189 /**
190  * Only upper-case variants of alpha characters are stored.
191  *
192  * @const
193  * @private
194  */
195 i18n.phonenumbers.PhoneNumberUtil.ALPHA_MAPPINGS_ = {
196   'A': '2',
197   'B': '2',
198   'C': '2',
199   'D': '3',
200   'E': '3',
201   'F': '3',
202   'G': '4',
203   'H': '4',
204   'I': '4',
205   'J': '5',
206   'K': '5',
207   'L': '5',
208   'M': '6',
209   'N': '6',
210   'O': '6',
211   'P': '7',
212   'Q': '7',
213   'R': '7',
214   'S': '7',
215   'T': '8',
216   'U': '8',
217   'V': '8',
218   'W': '9',
219   'X': '9',
220   'Y': '9',
221   'Z': '9'
222 };
223
224
225 /**
226  * For performance reasons, amalgamate both into one map.
227  *
228  * @const
229  * @private
230  */
231 i18n.phonenumbers.PhoneNumberUtil.ALL_NORMALIZATION_MAPPINGS_ = {
232   '0': '0',
233   '1': '1',
234   '2': '2',
235   '3': '3',
236   '4': '4',
237   '5': '5',
238   '6': '6',
239   '7': '7',
240   '8': '8',
241   '9': '9',
242   '\uFF10': '0', // Fullwidth digit 0
243   '\uFF11': '1', // Fullwidth digit 1
244   '\uFF12': '2', // Fullwidth digit 2
245   '\uFF13': '3', // Fullwidth digit 3
246   '\uFF14': '4', // Fullwidth digit 4
247   '\uFF15': '5', // Fullwidth digit 5
248   '\uFF16': '6', // Fullwidth digit 6
249   '\uFF17': '7', // Fullwidth digit 7
250   '\uFF18': '8', // Fullwidth digit 8
251   '\uFF19': '9', // Fullwidth digit 9
252   '\u0660': '0', // Arabic-indic digit 0
253   '\u0661': '1', // Arabic-indic digit 1
254   '\u0662': '2', // Arabic-indic digit 2
255   '\u0663': '3', // Arabic-indic digit 3
256   '\u0664': '4', // Arabic-indic digit 4
257   '\u0665': '5', // Arabic-indic digit 5
258   '\u0666': '6', // Arabic-indic digit 6
259   '\u0667': '7', // Arabic-indic digit 7
260   '\u0668': '8', // Arabic-indic digit 8
261   '\u0669': '9', // Arabic-indic digit 9
262   '\u06F0': '0', // Eastern-Arabic digit 0
263   '\u06F1': '1', // Eastern-Arabic digit 1
264   '\u06F2': '2', // Eastern-Arabic digit 2
265   '\u06F3': '3', // Eastern-Arabic digit 3
266   '\u06F4': '4', // Eastern-Arabic digit 4
267   '\u06F5': '5', // Eastern-Arabic digit 5
268   '\u06F6': '6', // Eastern-Arabic digit 6
269   '\u06F7': '7', // Eastern-Arabic digit 7
270   '\u06F8': '8', // Eastern-Arabic digit 8
271   '\u06F9': '9', // Eastern-Arabic digit 9
272   'A': '2',
273   'B': '2',
274   'C': '2',
275   'D': '3',
276   'E': '3',
277   'F': '3',
278   'G': '4',
279   'H': '4',
280   'I': '4',
281   'J': '5',
282   'K': '5',
283   'L': '5',
284   'M': '6',
285   'N': '6',
286   'O': '6',
287   'P': '7',
288   'Q': '7',
289   'R': '7',
290   'S': '7',
291   'T': '8',
292   'U': '8',
293   'V': '8',
294   'W': '9',
295   'X': '9',
296   'Y': '9',
297   'Z': '9'
298 };
299
300
301 /**
302  * A list of all country codes where national significant numbers (excluding any
303  * national prefix) exist that start with a leading zero.
304  *
305  * @const
306  * @private
307  */
308 i18n.phonenumbers.PhoneNumberUtil.LEADING_ZERO_COUNTRIES_ = {
309   39: 1,  // Italy
310   47: 1,  // Norway
311   225: 1,  // Cote d'Ivoire
312   227: 1,  // Niger
313   228: 1,  // Togo
314   241: 1,  // Gabon
315   242: 1,  // Congo (Rep. of the)
316   268: 1,  // Swaziland
317   378: 1,  // San Marino
318   379: 1,  // Vatican City
319   501: 1   // Belize
320 };
321
322
323 /**
324  * Pattern that makes it easy to distinguish whether a country has a unique
325  * international dialing prefix or not. If a country has a unique international
326  * prefix (e.g. 011 in USA), it will be represented as a string that contains a
327  * sequence of ASCII digits. If there are multiple available international
328  * prefixes in a country, they will be represented as a regex string that always
329  * contains character(s) other than ASCII digits. Note this regex also includes
330  * tilde, which signals waiting for the tone.
331  *
332  * @const
333  * @type {RegExp}
334  * @private
335  */
336 i18n.phonenumbers.PhoneNumberUtil.UNIQUE_INTERNATIONAL_PREFIX_ =
337     /[\d]+(?:[~\u2053\u223C\uFF5E][\d]+)?/;
338
339
340 /**
341  * Regular expression of acceptable punctuation found in phone numbers. This
342  * excludes punctuation found as a leading character only. This consists of dash
343  * characters, white space characters, full stops, slashes, square brackets,
344  * parentheses and tildes. It also includes the letter 'x' as that is found as a
345  * placeholder for carrier information in some phone numbers.
346  *
347  * @const
348  * @type {string}
349  * @private
350  */
351 i18n.phonenumbers.PhoneNumberUtil.VALID_PUNCTUATION_ =
352     '-x\u2010-\u2015\u2212\u30FC\uFF0D-\uFF0F \u00A0\u200B\u2060\u3000()' +
353     '\uFF08\uFF09\uFF3B\uFF3D.\\[\\]/~\u2053\u223C\uFF5E';
354
355
356 /**
357  * Digits accepted in phone numbers (ascii, fullwidth, arabic-indic, and eastern
358  * arabic digits).
359  *
360  * @const
361  * @type {string}
362  * @private
363  */
364 i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ =
365     '0-9\uFF10-\uFF19\u0660-\u0669\u06F0-\u06F9';
366
367
368 /**
369  * We accept alpha characters in phone numbers, ASCII only, upper and lower
370  * case.
371  *
372  * @const
373  * @type {string}
374  * @private
375  */
376 i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_ = 'A-Za-z';
377
378
379 /**
380  * @const
381  * @type {string}
382  * @private
383  */
384 i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ = '+\uFF0B';
385
386
387 /**
388  * @const
389  * @type {RegExp}
390  * @private
391  */
392 i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_PATTERN_ =
393     new RegExp('^[' + i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ + ']+');
394
395
396 /**
397  * @const
398  * @type {RegExp}
399  * @private
400  */
401 i18n.phonenumbers.PhoneNumberUtil.CAPTURING_DIGIT_PATTERN_ =
402     new RegExp('([' + i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + '])');
403
404
405 /**
406  * Regular expression of acceptable characters that may start a phone number for
407  * the purposes of parsing. This allows us to strip away meaningless prefixes to
408  * phone numbers that may be mistakenly given to us. This consists of digits,
409  * the plus symbol and arabic-indic digits. This does not contain alpha
410  * characters, although they may be used later in the number. It also does not
411  * include other punctuation, as this will be stripped later during parsing and
412  * is of no information value when parsing a number.
413  *
414  * @const
415  * @type {RegExp}
416  * @protected
417  */
418 i18n.phonenumbers.PhoneNumberUtil.VALID_START_CHAR_PATTERN =
419     new RegExp('[' + i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ +
420                i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']');
421
422
423 /**
424  * Regular expression of characters typically used to start a second phone
425  * number for the purposes of parsing. This allows us to strip off parts of the
426  * number that are actually the start of another number, such as for:
427  * (530) 583-6985 x302/x2303 -> the second extension here makes this actually
428  * two phone numbers, (530) 583-6985 x302 and (530) 583-6985 x2303. We remove
429  * the second extension so that the first number is parsed correctly.
430  *
431  * @const
432  * @type {RegExp}
433  * @private
434  */
435 i18n.phonenumbers.PhoneNumberUtil.SECOND_NUMBER_START_PATTERN_ = /[\\\/] *x/;
436
437
438 /**
439  * Regular expression of trailing characters that we want to remove. We remove
440  * all characters that are not alpha or numerical characters. The hash character
441  * is retained here, as it may signify the previous block was an extension.
442  *
443  * @const
444  * @type {RegExp}
445  * @private
446  */
447 i18n.phonenumbers.PhoneNumberUtil.UNWANTED_END_CHAR_PATTERN_ =
448     new RegExp('[^' + i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ +
449                i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_ + '#]+$');
450
451
452 /**
453  * We use this pattern to check if the phone number has at least three letters
454  * in it - if so, then we treat it as a number where some phone-number digits
455  * are represented by letters.
456  *
457  * @const
458  * @type {RegExp}
459  * @private
460  */
461 i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_PHONE_PATTERN_ =
462     /(?:.*?[A-Za-z]){3}.*/;
463
464
465 /**
466  * Regular expression of viable phone numbers. This is location independent.
467  * Checks we have at least three leading digits, and only valid punctuation,
468  * alpha characters and digits in the phone number. Does not include extension
469  * data. The symbol 'x' is allowed here as valid punctuation since it is often
470  * used as a placeholder for carrier codes, for example in Brazilian phone
471  * numbers. We also allow multiple '+' characters at the start.
472  * Corresponds to the following:
473  * plus_sign*([punctuation]*[digits]){3,}([punctuation]|[digits]|[alpha])*
474  * Note VALID_PUNCTUATION starts with a -, so must be the first in the range.
475  *
476  * @const
477  * @type {string}
478  * @private
479  */
480 i18n.phonenumbers.PhoneNumberUtil.VALID_PHONE_NUMBER_ =
481     '[' + i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_ + ']*(?:[' +
482     i18n.phonenumbers.PhoneNumberUtil.VALID_PUNCTUATION_ + ']*[' +
483     i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']){3,}[' +
484     i18n.phonenumbers.PhoneNumberUtil.VALID_PUNCTUATION_ +
485     i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_ +
486     i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']*';
487
488
489 /**
490  * Default extension prefix to use when formatting. This will be put in front of
491  * any extension component of the number, after the main national number is
492  * formatted. For example, if you wish the default extension formatting to be
493  * ' extn: 3456', then you should specify ' extn: ' here as the default
494  * extension prefix. This can be overridden by country-specific preferences.
495  *
496  * @const
497  * @type {string}
498  * @private
499  */
500 i18n.phonenumbers.PhoneNumberUtil.DEFAULT_EXTN_PREFIX_ = ' ext. ';
501
502
503 /**
504  * Regexp of all possible ways to write extensions, for use when parsing. This
505  * will be run as a case-insensitive regexp match. Wide character versions are
506  * also provided after each ascii version. There are two regular expressions
507  * here: the more generic one starts with optional white space and ends with an
508  * optional full stop (.), followed by zero or more spaces/tabs and then the
509  * numbers themselves. The other one covers the special case of American numbers
510  * where the extension is written with a hash at the end, such as "- 503#". Note
511  * that the only capturing groups should be around the digits that you want to
512  * capture as part of the extension, or else parsing will fail! We allow two
513  * options for representing the accented o - the character itself, and one in
514  * the unicode decomposed form with the combining acute accent.
515  *
516  * @const
517  * @type {string}
518  * @private
519  */
520 i18n.phonenumbers.PhoneNumberUtil.KNOWN_EXTN_PATTERNS_ =
521     '[ \u00A0\\t,]*' +
522     '(?:ext(?:ensi(?:o\u0301?|\u00F3))?n?|\uFF45\uFF58\uFF54\uFF4E?|' +
523     '[,x\uFF58#\uFF03~\uFF5E]|int|anexo|\uFF49\uFF4E\uFF54)' +
524     '[:\\.\uFF0E]?[ \u00A0\\t,-]*([' +
525     i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']{1,7})#?|[- ]+([' +
526     i18n.phonenumbers.PhoneNumberUtil.VALID_DIGITS_ + ']{1,5})#';
527
528
529 /**
530  * Regexp of all known extension prefixes used by different countries followed
531  * by 1 or more valid digits, for use when parsing.
532  *
533  * @const
534  * @type {RegExp}
535  * @private
536  */
537 i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERN_ =
538     new RegExp('(?:' + i18n.phonenumbers.PhoneNumberUtil.KNOWN_EXTN_PATTERNS_ +
539                ')$', 'i');
540
541
542 /**
543  * We append optionally the extension pattern to the end here, as a valid phone
544  * number may have an extension prefix appended, followed by 1 or more digits.
545  *
546  * @const
547  * @type {RegExp}
548  * @private
549  */
550 i18n.phonenumbers.PhoneNumberUtil.VALID_PHONE_NUMBER_PATTERN_ =
551     new RegExp('^' + i18n.phonenumbers.PhoneNumberUtil.VALID_PHONE_NUMBER_ +
552                '(?:' + i18n.phonenumbers.PhoneNumberUtil.KNOWN_EXTN_PATTERNS_ +
553                ')?' + '$', 'i');
554
555
556 /**
557  * @const
558  * @type {RegExp}
559  * @private
560  */
561 i18n.phonenumbers.PhoneNumberUtil.NON_DIGITS_PATTERN_ = /\D+/;
562
563
564 /**
565  * @const
566  * @type {RegExp}
567  * @private
568  */
569 i18n.phonenumbers.PhoneNumberUtil.FIRST_GROUP_PATTERN_ = /(\$1)/;
570
571
572 /**
573  * @const
574  * @type {RegExp}
575  * @private
576  */
577 i18n.phonenumbers.PhoneNumberUtil.NP_PATTERN_ = /\$NP/;
578
579
580 /**
581  * @const
582  * @type {RegExp}
583  * @private
584  */
585 i18n.phonenumbers.PhoneNumberUtil.FG_PATTERN_ = /\$FG/;
586
587
588 /**
589  * @const
590  * @type {RegExp}
591  * @private
592  */
593 i18n.phonenumbers.PhoneNumberUtil.CC_PATTERN_ = /\$CC/;
594
595
596 /**
597  * INTERNATIONAL and NATIONAL formats are consistent with the definition in
598  * ITU-T Recommendation E. 123. For example, the number of the Google Zurich
599  * office will be written as "+41 44 668 1800" in INTERNATIONAL format, and as
600  * "044 668 1800" in NATIONAL format. E164 format is as per INTERNATIONAL format
601  * but with no formatting applied, e.g. +41446681800.
602  *
603  * @enum {number}
604  */
605 i18n.phonenumbers.PhoneNumberFormat = {
606   E164: 0,
607   INTERNATIONAL: 1,
608   NATIONAL: 2
609 };
610
611
612 /**
613  * Type of phone numbers.
614  *
615  * @enum {number}
616  */
617 i18n.phonenumbers.PhoneNumberType = {
618   FIXED_LINE: 0,
619   MOBILE: 1,
620   // In some countries (e.g. the USA), it is impossible to distinguish between
621   // fixed-line and mobile numbers by looking at the phone number itself.
622   FIXED_LINE_OR_MOBILE: 2,
623   // Freephone lines
624   TOLL_FREE: 3,
625   PREMIUM_RATE: 4,
626   // The cost of this call is shared between the caller and the recipient, and
627   // is hence typically less than PREMIUM_RATE calls. See
628   // http://en.wikipedia.org/wiki/Shared_Cost_Service for more information.
629   SHARED_COST: 5,
630   // Voice over IP numbers. This includes TSoIP (Telephony Service over IP).
631   VOIP: 6,
632   // A personal number is associated with a particular person, and may be routed
633   // to either a MOBILE or FIXED_LINE number. Some more information can be found
634   // here: http://en.wikipedia.org/wiki/Personal_Numbers
635   PERSONAL_NUMBER: 7,
636   PAGER: 8,
637   // Used for "Universal Access Numbers" or "Company Numbers". They may be
638   // further routed to specific offices, but allow one number to be used for a
639   // company.
640   UAN: 9,
641   // A phone number is of type UNKNOWN when it does not fit any of the known
642   // patterns for a specific country.
643   UNKNOWN: 10
644 };
645
646
647 /**
648  * Types of phone number matches. See detailed description beside the
649  * isNumberMatch() method.
650  *
651  * @enum {number}
652  */
653 i18n.phonenumbers.PhoneNumberUtil.MatchType = {
654   NOT_A_NUMBER: 0,
655   NO_MATCH: 1,
656   SHORT_NSN_MATCH: 2,
657   NSN_MATCH: 3,
658   EXACT_MATCH: 4
659 };
660
661
662 /**
663  * Possible outcomes when testing if a PhoneNumber is possible.
664  *
665  * @enum {number}
666  */
667 i18n.phonenumbers.PhoneNumberUtil.ValidationResult = {
668   IS_POSSIBLE: 0,
669   INVALID_COUNTRY_CODE: 1,
670   TOO_SHORT: 2,
671   TOO_LONG: 3
672 };
673
674
675 /**
676  * Attempts to extract a possible number from the string passed in. This
677  * currently strips all leading characters that could not be used to start a
678  * phone number. Characters that can be used to start a phone number are defined
679  * in the VALID_START_CHAR_PATTERN. If none of these characters are found in the
680  * number passed in, an empty string is returned. This function also attempts to
681  * strip off any alternative extensions or endings if two or more are present,
682  * such as in the case of: (530) 583-6985 x302/x2303. The second extension here
683  * makes this actually two phone numbers, (530) 583-6985 x302 and (530) 583-6985
684  * x2303. We remove the second extension so that the first number is parsed
685  * correctly.
686  *
687  * @param {string} number the string that might contain a phone number.
688  * @return {string} the number, stripped of any non-phone-number prefix (such as
689  *     'Tel:') or an empty string if no character used to start phone numbers
690  *     (such as + or any digit) is found in the number.
691  */
692 i18n.phonenumbers.PhoneNumberUtil.extractPossibleNumber = function(number) {
693   /** @type {string} */
694   var possibleNumber;
695
696   /** @type {number} */
697   var start = number
698       .search(i18n.phonenumbers.PhoneNumberUtil.VALID_START_CHAR_PATTERN);
699   if (start >= 0) {
700     possibleNumber = number.substring(start);
701     // Remove trailing non-alpha non-numerical characters.
702     possibleNumber = possibleNumber.replace(
703         i18n.phonenumbers.PhoneNumberUtil.UNWANTED_END_CHAR_PATTERN_, '');
704
705     // Check for extra numbers at the end.
706     /** @type {number} */
707     var secondNumberStart = possibleNumber
708         .search(i18n.phonenumbers.PhoneNumberUtil.SECOND_NUMBER_START_PATTERN_);
709     if (secondNumberStart >= 0) {
710       possibleNumber = possibleNumber.substring(0, secondNumberStart);
711     }
712   } else {
713     possibleNumber = '';
714   }
715   return possibleNumber;
716 };
717
718
719 /**
720  * Checks to see if the string of characters could possibly be a phone number at
721  * all. At the moment, checks to see that the string begins with at least 3
722  * digits, ignoring any punctuation commonly found in phone numbers. This method
723  * does not require the number to be normalized in advance - but does assume
724  * that leading non-number symbols have been removed, such as by the method
725  * extractPossibleNumber.
726  *
727  * @param {string} number string to be checked for viability as a phone number.
728  * @return {boolean} true if the number could be a phone number of some sort,
729  *     otherwise false.
730  */
731 i18n.phonenumbers.PhoneNumberUtil.isViablePhoneNumber = function(number) {
732   if (number.length < i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_) {
733     return false;
734   }
735   return i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
736       i18n.phonenumbers.PhoneNumberUtil.VALID_PHONE_NUMBER_PATTERN_, number);
737 };
738
739
740 /**
741  * Normalizes a string of characters representing a phone number. This performs
742  * the following conversions:
743  *  - Wide-ascii digits are converted to normal ASCII (European) digits.
744  *  - Letters are converted to their numeric representation on a telephone
745  * keypad. The keypad used here is the one defined in ITU Recommendation E.161.
746  * This is only done if there are 3 or more letters in the number, to lessen the
747  * risk that such letters are typos - otherwise alpha characters are stripped.
748  *  - Punctuation is stripped.
749  *  - Arabic-Indic numerals are converted to European numerals.
750  *
751  * @param {string} number a string of characters representing a phone number.
752  * @return {string} the normalized string version of the phone number.
753  */
754 i18n.phonenumbers.PhoneNumberUtil.normalize = function(number) {
755   if (i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
756       i18n.phonenumbers.PhoneNumberUtil.VALID_ALPHA_PHONE_PATTERN_, number)) {
757     return i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(number,
758         i18n.phonenumbers.PhoneNumberUtil.ALL_NORMALIZATION_MAPPINGS_, true);
759   } else {
760     return i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(number,
761         i18n.phonenumbers.PhoneNumberUtil.DIGIT_MAPPINGS, true);
762   }
763 };
764
765
766 /**
767  * Normalizes a string of characters representing a phone number. This is a
768  * wrapper for normalize(String number) but does in-place normalization of the
769  * StringBuffer provided.
770  *
771  * @param {!goog.string.StringBuffer} number a StringBuffer of characters
772  *     representing a phone number that will be normalized in place.
773  * @private
774  */
775 i18n.phonenumbers.PhoneNumberUtil.normalizeSB_ = function(number) {
776   /** @type {string} */
777   var normalizedNumber = i18n.phonenumbers.PhoneNumberUtil.normalize(number
778       .toString());
779   number.clear();
780   number.append(normalizedNumber);
781 };
782
783
784 /**
785  * Normalizes a string of characters representing a phone number. This converts
786  * wide-ascii and arabic-indic numerals to European numerals, and strips
787  * punctuation and alpha characters.
788  *
789  * @param {string} number a string of characters representing a phone number.
790  * @return {string} the normalized string version of the phone number.
791  */
792 i18n.phonenumbers.PhoneNumberUtil.normalizeDigitsOnly = function(number) {
793   return i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(number,
794       i18n.phonenumbers.PhoneNumberUtil.DIGIT_MAPPINGS, true);
795 };
796
797
798 /**
799  * Converts all alpha characters in a number to their respective digits on a
800  * keypad, but retains existing formatting. Also converts wide-ascii digits to
801  * normal ascii digits, and converts Arabic-Indic numerals to European numerals.
802  *
803  * @param {string} number a string of characters representing a phone number.
804  * @return {string} the normalized string version of the phone number.
805  */
806 i18n.phonenumbers.PhoneNumberUtil.convertAlphaCharactersInNumber =
807     function(number) {
808
809   return i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(number,
810       i18n.phonenumbers.PhoneNumberUtil.ALL_NORMALIZATION_MAPPINGS_, false);
811 };
812
813
814 /**
815  * Gets the length of the geographical area code from the national_number field
816  * of the PhoneNumber object passed in, so that clients could use it to split a
817  * national significant number into geographical area code and subscriber
818  * number. It works in such a way that the resultant subscriber number should be
819  * diallable, at least on some devices. An example of how this could be used:
820  *
821  * var phoneUtil = i18n.phonenumbers.PhoneNumberUtil.getInstance();
822  * var number = phoneUtil.parse('16502530000', 'US');
823  * var nationalSignificantNumber =
824  *     i18n.phonenumbers.PhoneNumberUtil.getNationalSignificantNumber(number);
825  * var areaCode;
826  * var subscriberNumber;
827  *
828  * var areaCodeLength = phoneUtil.getLengthOfGeographicalAreaCode(number);
829  * if (areaCodeLength > 0) {
830  *   areaCode = nationalSignificantNumber.substring(0, areaCodeLength);
831  *   subscriberNumber = nationalSignificantNumber.substring(areaCodeLength);
832  * } else {
833  *   areaCode = '';
834  *   subscriberNumber = nationalSignificantNumber;
835  * }
836  *
837  * N.B.: area code is a very ambiguous concept, so the I18N team generally
838  * recommends against using it for most purposes, but recommends using the more
839  * general national_number instead. Read the following carefully before deciding
840  * to use this method:
841  *  - geographical area codes change over time, and this method honors those
842  * changes; therefore, it doesn't guarantee the stability of the result it
843  * produces.
844  *  - subscriber numbers may not be diallable from all devices (notably mobile
845  * devices, which typically requires the full national_number to be dialled in
846  * most countries).
847  *  - most non-geographical numbers have no area codes.
848  *  - some geographical numbers have no area codes.
849  *
850  * @param {i18n.phonenumbers.PhoneNumber} number the PhoneNumber object for
851  *     which clients want to know the length of the area code in the
852  *     national_number field.
853  * @return {number} the length of area code of the PhoneNumber object passed in.
854  */
855 i18n.phonenumbers.PhoneNumberUtil.prototype.getLengthOfGeographicalAreaCode =
856     function(number) {
857
858   if (number == null) {
859     return 0;
860   }
861   /** @type {?string} */
862   var regionCode = this.getRegionCodeForNumber(number);
863   if (!this.isValidRegionCode_(regionCode)) {
864     return 0;
865   }
866   /** @type {i18n.phonenumbers.PhoneMetadata} */
867   var metadata = this.getMetadataForRegion(regionCode);
868   if (!metadata.hasNationalPrefix()) {
869     return 0;
870   }
871
872   /** @type {i18n.phonenumbers.PhoneNumberType} */
873   var type = this.getNumberTypeHelper_(
874       i18n.phonenumbers.PhoneNumberUtil.getNationalSignificantNumber(number),
875       metadata);
876   // Most numbers other than the two types below have to be dialled in full.
877   if (type != i18n.phonenumbers.PhoneNumberType.FIXED_LINE &&
878       type != i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE) {
879     return 0;
880   }
881
882   return this.getLengthOfNationalDestinationCode(number);
883 };
884
885
886 /**
887  * Gets the length of the national destination code (NDC) from the PhoneNumber
888  * object passed in, so that clients could use it to split a national
889  * significant number into NDC and subscriber number. The NDC of a phone number
890  * is normally the first group of digit(s) right after the country code when the
891  * number is formatted in the international format, if there is a subscriber
892  * number part that follows. An example of how this could be used:
893  *
894  * var phoneUtil = i18n.phonenumbers.PhoneNumberUtil.getInstance();
895  * var number = phoneUtil.parse('18002530000', 'US');
896  * var nationalSignificantNumber =
897  *     i18n.phonenumbers.PhoneNumberUtil.getNationalSignificantNumber(number);
898  * var nationalDestinationCode;
899  * var subscriberNumber;
900  *
901  * var nationalDestinationCodeLength =
902  *     phoneUtil.getLengthOfNationalDestinationCode(number);
903  * if (nationalDestinationCodeLength > 0) {
904  *   nationalDestinationCode =
905  *       nationalSignificantNumber.substring(0, nationalDestinationCodeLength);
906  *   subscriberNumber =
907  *       nationalSignificantNumber.substring(nationalDestinationCodeLength);
908  * } else {
909  *   nationalDestinationCode = '';
910  *   subscriberNumber = nationalSignificantNumber;
911  * }
912  *
913  * Refer to the unittests to see the difference between this function and
914  * getLengthOfGeographicalAreaCode().
915  *
916  * @param {i18n.phonenumbers.PhoneNumber} number the PhoneNumber object for
917  *     which clients want to know the length of the NDC.
918  * @return {number} the length of NDC of the PhoneNumber object passed in.
919  */
920 i18n.phonenumbers.PhoneNumberUtil.prototype.getLengthOfNationalDestinationCode =
921     function(number) {
922
923   /** @type {i18n.phonenumbers.PhoneNumber} */
924   var copiedProto;
925   if (number.hasExtension()) {
926     // We don't want to alter the proto given to us, but we don't want to
927     // include the extension when we format it, so we copy it and clear the
928     // extension here.
929     copiedProto = new i18n.phonenumbers.PhoneNumber();
930     copiedProto.mergeFrom(number);
931     copiedProto.clearExtension();
932   } else {
933     copiedProto = number;
934   }
935
936   /** @type {string} */
937   var nationalSignificantNumber = this.format(copiedProto,
938       i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL);
939   /** @type {!Array.<string>} */
940   var numberGroups = nationalSignificantNumber.split(
941       i18n.phonenumbers.PhoneNumberUtil.NON_DIGITS_PATTERN_);
942   // The pattern will start with '+COUNTRY_CODE ' so the first group will always
943   // be the empty string (before the + symbol) and the second group will be the
944   // country code. The third group will be area code if it's not the last group.
945   // NOTE: On IE the first group that is supposed to be the empty string does
946   // not appear in the array of number groups... so make the result on non-IE
947   // browsers to be that of IE.
948   if (numberGroups[0].length == 0) {
949     numberGroups.shift();
950   }
951   if (numberGroups.length <= 2) {
952     return 0;
953   }
954
955   if (this.getRegionCodeForNumber(number) == 'AR' &&
956       this.getNumberType(number) == i18n.phonenumbers.PhoneNumberType.MOBILE) {
957     // Argentinian mobile numbers, when formatted in the international format,
958     // are in the form of +54 9 NDC XXXX.... As a result, we take the length of
959     // the third group (NDC) and add 1 for the digit 9, which also forms part of
960     // the national significant number.
961     //
962     // TODO: Investigate the possibility of better modeling the metadata to make
963     // it easier to obtain the NDC.
964     return numberGroups[2].length + 1;
965   }
966   return numberGroups[1].length;
967 };
968
969
970 /**
971  * Normalizes a string of characters representing a phone number by replacing
972  * all characters found in the accompanying map with the values therein, and
973  * stripping all other characters if removeNonMatches is true.
974  *
975  * @param {string} number a string of characters representing a phone number.
976  * @param {!Object} normalizationReplacements a mapping of characters to what
977  *     they should be replaced by in the normalized version of the phone number.
978  * @param {boolean} removeNonMatches indicates whether characters that are not
979  *     able to be replaced should be stripped from the number. If this is false,
980  *     they will be left unchanged in the number.
981  * @return {string} the normalized string version of the phone number.
982  * @private
983  */
984 i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_ =
985     function(number, normalizationReplacements, removeNonMatches) {
986
987   /** @type {!goog.string.StringBuffer} */
988   var normalizedNumber = new goog.string.StringBuffer();
989   /** @type {string} */
990   var character;
991   /** @type {string} */
992   var newDigit;
993   /** @type {number} */
994   var numberLength = number.length;
995   for (var i = 0; i < numberLength; ++i) {
996     character = number.charAt(i);
997     newDigit = normalizationReplacements[character.toUpperCase()];
998     if (newDigit != null) {
999       normalizedNumber.append(newDigit);
1000     } else if (!removeNonMatches) {
1001       normalizedNumber.append(character);
1002     }
1003     // If neither of the above are true, we remove this character.
1004   }
1005   return normalizedNumber.toString();
1006 };
1007
1008
1009 /**
1010  * Helper function to check region code is not unknown or null.
1011  *
1012  * @param {?string} regionCode the ISO 3166-1 two-letter country code that
1013  *     denotes the country/region that we want to get the country code for.
1014  * @return {boolean} true if region code is valid.
1015  * @private
1016  */
1017 i18n.phonenumbers.PhoneNumberUtil.prototype.isValidRegionCode_ =
1018     function(regionCode) {
1019
1020   return regionCode != null &&
1021       regionCode.toUpperCase() in i18n.phonenumbers.metadata.countryToMetadata;
1022 };
1023
1024
1025 /**
1026  * Formats a phone number in the specified format using default rules. Note that
1027  * this does not promise to produce a phone number that the user can dial from
1028  * where they are - although we do format in either 'national' or
1029  * 'international' format depending on what the client asks for, we do not
1030  * currently support a more abbreviated format, such as for users in the same
1031  * "area" who could potentially dial the number without area code. Note that if
1032  * the phone number has a country code of 0 or an otherwise invalid country
1033  * code, we cannot work out which formatting rules to apply so we return the
1034  * national significant number with no formatting applied.
1035  *
1036  * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be
1037  *     formatted.
1038  * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
1039  *     phone number should be formatted into.
1040  * @return {string} the formatted phone number.
1041  */
1042 i18n.phonenumbers.PhoneNumberUtil.prototype.format =
1043     function(number, numberFormat) {
1044
1045   /** @type {number} */
1046   var countryCode = number.getCountryCodeOrDefault();
1047   /** @type {string} */
1048   var nationalSignificantNumber = i18n.phonenumbers.PhoneNumberUtil
1049       .getNationalSignificantNumber(number);
1050   if (numberFormat == i18n.phonenumbers.PhoneNumberFormat.E164) {
1051     // Early exit for E164 case since no formatting of the national number needs
1052     // to be applied. Extensions are not formatted.
1053     return this.formatNumberByFormat_(countryCode,
1054                                       i18n.phonenumbers.PhoneNumberFormat.E164,
1055                                       nationalSignificantNumber, '');
1056   }
1057   // Note getRegionCodeForCountryCode() is used because formatting information
1058   // for countries which share a country code is contained by only one country
1059   // for performance reasons. For example, for NANPA countries it will be
1060   // contained in the metadata for US.
1061   /** @type {string} */
1062   var regionCode = this.getRegionCodeForCountryCode(countryCode);
1063   if (!this.isValidRegionCode_(regionCode)) {
1064     return nationalSignificantNumber;
1065   }
1066
1067   /** @type {string} */
1068   var formattedExtension = this.maybeGetFormattedExtension_(number, regionCode);
1069   /** @type {string} */
1070   var formattedNationalNumber =
1071       this.formatNationalNumber_(nationalSignificantNumber,
1072                                  regionCode,
1073                                  numberFormat);
1074   return this.formatNumberByFormat_(countryCode,
1075                                     numberFormat,
1076                                     formattedNationalNumber,
1077                                     formattedExtension);
1078 };
1079
1080
1081 /**
1082  * Formats a phone number in the specified format using client-defined
1083  * formatting rules. Note that if the phone number has a country code of zero or
1084  * an otherwise invalid country code, we cannot work out things like whether
1085  * there should be a national prefix applied, or how to format extensions, so we
1086  * return the national significant number with no formatting applied.
1087  *
1088  * @param {i18n.phonenumbers.PhoneNumber} number the phone  number to be
1089  *     formatted.
1090  * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
1091  *     phone number should be formatted into.
1092  * @param {Array.<i18n.phonenumbers.NumberFormat>} userDefinedFormats formatting
1093  *     rules specified by clients.
1094  * @return {string} the formatted phone number.
1095  */
1096 i18n.phonenumbers.PhoneNumberUtil.prototype.formatByPattern =
1097     function(number, numberFormat, userDefinedFormats) {
1098
1099   /** @type {number} */
1100   var countryCode = number.getCountryCodeOrDefault();
1101   /** @type {string} */
1102   var nationalSignificantNumber =
1103       i18n.phonenumbers.PhoneNumberUtil.getNationalSignificantNumber(number);
1104   // Note getRegionCodeForCountryCode() is used because formatting information
1105   // for countries which share a country code is contained by only one country
1106   // for performance reasons. For example, for NANPA countries it will be
1107   // contained in the metadata for US.
1108   /** @type {string} */
1109   var regionCode = this.getRegionCodeForCountryCode(countryCode);
1110   if (!this.isValidRegionCode_(regionCode)) {
1111     return nationalSignificantNumber;
1112   }
1113   /** @type {Array.<i18n.phonenumbers.NumberFormat>} */
1114   var userDefinedFormatsCopy = [];
1115   /** @type {number} */
1116   var size = userDefinedFormats.length;
1117   for (var i = 0; i < size; ++i) {
1118     /** @type {i18n.phonenumbers.NumberFormat} */
1119     var numFormat = userDefinedFormats[i];
1120     /** @type {string} */
1121     var nationalPrefixFormattingRule =
1122         numFormat.getNationalPrefixFormattingRuleOrDefault();
1123     if (nationalPrefixFormattingRule.length > 0) {
1124       // Before we do a replacement of the national prefix pattern $NP with the
1125       // national prefix, we need to copy the rule so that subsequent
1126       // replacements for different numbers have the appropriate national
1127       // prefix.
1128       /** type {i18n.phonenumbers.NumberFormat} */
1129       var numFormatCopy = new i18n.phonenumbers.NumberFormat();
1130       numFormatCopy.mergeFrom(numFormat);
1131       /** @type {string} */
1132       var nationalPrefix =
1133           this.getMetadataForRegion(regionCode).getNationalPrefixOrDefault();
1134       if (nationalPrefix.length > 0) {
1135         // Replace $NP with national prefix and $FG with the first group ($1).
1136         nationalPrefixFormattingRule = nationalPrefixFormattingRule
1137             .replace(i18n.phonenumbers.PhoneNumberUtil.NP_PATTERN_,
1138                      nationalPrefix)
1139             .replace(i18n.phonenumbers.PhoneNumberUtil.FG_PATTERN_, '$1');
1140         numFormatCopy.setNationalPrefixFormattingRule(
1141             nationalPrefixFormattingRule);
1142       } else {
1143         // We don't want to have a rule for how to format the national prefix if
1144         // there isn't one.
1145         numFormatCopy.clearNationalPrefixFormattingRule();
1146       }
1147       userDefinedFormatsCopy.push(numFormatCopy);
1148     } else {
1149       // Otherwise, we just add the original rule to the modified list of
1150       // formats.
1151       userDefinedFormatsCopy.push(numFormat);
1152     }
1153   }
1154
1155   /** @type {string} */
1156   var formattedExtension = this.maybeGetFormattedExtension_(number, regionCode);
1157   /** @type {string} */
1158   var formattedNationalNumber =
1159       this.formatAccordingToFormats_(nationalSignificantNumber,
1160                                      userDefinedFormatsCopy,
1161                                      numberFormat);
1162   return this.formatNumberByFormat_(countryCode,
1163                                     numberFormat,
1164                                     formattedNationalNumber,
1165                                     formattedExtension);
1166 };
1167
1168
1169 /**
1170  * @param {i18n.phonenumbers.PhoneNumber} number
1171  * @param {string} carrierCode
1172  * @return {string}
1173  */
1174 i18n.phonenumbers.PhoneNumberUtil.prototype.
1175     formatNationalNumberWithCarrierCode = function(number, carrierCode) {
1176
1177   /** @type {number} */
1178   var countryCode = number.getCountryCodeOrDefault();
1179   /** @type {string} */
1180   var nationalSignificantNumber =
1181       i18n.phonenumbers.PhoneNumberUtil.getNationalSignificantNumber(number);
1182   // Note getRegionCodeForCountryCode() is used because formatting information
1183   // for countries which share a country code is contained by only one country
1184   // for performance reasons. For example, for NANPA countries it will be
1185   // contained in the metadata for US.
1186   /** @type {string} */
1187   var regionCode = this.getRegionCodeForCountryCode(countryCode);
1188   if (!this.isValidRegionCode_(regionCode)) {
1189     return nationalSignificantNumber;
1190   }
1191
1192   /** @type {string} */
1193   var formattedExtension = this.maybeGetFormattedExtension_(number, regionCode);
1194   /** @type {string} */
1195   var formattedNationalNumber =
1196       this.formatNationalNumber_(nationalSignificantNumber,
1197                                  regionCode,
1198                                  i18n.phonenumbers.PhoneNumberFormat.NATIONAL,
1199                                  carrierCode);
1200   return this.formatNumberByFormat_(
1201       countryCode, i18n.phonenumbers.PhoneNumberFormat.NATIONAL,
1202       formattedNationalNumber, formattedExtension);
1203 };
1204
1205
1206 /**
1207  * Formats a phone number for out-of-country dialing purpose. If no
1208  * countryCallingFrom is supplied, we format the number in its INTERNATIONAL
1209  * format. If the countryCallingFrom is the same as the country where the number
1210  * is from, then NATIONAL formatting will be applied.
1211  *
1212  * If the number itself has a country code of zero or an otherwise invalid
1213  * country code, then we return the number with no formatting applied.
1214  *
1215  * Note this function takes care of the case for calling inside of NANPA and
1216  * between Russia and Kazakhstan (who share the same country code). In those
1217  * cases, no international prefix is used. For countries which have multiple
1218  * international prefixes, the number in its INTERNATIONAL format will be
1219  * returned instead.
1220  *
1221  * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be
1222  *     formatted.
1223  * @param {string} countryCallingFrom the ISO 3166-1 two-letter country code
1224  *     that denotes the foreign country where the call is being placed.
1225  * @return {string} the formatted phone number.
1226  */
1227 i18n.phonenumbers.PhoneNumberUtil.prototype.formatOutOfCountryCallingNumber =
1228     function(number, countryCallingFrom) {
1229
1230   if (!this.isValidRegionCode_(countryCallingFrom)) {
1231     return this.format(number,
1232                        i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL);
1233   }
1234   /** @type {number} */
1235   var countryCode = number.getCountryCodeOrDefault();
1236   /** @type {string} */
1237   var regionCode = this.getRegionCodeForCountryCode(countryCode);
1238   /** @type {string} */
1239   var nationalSignificantNumber =
1240       i18n.phonenumbers.PhoneNumberUtil.getNationalSignificantNumber(number);
1241   if (!this.isValidRegionCode_(regionCode)) {
1242     return nationalSignificantNumber;
1243   }
1244   if (countryCode == i18n.phonenumbers.PhoneNumberUtil.NANPA_COUNTRY_CODE_) {
1245     if (this.isNANPACountry(countryCallingFrom)) {
1246       // For NANPA countries, return the national format for these countries but
1247       // prefix it with the country code.
1248       return countryCode + ' ' +
1249           this.format(number, i18n.phonenumbers.PhoneNumberFormat.NATIONAL);
1250     }
1251   } else if (countryCode == this.getCountryCodeForRegion(countryCallingFrom)) {
1252     // For countries that share a country calling code, the country code need
1253     // not be dialled. This also applies when dialling within a country, so this
1254     // if clause covers both these cases. Technically this is the case for
1255     // dialling from la Reunion to other overseas departments of France (French
1256     // Guiana, Martinique, Guadeloupe), but not vice versa - so we don't cover
1257     // this edge case for now and for those cases return the version including
1258     // country code. Details here:
1259     // http://www.petitfute.com/voyage/225-info-pratiques-reunion
1260     return this.format(number,
1261                        i18n.phonenumbers.PhoneNumberFormat.NATIONAL);
1262   }
1263   /** @type {string} */
1264   var formattedNationalNumber =
1265       this.formatNationalNumber_(nationalSignificantNumber, regionCode,
1266           i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL);
1267   /** @type {i18n.phonenumbers.PhoneMetadata} */
1268   var metadata = this.getMetadataForRegion(countryCallingFrom);
1269   /** @type {string} */
1270   var internationalPrefix = metadata.getInternationalPrefixOrDefault();
1271   /** @type {string} */
1272   var formattedExtension = this.maybeGetFormattedExtension_(number, regionCode);
1273
1274   // For countries that have multiple international prefixes, the international
1275   // format of the number is returned, unless there is a preferred international
1276   // prefix.
1277   /** @type {string} */
1278   var internationalPrefixForFormatting = '';
1279   if (i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
1280       i18n.phonenumbers.PhoneNumberUtil.UNIQUE_INTERNATIONAL_PREFIX_,
1281       internationalPrefix)) {
1282     internationalPrefixForFormatting = internationalPrefix;
1283   } else if (metadata.hasPreferredInternationalPrefix()) {
1284     internationalPrefixForFormatting =
1285         metadata.getPreferredInternationalPrefixOrDefault();
1286   }
1287
1288   return internationalPrefixForFormatting != '' ?
1289       internationalPrefixForFormatting + ' ' + countryCode + ' ' +
1290           formattedNationalNumber + formattedExtension :
1291       this.formatNumberByFormat_(
1292           countryCode, i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL,
1293           formattedNationalNumber, formattedExtension);
1294 };
1295
1296
1297 /**
1298  * Formats a phone number using the original phone number format that the number
1299  * is parsed from. The original format is embedded in the country_code_source
1300  * field of the PhoneNumber object passed in. If such information is missing,
1301  * the number will be formatted into the NATIONAL format by default.
1302  *
1303  * @param {i18n.phonenumbers.PhoneNumber} number the PhoneNumber that needs to
1304  *     be formatted in its original number format.
1305  * @param {string} countryCallingFrom the country whose IDD needs to be prefixed
1306  *     if the original number has one.
1307  * @return {string} the formatted phone number in its original number format.
1308  */
1309 i18n.phonenumbers.PhoneNumberUtil.prototype.formatInOriginalFormat =
1310     function(number, countryCallingFrom) {
1311
1312   if (!number.hasCountryCodeSource()) {
1313     return this.format(number, i18n.phonenumbers.PhoneNumberFormat.NATIONAL);
1314   }
1315   switch (number.getCountryCodeSource()) {
1316     case i18n.phonenumbers.PhoneNumber.CountryCodeSource
1317         .FROM_NUMBER_WITH_PLUS_SIGN:
1318       return this.format(number,
1319           i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL);
1320     case i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_IDD:
1321       return this.formatOutOfCountryCallingNumber(number, countryCallingFrom);
1322     case i18n.phonenumbers.PhoneNumber.CountryCodeSource
1323         .FROM_NUMBER_WITHOUT_PLUS_SIGN:
1324       return this.format(number,
1325           i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL).substring(1);
1326     case i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_DEFAULT_COUNTRY:
1327     default:
1328       return this.format(number, i18n.phonenumbers.PhoneNumberFormat.NATIONAL);
1329   }
1330 };
1331
1332
1333 /**
1334  * Gets the national significant number of the a phone number. Note a national
1335  * significant number doesn't contain a national prefix or any formatting.
1336  *
1337  * @param {i18n.phonenumbers.PhoneNumber} number the PhoneNumber object for
1338  *     which the national significant number is needed.
1339  * @return {string} the national significant number of the PhoneNumber object
1340  *     passed in.
1341  */
1342 i18n.phonenumbers.PhoneNumberUtil.getNationalSignificantNumber =
1343     function(number) {
1344
1345   // The leading zero in the national (significant) number of an Italian phone
1346   // number has a special meaning. Unlike the rest of the world, it indicates
1347   // the number is a landline number. There have been plans to migrate landline
1348   // numbers to start with the digit two since December 2000, but it has not yet
1349   // happened. See http://en.wikipedia.org/wiki/%2B39 for more details.
1350   // Other countries such as Cote d'Ivoire and Gabon use this for their mobile
1351   // numbers.
1352   /** @type {string} */
1353   var nationalNumber = '' + number.getNationalNumber();
1354   if (number.hasItalianLeadingZero() && number.getItalianLeadingZero() &&
1355       i18n.phonenumbers.PhoneNumberUtil.isLeadingZeroCountry(
1356           number.getCountryCodeOrDefault())) {
1357     return '0' + nationalNumber;
1358   }
1359   return nationalNumber;
1360 };
1361
1362
1363 /**
1364  * A helper function that is used by format and formatByPattern.
1365  *
1366  * @param {number} countryCode the country calling code.
1367  * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
1368  *     phone number should be formatted into.
1369  * @param {string} formattedNationalNumber
1370  * @param {string} formattedExtension
1371  * @return {string} the formatted phone number.
1372  * @private
1373  */
1374 i18n.phonenumbers.PhoneNumberUtil.prototype.formatNumberByFormat_ =
1375     function(countryCode, numberFormat,
1376              formattedNationalNumber, formattedExtension) {
1377
1378   switch (numberFormat) {
1379     case i18n.phonenumbers.PhoneNumberFormat.E164:
1380       return i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN + countryCode +
1381           formattedNationalNumber + formattedExtension;
1382     case i18n.phonenumbers.PhoneNumberFormat.INTERNATIONAL:
1383       return i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN + countryCode + ' ' +
1384           formattedNationalNumber + formattedExtension;
1385     case i18n.phonenumbers.PhoneNumberFormat.NATIONAL:
1386     default:
1387       return formattedNationalNumber + formattedExtension;
1388   }
1389 };
1390
1391
1392 /**
1393  * Note in some countries, the national number can be written in two completely
1394  * different ways depending on whether it forms part of the NATIONAL format or
1395  * INTERNATIONAL format. The numberFormat parameter here is used to specify
1396  * which format to use for those cases. If a carrierCode is specified, this will
1397  * be inserted into the formatted string to replace $CC.
1398  *
1399  * @param {string} number a string of characters representing a phone number.
1400  * @param {string} regionCode the ISO 3166-1 two-letter country code.
1401  * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
1402  *     phone number should be formatted into.
1403  * @param {string=} opt_carrierCode
1404  * @return {string} the formatted phone number.
1405  * @private
1406  */
1407 i18n.phonenumbers.PhoneNumberUtil.prototype.formatNationalNumber_ =
1408     function(number, regionCode, numberFormat, opt_carrierCode) {
1409
1410   /** @type {i18n.phonenumbers.PhoneMetadata} */
1411   var metadata = this.getMetadataForRegion(regionCode);
1412   /** @type {Array.<i18n.phonenumbers.NumberFormat>} */
1413   var intlNumberFormats = metadata.intlNumberFormatArray();
1414   // When the intlNumberFormats exists, we use that to format national number
1415   // for the INTERNATIONAL format instead of using the numberDesc.numberFormats.
1416   /** @type {Array.<i18n.phonenumbers.NumberFormat>} */
1417   var availableFormats =
1418       (intlNumberFormats.length == 0 ||
1419           numberFormat == i18n.phonenumbers.PhoneNumberFormat.NATIONAL) ?
1420       metadata.numberFormatArray() : metadata.intlNumberFormatArray();
1421   return this.formatAccordingToFormats_(number, availableFormats, numberFormat,
1422                                         opt_carrierCode);
1423 };
1424
1425
1426 /**
1427  * Note that carrierCode is optional - if NULL or an empty string, no carrier
1428  * code replacement will take place. Carrier code replacement occurs before
1429  * national prefix replacement.
1430  *
1431  * @param {string} nationalNumber a string of characters representing a phone
1432  *     number.
1433  * @param {Array.<i18n.phonenumbers.NumberFormat>} availableFormats the
1434  *     available formats the phone number could be formatted into.
1435  * @param {i18n.phonenumbers.PhoneNumberFormat} numberFormat the format the
1436  *     phone number should be formatted into.
1437  * @param {string=} opt_carrierCode
1438  * @return {string} the formatted phone number.
1439  * @private
1440  */
1441 i18n.phonenumbers.PhoneNumberUtil.prototype.formatAccordingToFormats_ =
1442     function(nationalNumber, availableFormats, numberFormat, opt_carrierCode) {
1443
1444   /** @type {i18n.phonenumbers.NumberFormat} */
1445   var numFormat;
1446   /** @type {number} */
1447   var l = availableFormats.length;
1448   for (var i = 0; i < l; ++i) {
1449     numFormat = availableFormats[i];
1450     /** @type {number} */
1451     var size = numFormat.leadingDigitsPatternCount();
1452     if (size == 0 ||
1453         // We always use the last leading_digits_pattern, as it is the most
1454         // detailed.
1455         nationalNumber
1456             .search(numFormat.getLeadingDigitsPattern(size - 1)) == 0) {
1457       /** @type {RegExp} */
1458       var patternToMatch = new RegExp(numFormat.getPattern());
1459       /** @type {string} */
1460       var numberFormatRule = numFormat.getFormatOrDefault();
1461       if (i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(patternToMatch,
1462                                                              nationalNumber)) {
1463         if (opt_carrierCode != null && opt_carrierCode.length > 0) {
1464           /** @type {string} */
1465           var domesticCarrierCodeFormattingRule =
1466               numFormat.getDomesticCarrierCodeFormattingRuleOrDefault();
1467           if (domesticCarrierCodeFormattingRule.length > 0) {
1468             // Replace the $CC in the formatting rule with the desired carrier
1469             // code.
1470             /** @type {string} */
1471             var carrierCodeFormattingRule = domesticCarrierCodeFormattingRule
1472                 .replace(i18n.phonenumbers.PhoneNumberUtil.CC_PATTERN_,
1473                          opt_carrierCode);
1474             // Now replace the $FG in the formatting rule with the first group
1475             // and the carrier code combined in the appropriate way.
1476             numberFormatRule = numberFormatRule.replace(
1477                 i18n.phonenumbers.PhoneNumberUtil.FIRST_GROUP_PATTERN_,
1478                 carrierCodeFormattingRule);
1479           }
1480         }
1481         /** @type {string} */
1482         var nationalPrefixFormattingRule =
1483             numFormat.getNationalPrefixFormattingRuleOrDefault();
1484         if (numberFormat == i18n.phonenumbers.PhoneNumberFormat.NATIONAL &&
1485             nationalPrefixFormattingRule != null &&
1486             nationalPrefixFormattingRule.length > 0) {
1487           return nationalNumber.replace(patternToMatch, numberFormatRule
1488               .replace(i18n.phonenumbers.PhoneNumberUtil.FIRST_GROUP_PATTERN_,
1489                        nationalPrefixFormattingRule));
1490         } else {
1491           return nationalNumber.replace(patternToMatch, numberFormatRule);
1492         }
1493       }
1494     }
1495   }
1496
1497   // If no pattern above is matched, we format the number as a whole.
1498   return nationalNumber;
1499 };
1500
1501
1502 /**
1503  * Gets a valid number for the specified country.
1504  *
1505  * @param {string} regionCode the ISO 3166-1 two-letter country code that
1506  *     denotes the country for which an example number is needed.
1507  * @return {i18n.phonenumbers.PhoneNumber} a valid fixed-line number for the
1508  *     specified country. Returns null when the metadata does not contain such
1509  *     information.
1510  */
1511 i18n.phonenumbers.PhoneNumberUtil.prototype.getExampleNumber =
1512     function(regionCode) {
1513
1514   return this.getExampleNumberForType(regionCode,
1515       i18n.phonenumbers.PhoneNumberType.FIXED_LINE);
1516 };
1517
1518
1519 /**
1520  * Gets a valid number, if any, for the specified country and number type.
1521  *
1522  * @param {string} regionCode the ISO 3166-1 two-letter country code that
1523  *     denotes the country for which an example number is needed.
1524  * @param {i18n.phonenumbers.PhoneNumberType} type the type of number that is
1525  *     needed.
1526  * @return {i18n.phonenumbers.PhoneNumber} a valid number for the specified
1527  *     country and type. Returns null when the metadata does not contain such
1528  *     information.
1529  */
1530 i18n.phonenumbers.PhoneNumberUtil.prototype.getExampleNumberForType =
1531     function(regionCode, type) {
1532
1533   /** @type {i18n.phonenumbers.PhoneNumberDesc} */
1534   var desc = this.getNumberDescByType_(
1535       this.getMetadataForRegion(regionCode), type);
1536   try {
1537     if (desc.hasExampleNumber()) {
1538       return this.parse(desc.getExampleNumberOrDefault(), regionCode);
1539     }
1540   } catch (e) {
1541   }
1542   return null;
1543 };
1544
1545
1546 /**
1547  * Gets the formatted extension of a phone number, if the phone number had an
1548  * extension specified. If not, it returns an empty string.
1549  *
1550  * @param {i18n.phonenumbers.PhoneNumber} number the PhoneNumber that might have
1551  *     an extension.
1552  * @param {string} regionCode the ISO 3166-1 two-letter country code.
1553  * @return {string} the formatted extension if any.
1554  * @private
1555  */
1556 i18n.phonenumbers.PhoneNumberUtil.prototype.maybeGetFormattedExtension_ =
1557     function(number, regionCode) {
1558
1559   if (!number.hasExtension()) {
1560     return '';
1561   } else {
1562     return this.formatExtension_(number.getExtensionOrDefault(), regionCode);
1563   }
1564 };
1565
1566
1567 /**
1568  * Formats the extension part of the phone number by prefixing it with the
1569  * appropriate extension prefix. This will be the default extension prefix,
1570  * unless overridden by a preferred extension prefix for this country.
1571  *
1572  * @param {string} extensionDigits the extension digits.
1573  * @param {string} regionCode the ISO 3166-1 two-letter country code.
1574  * @return {string} the formatted extension.
1575  * @private
1576  */
1577 i18n.phonenumbers.PhoneNumberUtil.prototype.formatExtension_ =
1578     function(extensionDigits, regionCode) {
1579
1580   /** @type {i18n.phonenumbers.PhoneMetadata} */
1581   var metadata = this.getMetadataForRegion(regionCode);
1582   if (metadata.hasPreferredExtnPrefix()) {
1583     return metadata.getPreferredExtnPrefix() + extensionDigits;
1584   } else {
1585     return i18n.phonenumbers.PhoneNumberUtil.DEFAULT_EXTN_PREFIX_ +
1586         extensionDigits;
1587   }
1588 };
1589
1590
1591 /**
1592  * @param {i18n.phonenumbers.PhoneMetadata} metadata
1593  * @param {i18n.phonenumbers.PhoneNumberType} type
1594  * @return {i18n.phonenumbers.PhoneNumberDesc}
1595  * @private
1596  */
1597 i18n.phonenumbers.PhoneNumberUtil.prototype.getNumberDescByType_ =
1598     function(metadata, type) {
1599
1600   switch (type) {
1601     case i18n.phonenumbers.PhoneNumberType.PREMIUM_RATE:
1602       return metadata.getPremiumRate();
1603     case i18n.phonenumbers.PhoneNumberType.TOLL_FREE:
1604       return metadata.getTollFree();
1605     case i18n.phonenumbers.PhoneNumberType.MOBILE:
1606       return metadata.getMobile();
1607     case i18n.phonenumbers.PhoneNumberType.FIXED_LINE:
1608     case i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE:
1609       return metadata.getFixedLine();
1610     case i18n.phonenumbers.PhoneNumberType.SHARED_COST:
1611       return metadata.getSharedCost();
1612     case i18n.phonenumbers.PhoneNumberType.VOIP:
1613       return metadata.getVoip();
1614     case i18n.phonenumbers.PhoneNumberType.PERSONAL_NUMBER:
1615       return metadata.getPersonalNumber();
1616     case i18n.phonenumbers.PhoneNumberType.PAGER:
1617       return metadata.getPager();
1618     case i18n.phonenumbers.PhoneNumberType.UAN:
1619       return metadata.getUan();
1620     default:
1621       return metadata.getGeneralDesc();
1622   }
1623 };
1624
1625
1626 /**
1627  * Gets the type of a phone number.
1628  *
1629  * @param {i18n.phonenumbers.PhoneNumber} number the phone number that we want
1630  *     to know the type.
1631  * @return {i18n.phonenumbers.PhoneNumberType} the type of the phone number.
1632  */
1633 i18n.phonenumbers.PhoneNumberUtil.prototype.getNumberType =
1634     function(number) {
1635
1636   /** @type {?string} */
1637   var regionCode = this.getRegionCodeForNumber(number);
1638   if (!this.isValidRegionCode_(regionCode)) {
1639     return i18n.phonenumbers.PhoneNumberType.UNKNOWN;
1640   }
1641   /** @type {string} */
1642   var nationalSignificantNumber =
1643       i18n.phonenumbers.PhoneNumberUtil.getNationalSignificantNumber(number);
1644   return this.getNumberTypeHelper_(nationalSignificantNumber,
1645       this.getMetadataForRegion(regionCode));
1646 };
1647
1648
1649 /**
1650  * @param {string} nationalNumber
1651  * @param {i18n.phonenumbers.PhoneMetadata} metadata
1652  * @return {i18n.phonenumbers.PhoneNumberType}
1653  * @private
1654  */
1655 i18n.phonenumbers.PhoneNumberUtil.prototype.getNumberTypeHelper_ =
1656     function(nationalNumber, metadata) {
1657
1658   /** @type {i18n.phonenumbers.PhoneNumberDesc} */
1659   var generalNumberDesc = metadata.getGeneralDesc();
1660   if (!generalNumberDesc.hasNationalNumberPattern() ||
1661       !this.isNumberMatchingDesc_(nationalNumber, generalNumberDesc)) {
1662     return i18n.phonenumbers.PhoneNumberType.UNKNOWN;
1663   }
1664
1665   if (this.isNumberMatchingDesc_(nationalNumber, metadata.getPremiumRate())) {
1666     return i18n.phonenumbers.PhoneNumberType.PREMIUM_RATE;
1667   }
1668   if (this.isNumberMatchingDesc_(nationalNumber, metadata.getTollFree())) {
1669     return i18n.phonenumbers.PhoneNumberType.TOLL_FREE;
1670   }
1671   if (this.isNumberMatchingDesc_(nationalNumber, metadata.getSharedCost())) {
1672     return i18n.phonenumbers.PhoneNumberType.SHARED_COST;
1673   }
1674   if (this.isNumberMatchingDesc_(nationalNumber, metadata.getVoip())) {
1675     return i18n.phonenumbers.PhoneNumberType.VOIP;
1676   }
1677   if (this.isNumberMatchingDesc_(nationalNumber,
1678                                  metadata.getPersonalNumber())) {
1679     return i18n.phonenumbers.PhoneNumberType.PERSONAL_NUMBER;
1680   }
1681   if (this.isNumberMatchingDesc_(nationalNumber, metadata.getPager())) {
1682     return i18n.phonenumbers.PhoneNumberType.PAGER;
1683   }
1684   if (this.isNumberMatchingDesc_(nationalNumber, metadata.getUan())) {
1685     return i18n.phonenumbers.PhoneNumberType.UAN;
1686   }
1687
1688   /** @type {boolean} */
1689   var isFixedLine = this.isNumberMatchingDesc_(nationalNumber, metadata
1690       .getFixedLine());
1691   if (isFixedLine) {
1692     if (metadata.getSameMobileAndFixedLinePattern()) {
1693       return i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE;
1694     } else if (this.isNumberMatchingDesc_(nationalNumber,
1695                                           metadata.getMobile())) {
1696       return i18n.phonenumbers.PhoneNumberType.FIXED_LINE_OR_MOBILE;
1697     }
1698     return i18n.phonenumbers.PhoneNumberType.FIXED_LINE;
1699   }
1700   // Otherwise, test to see if the number is mobile. Only do this if certain
1701   // that the patterns for mobile and fixed line aren't the same.
1702   if (!metadata.getSameMobileAndFixedLinePattern() &&
1703       this.isNumberMatchingDesc_(nationalNumber, metadata.getMobile())) {
1704     return i18n.phonenumbers.PhoneNumberType.MOBILE;
1705   }
1706   return i18n.phonenumbers.PhoneNumberType.UNKNOWN;
1707 };
1708
1709
1710 /**
1711  * @param {?string} regionCode
1712  * @return {i18n.phonenumbers.PhoneMetadata}
1713  */
1714 i18n.phonenumbers.PhoneNumberUtil.prototype.getMetadataForRegion =
1715     function(regionCode) {
1716
1717   if (regionCode == null) {
1718     return null;
1719   }
1720   regionCode = regionCode.toUpperCase();
1721   /** @type {i18n.phonenumbers.PhoneMetadata} */
1722   var metadata = this.countryToMetadata[regionCode];
1723   if (metadata == null) {
1724     /** @type {goog.proto2.PbLiteSerializer} */
1725     var serializer = new goog.proto2.PbLiteSerializer();
1726     /** @type {Array} */
1727     var metadataSerialized =
1728         i18n.phonenumbers.metadata.countryToMetadata[regionCode];
1729     if (metadataSerialized == null) {
1730       return null;
1731     }
1732     metadata = /** @type {i18n.phonenumbers.PhoneMetadata} */ (
1733         serializer.deserialize(i18n.phonenumbers.PhoneMetadata.getDescriptor(),
1734             metadataSerialized));
1735     this.countryToMetadata[regionCode] = metadata;
1736   }
1737   return metadata;
1738 };
1739
1740
1741 /**
1742  * @param {string} nationalNumber
1743  * @param {i18n.phonenumbers.PhoneNumberDesc} numberDesc
1744  * @return {boolean}
1745  * @private
1746  */
1747 i18n.phonenumbers.PhoneNumberUtil.prototype.isNumberMatchingDesc_ =
1748     function(nationalNumber, numberDesc) {
1749
1750   return i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
1751       numberDesc.getPossibleNumberPattern(), nationalNumber) &&
1752       i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
1753           numberDesc.getNationalNumberPattern(), nationalNumber);
1754 };
1755
1756
1757 /**
1758  * Tests whether a phone number matches a valid pattern. Note this doesn't
1759  * verify the number is actually in use, which is impossible to tell by just
1760  * looking at a number itself.
1761  *
1762  * @param {i18n.phonenumbers.PhoneNumber} number the phone number that we want
1763  *     to validate.
1764  * @return {boolean} a boolean that indicates whether the number is of a valid
1765  *     pattern.
1766  */
1767 i18n.phonenumbers.PhoneNumberUtil.prototype.isValidNumber = function(number) {
1768   /** @type {?string} */
1769   var regionCode = this.getRegionCodeForNumber(number);
1770   return this.isValidRegionCode_(regionCode) &&
1771       this.isValidNumberForRegion(number, /** @type {string} */ (regionCode));
1772 };
1773
1774
1775 /**
1776  * Tests whether a phone number is valid for a certain region. Note this doesn't
1777  * verify the number is actually in use, which is impossible to tell by just
1778  * looking at a number itself. If the country code is not the same as the
1779  * country code for the region, this immediately exits with false. After this,
1780  * the specific number pattern rules for the region are examined. This is useful
1781  * for determining for example whether a particular number is valid for Canada,
1782  * rather than just a valid NANPA number.
1783  *
1784  * @param {i18n.phonenumbers.PhoneNumber} number the phone number that we want
1785  *     to validate.
1786  * @param {string} regionCode the ISO 3166-1 two-letter country code that
1787  *     denotes the region/country that we want to validate the phone number for.
1788  * @return {boolean} a boolean that indicates whether the number is of a valid
1789  *     pattern.
1790  */
1791 i18n.phonenumbers.PhoneNumberUtil.prototype.isValidNumberForRegion =
1792     function(number, regionCode) {
1793
1794   if (number.getCountryCodeOrDefault() !=
1795       this.getCountryCodeForRegion(regionCode)) {
1796     return false;
1797   }
1798   /** @type {i18n.phonenumbers.PhoneMetadata} */
1799   var metadata = this.getMetadataForRegion(regionCode);
1800   /** @type {i18n.phonenumbers.PhoneNumberDesc} */
1801   var generalNumDesc = metadata.getGeneralDesc();
1802   /** @type {string} */
1803   var nationalSignificantNumber =
1804       i18n.phonenumbers.PhoneNumberUtil.getNationalSignificantNumber(number);
1805
1806   // For countries where we don't have metadata for PhoneNumberDesc, we treat
1807   // any number passed in as a valid number if its national significant number
1808   // is between the minimum and maximum lengths defined by ITU for a national
1809   // significant number.
1810   if (!generalNumDesc.hasNationalNumberPattern()) {
1811     /** @type {number} */
1812     var numberLength = nationalSignificantNumber.length;
1813     return numberLength >
1814         i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_ &&
1815         numberLength <= i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_FOR_NSN_;
1816   }
1817   return this.getNumberTypeHelper_(nationalSignificantNumber, metadata) !=
1818       i18n.phonenumbers.PhoneNumberType.UNKNOWN;
1819 };
1820
1821
1822 /**
1823  * Returns the country/region where a phone number is from. This could be used
1824  * for geo-coding in the country/region level.
1825  *
1826  * @param {i18n.phonenumbers.PhoneNumber} number the phone number whose origin
1827  *     we want to know.
1828  * @return {?string} the country/region where the phone number is from, or null
1829  *     if no country matches this calling code.
1830  */
1831 i18n.phonenumbers.PhoneNumberUtil.prototype.getRegionCodeForNumber =
1832     function(number) {
1833
1834   if (number == null) {
1835     return null;
1836   }
1837   /** @type {number} */
1838   var countryCode = number.getCountryCodeOrDefault();
1839   /** @type {Array.<string>} */
1840   var regions =
1841       i18n.phonenumbers.metadata.countryCodeToRegionCodeMap[countryCode];
1842   if (regions == null) {
1843     return null;
1844   }
1845   if (regions.length == 1) {
1846     return regions[0];
1847   } else {
1848     return this.getRegionCodeForNumberFromRegionList_(number, regions);
1849   }
1850 };
1851
1852
1853 /**
1854  * @param {i18n.phonenumbers.PhoneNumber} number
1855  * @param {Array.<string>} regionCodes
1856  * @return {?string}
1857  * @private
1858  */
1859 i18n.phonenumbers.PhoneNumberUtil.prototype.
1860     getRegionCodeForNumberFromRegionList_ = function(number, regionCodes) {
1861
1862   /** @type {string} */
1863   var nationalNumber = '' + number.getNationalNumber();
1864   /** @type {string} */
1865   var regionCode;
1866   /** @type {number} */
1867   var regionCodesLength = regionCodes.length;
1868   for (var i = 0; i < regionCodesLength; i++) {
1869     regionCode = regionCodes[i];
1870     // If leadingDigits is present, use this. Otherwise, do full validation.
1871     /** @type {i18n.phonenumbers.PhoneMetadata} */
1872     var metadata = this.getMetadataForRegion(regionCode);
1873     if (metadata.hasLeadingDigits()) {
1874       if (nationalNumber.search(metadata.getLeadingDigits()) == 0) {
1875         return regionCode;
1876       }
1877     } else if (this.getNumberTypeHelper_(nationalNumber, metadata) !=
1878         i18n.phonenumbers.PhoneNumberType.UNKNOWN) {
1879       return regionCode;
1880     }
1881   }
1882   return null;
1883 };
1884
1885
1886 /**
1887  * Returns the region code that matches the specific country code. In the case
1888  * of no region code being found, ZZ will be returned. In the case of multiple
1889  * regions, the one designated in the metadata as the "main" country for this
1890  * calling code will be returned.
1891  *
1892  * @param {number} countryCode the country calling code.
1893  * @return {string}
1894  */
1895 i18n.phonenumbers.PhoneNumberUtil.prototype.getRegionCodeForCountryCode =
1896     function(countryCode) {
1897
1898   /** @type {Array.<string>} */
1899   var regionCodes =
1900       i18n.phonenumbers.metadata.countryCodeToRegionCodeMap[countryCode];
1901   return regionCodes == null ?
1902       i18n.phonenumbers.PhoneNumberUtil.UNKNOWN_REGION_ : regionCodes[0];
1903 };
1904
1905
1906 /**
1907  * Returns the country calling code for a specific region. For example, this
1908  * would be 1 for the United States, and 64 for New Zealand.
1909  *
1910  * @param {?string} regionCode the ISO 3166-1 two-letter country code that
1911  *     denotes the country/region that we want to get the country code for.
1912  * @return {number} the country calling code for the country/region denoted by
1913  *     regionCode.
1914  */
1915 i18n.phonenumbers.PhoneNumberUtil.prototype.getCountryCodeForRegion =
1916     function(regionCode) {
1917
1918   if (!this.isValidRegionCode_(regionCode)) {
1919     return 0;
1920   }
1921   /** @type {i18n.phonenumbers.PhoneMetadata} */
1922   var metadata = this.getMetadataForRegion(regionCode);
1923   if (metadata == null) {
1924     return 0;
1925   }
1926   return metadata.getCountryCodeOrDefault();
1927 };
1928
1929
1930 /**
1931  * Returns the national dialling prefix for a specific region. For example, this
1932  * would be 1 for the United States, and 0 for New Zealand. Set stripNonDigits
1933  * to true to strip symbols like "~" (which indicates a wait for a dialling
1934  * tone) from the prefix returned. If no national prefix is present, we return
1935  * null.
1936  *
1937  * Warning: Do not use this method for do-your-own formatting - for some
1938  * countries, the national dialling prefix is used only for certain types of
1939  * numbers. Use the library's formatting functions to prefix the national prefix
1940  * when required.
1941  *
1942  * @param {string} regionCode the ISO 3166-1 two-letter country code that
1943  *     denotes the country/region that we want to get the dialling prefix for.
1944  * @param {boolean} stripNonDigits true to strip non-digits from the national
1945  *     dialling prefix.
1946  * @return {?string} the dialling prefix for the country/region denoted by
1947  *     regionCode.
1948  */
1949 i18n.phonenumbers.PhoneNumberUtil.prototype.getNddPrefixForRegion = function(
1950     regionCode, stripNonDigits) {
1951   if (!this.isValidRegionCode_(regionCode)) {
1952     return null;
1953   }
1954   /** @type {i18n.phonenumbers.PhoneMetadata} */
1955   var metadata = this.getMetadataForRegion(regionCode);
1956   if (metadata == null) {
1957     return null;
1958   }
1959   /** @type {string} */
1960   var nationalPrefix = metadata.getNationalPrefixOrDefault();
1961   // If no national prefix was found, we return null.
1962   if (nationalPrefix.length == 0) {
1963     return null;
1964   }
1965   if (stripNonDigits) {
1966     // Note: if any other non-numeric symbols are ever used in national
1967     // prefixes, these would have to be removed here as well.
1968     nationalPrefix = nationalPrefix.replace('~', '');
1969   }
1970   return nationalPrefix;
1971 };
1972
1973
1974 /**
1975  * Check if a country is one of the countries under the North American Numbering
1976  * Plan Administration (NANPA).
1977  *
1978  * @param {string} regionCode the ISO 3166-1 two-letter country code.
1979  * @return {boolean} true if regionCode is one of the countries under NANPA.
1980  */
1981 i18n.phonenumbers.PhoneNumberUtil.prototype.isNANPACountry =
1982     function(regionCode) {
1983
1984   return goog.array.contains(
1985       i18n.phonenumbers.metadata.countryCodeToRegionCodeMap[
1986           i18n.phonenumbers.PhoneNumberUtil.NANPA_COUNTRY_CODE_],
1987       regionCode.toUpperCase());
1988 };
1989
1990
1991 /**
1992  * Check whether countryCode represents the country calling code from a country
1993  * whose national significant number could contain a leading zero. An example of
1994  * such a country is Italy.
1995  *
1996  * @param {number} countryCode the country calling code.
1997  * @return {boolean}
1998  */
1999 i18n.phonenumbers.PhoneNumberUtil.isLeadingZeroCountry = function(countryCode) {
2000   return countryCode in
2001       i18n.phonenumbers.PhoneNumberUtil.LEADING_ZERO_COUNTRIES_;
2002 };
2003
2004
2005 /**
2006  * Convenience wrapper around isPossibleNumberWithReason. Instead of returning
2007  * the reason for failure, this method returns a boolean value.
2008  *
2009  * @param {i18n.phonenumbers.PhoneNumber} number the number that needs to be
2010  *     checked.
2011  * @return {boolean} true if the number is possible.
2012  */
2013 i18n.phonenumbers.PhoneNumberUtil.prototype.isPossibleNumber =
2014     function(number) {
2015
2016   return this.isPossibleNumberWithReason(number) ==
2017       i18n.phonenumbers.PhoneNumberUtil.ValidationResult.IS_POSSIBLE;
2018 };
2019
2020
2021 /**
2022  * Check whether a phone number is a possible number. It provides a more lenient
2023  * check than isValidNumber in the following sense:
2024  *
2025  * 1. It only checks the length of phone numbers. In particular, it doesn't
2026  * check starting digits of the number.
2027  *
2028  * 2. It doesn't attempt to figure out the type of the number, but uses general
2029  * rules which applies to all types of phone numbers in a country. Therefore, it
2030  * is much faster than isValidNumber.
2031  *
2032  * 3. For fixed line numbers, many countries have the concept of area code,
2033  * which together with subscriber number constitute the national significant
2034  * number. It is sometimes okay to dial the subscriber number only when dialing
2035  * in the same area. This function will return true if the
2036  * subscriber-number-only version is passed in. On the other hand, because
2037  * isValidNumber validates using information on both starting digits (for fixed
2038  * line numbers, that would most likely be area codes) and length (obviously
2039  * includes the length of area codes for fixed line numbers), it will return
2040  * false for the subscriber-number-only version.
2041  *
2042  * @param {i18n.phonenumbers.PhoneNumber} number the number that needs to be
2043  *     checked.
2044  * @return {i18n.phonenumbers.PhoneNumberUtil.ValidationResult} a
2045  *     ValidationResult object which indicates whether the number is possible.
2046  */
2047 i18n.phonenumbers.PhoneNumberUtil.prototype.isPossibleNumberWithReason =
2048     function(number) {
2049
2050   /** @type {number} */
2051   var countryCode = number.getCountryCodeOrDefault();
2052   // Note: For Russian Fed and NANPA numbers, we just use the rules from the
2053   // default region (US or Russia) since the getRegionCodeForNumber will not
2054   // work if the number is possible but not valid. This would need to be
2055   // revisited if the possible number pattern ever differed between various
2056   // countries within those plans.
2057   /** @type {string} */
2058   var regionCode = this.getRegionCodeForCountryCode(countryCode);
2059   if (!this.isValidRegionCode_(regionCode)) {
2060     return i18n.phonenumbers.PhoneNumberUtil.ValidationResult
2061         .INVALID_COUNTRY_CODE;
2062   }
2063   /** @type {string} */
2064   var nationalNumber =
2065       i18n.phonenumbers.PhoneNumberUtil.getNationalSignificantNumber(number);
2066   /** @type {i18n.phonenumbers.PhoneNumberDesc} */
2067   var generalNumDesc = this.getMetadataForRegion(regionCode).getGeneralDesc();
2068   // Handling case of numbers with no metadata.
2069   if (!generalNumDesc.hasNationalNumberPattern()) {
2070     /** @type {number} */
2071     var numberLength = nationalNumber.length;
2072     if (numberLength < i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_) {
2073       return i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_SHORT;
2074     } else if (numberLength >
2075                i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_FOR_NSN_) {
2076       return i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_LONG;
2077     } else {
2078       return i18n.phonenumbers.PhoneNumberUtil.ValidationResult.IS_POSSIBLE;
2079     }
2080   }
2081   /** @type {string} */
2082   var possibleNumberPattern =
2083       generalNumDesc.getPossibleNumberPatternOrDefault();
2084   /** @type {Array.<string> } */
2085   var matchedGroups = nationalNumber.match('^' + possibleNumberPattern);
2086   /** @type {string} */
2087   var firstGroup = matchedGroups ? matchedGroups[0] : '';
2088   if (firstGroup.length > 0) {
2089     return (firstGroup.length == nationalNumber.length) ?
2090         i18n.phonenumbers.PhoneNumberUtil.ValidationResult.IS_POSSIBLE :
2091         i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_LONG;
2092   } else {
2093     return i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_SHORT;
2094   }
2095 };
2096
2097
2098 /**
2099  * Check whether a phone number is a possible number given a number in the form
2100  * of a string, and the country where the number could be dialed from. It
2101  * provides a more lenient check than isValidNumber. See
2102  * isPossibleNumber(number) for details.
2103  *
2104  * This method first parses the number, then invokes
2105  * isPossibleNumber(PhoneNumber number) with the resultant PhoneNumber object.
2106  *
2107  * @param {string} number the number that needs to be checked, in the form of a
2108  *     string.
2109  * @param {string} countryDialingFrom the ISO 3166-1 two-letter country code
2110  *     that denotes the country that we are expecting the number to be dialed
2111  *     from. Note this is different from the country where the number belongs.
2112  *     For example, the number +1 650 253 0000 is a number that belongs to US.
2113  *     When written in this form, it could be dialed from any country. When it
2114  *     is written as 00 1 650 253 0000, it could be dialed from any country
2115  *     which uses an international dialling prefix of 00. When it is written as
2116  *     650 253 0000, it could only be dialed from within the US, and when
2117  *     written as 253 0000, it could only be dialed from within a smaller area
2118  *     in the US (Mountain View, CA, to be more specific).
2119  * @return {boolean} true if the number is possible.
2120  */
2121 i18n.phonenumbers.PhoneNumberUtil.prototype.isPossibleNumberString =
2122     function(number, countryDialingFrom) {
2123
2124   try {
2125     return this.isPossibleNumber(this.parse(number, countryDialingFrom));
2126   } catch (e) {
2127     return false;
2128   }
2129 };
2130
2131
2132 /**
2133  * Attempts to extract a valid number from a phone number that is too long to be
2134  * valid, and resets the PhoneNumber object passed in to that valid version. If
2135  * no valid number could be extracted, the PhoneNumber object passed in will not
2136  * be modified.
2137  * @param {i18n.phonenumbers.PhoneNumber} number a PhoneNumber object which
2138  *     contains a number that is too long to be valid.
2139  * @return {boolean} true if a valid phone number can be successfully extracted.
2140  */
2141 i18n.phonenumbers.PhoneNumberUtil.prototype.truncateTooLongNumber =
2142     function(number) {
2143
2144   if (this.isValidNumber(number)) {
2145     return true;
2146   }
2147   /** @type {i18n.phonenumbers.PhoneNumber} */
2148   var numberCopy = new i18n.phonenumbers.PhoneNumber();
2149   numberCopy.mergeFrom(number);
2150   /** @type {number} */
2151   var nationalNumber = number.getNationalNumberOrDefault();
2152   do {
2153     nationalNumber = Math.floor(nationalNumber / 10);
2154     numberCopy.setNationalNumber(nationalNumber);
2155     if (nationalNumber == 0 ||
2156         this.isPossibleNumberWithReason(numberCopy) ==
2157             i18n.phonenumbers.PhoneNumberUtil.ValidationResult.TOO_SHORT) {
2158       return false;
2159     }
2160   } while (!this.isValidNumber(numberCopy));
2161   number.setNationalNumber(nationalNumber);
2162   return true;
2163 };
2164
2165
2166 /**
2167  * Extracts country code from fullNumber, returns it and places the remaining
2168  * number in nationalNumber. It assumes that the leading plus sign or IDD has
2169  * already been removed. Returns 0 if fullNumber doesn't start with a valid
2170  * country code, and leaves nationalNumber unmodified.
2171  *
2172  * @param {!goog.string.StringBuffer} fullNumber
2173  * @param {!goog.string.StringBuffer} nationalNumber
2174  * @return {number}
2175  */
2176 i18n.phonenumbers.PhoneNumberUtil.prototype.extractCountryCode =
2177     function(fullNumber, nationalNumber) {
2178
2179   /** @type {string} */
2180   var fullNumberStr = fullNumber.toString();
2181   /** @type {number} */
2182   var potentialCountryCode;
2183   /** @type {number} */
2184   var numberLength = fullNumberStr.length;
2185   for (var i = 1;
2186       i <= i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_COUNTRY_CODE_ &&
2187       i <= numberLength; ++i) {
2188     potentialCountryCode = parseInt(fullNumberStr.substring(0, i), 10);
2189     if (potentialCountryCode in
2190         i18n.phonenumbers.metadata.countryCodeToRegionCodeMap) {
2191       nationalNumber.append(fullNumberStr.substring(i));
2192       return potentialCountryCode;
2193     }
2194   }
2195   return 0;
2196 };
2197
2198
2199 /**
2200  * Tries to extract a country code from a number. This method will return zero
2201  * if no country code is considered to be present. Country codes are extracted
2202  * in the following ways:
2203  *  - by stripping the international dialing prefix of the country the person is
2204  * dialing from, if this is present in the number, and looking at the next
2205  * digits
2206  *  - by stripping the '+' sign if present and then looking at the next digits
2207  *  - by comparing the start of the number and the country code of the default
2208  * region. If the number is not considered possible for the numbering plan of
2209  * the default region initially, but starts with the country code of this
2210  * region, validation will be reattempted after stripping this country code. If
2211  * this number is considered a possible number, then the first digits will be
2212  * considered the country code and removed as such.
2213  *
2214  * It will throw a i18n.phonenumbers.Error if the number starts with a '+' but
2215  * the country code supplied after this does not match that of any known
2216  * country.
2217  *
2218  * @param {string} number non-normalized telephone number that we wish to
2219  *     extract a country code from - may begin with '+'.
2220  * @param {i18n.phonenumbers.PhoneMetadata} defaultRegionMetadata metadata
2221  *     about the region this number may be from.
2222  * @param {!goog.string.StringBuffer} nationalNumber a string buffer to store
2223  *     the national significant number in, in the case that a country code was
2224  *     extracted. The number is appended to any existing contents. If no country
2225  *     code was extracted, this will be left unchanged.
2226  * @param {boolean} storeCountryCodeSource true if the country_code_source field
2227  *     of phoneNumber should be populated.
2228  * @param {i18n.phonenumbers.PhoneNumber} phoneNumber the PhoneNumber object
2229  *     that needs to be populated with country code and country code source.
2230  *     Note the country code is always populated, whereas country code source is
2231  *     only populated when keepCountryCodeSource is true.
2232  * @return {number} the country code extracted or 0 if none could be extracted.
2233  * @throws {i18n.phonenumbers.Error}
2234  */
2235 i18n.phonenumbers.PhoneNumberUtil.prototype.maybeExtractCountryCode =
2236     function(number, defaultRegionMetadata, nationalNumber,
2237              storeCountryCodeSource, phoneNumber) {
2238
2239   if (number.length == 0) {
2240     return 0;
2241   }
2242   /** @type {!goog.string.StringBuffer} */
2243   var fullNumber = new goog.string.StringBuffer(number);
2244   // Set the default prefix to be something that will never match.
2245   /** @type {?string} */
2246   var possibleCountryIddPrefix;
2247   if (defaultRegionMetadata != null) {
2248     possibleCountryIddPrefix = defaultRegionMetadata.getInternationalPrefix();
2249   }
2250   if (possibleCountryIddPrefix == null) {
2251     possibleCountryIddPrefix = 'NonMatch';
2252   }
2253
2254   /** @type {i18n.phonenumbers.PhoneNumber.CountryCodeSource} */
2255   var countryCodeSource = this.maybeStripInternationalPrefixAndNormalize(
2256       fullNumber, possibleCountryIddPrefix);
2257   if (storeCountryCodeSource) {
2258     phoneNumber.setCountryCodeSource(countryCodeSource);
2259   }
2260   if (countryCodeSource !=
2261       i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_DEFAULT_COUNTRY) {
2262     if (fullNumber.getLength() <
2263         i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_) {
2264       throw i18n.phonenumbers.Error.TOO_SHORT_AFTER_IDD;
2265     }
2266     /** @type {number} */
2267     var potentialCountryCode = this.extractCountryCode(fullNumber,
2268                                                        nationalNumber);
2269     if (potentialCountryCode != 0) {
2270       phoneNumber.setCountryCode(potentialCountryCode);
2271       return potentialCountryCode;
2272     }
2273
2274     // If this fails, they must be using a strange country code that we don't
2275     // recognize, or that doesn't exist.
2276     throw i18n.phonenumbers.Error.INVALID_COUNTRY_CODE;
2277   } else if (defaultRegionMetadata != null) {
2278     // Check to see if the number is valid for the default region already. If
2279     // not, we check to see if the country code for the default region is
2280     // present at the start of the number.
2281     /** @type {i18n.phonenumbers.PhoneNumberDesc} */
2282     var generalDesc = defaultRegionMetadata.getGeneralDesc();
2283     /** @type {RegExp} */
2284     var validNumberPattern = new RegExp(generalDesc.getNationalNumberPattern());
2285     if (!i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
2286         validNumberPattern, fullNumber.toString())) {
2287       /** @type {number} */
2288       var defaultCountryCode = defaultRegionMetadata.getCountryCodeOrDefault();
2289       /** @type {string} */
2290       var defaultCountryCodeString = '' + defaultCountryCode;
2291       /** @type {string} */
2292       var normalizedNumber = fullNumber.toString();
2293       if (goog.string.startsWith(normalizedNumber, defaultCountryCodeString)) {
2294         // If so, strip this, and see if the resultant number is valid.
2295         /** @type {!goog.string.StringBuffer} */
2296         var potentialNationalNumber = new goog.string.StringBuffer(
2297             normalizedNumber.substring(defaultCountryCodeString.length));
2298         this.maybeStripNationalPrefix(potentialNationalNumber,
2299             defaultRegionMetadata.getNationalPrefixForParsing(),
2300             defaultRegionMetadata.getNationalPrefixTransformRule(),
2301             validNumberPattern);
2302         /** @type {string} */
2303         var potentialNationalNumberStr = potentialNationalNumber.toString();
2304         /** @type {Array.<string> } */
2305         var matchedGroups = potentialNationalNumberStr.match(
2306             '^' + generalDesc.getPossibleNumberPattern());
2307         /** @type {number} */
2308         var possibleNumberMatchedLength = matchedGroups &&
2309             matchedGroups[0] != null && matchedGroups[0].length || 0;
2310         // If the resultant number is either valid, or still too long even with
2311         // the country code stripped, we consider this a better result and keep
2312         // the potential national number.
2313         if (i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(
2314             validNumberPattern, potentialNationalNumberStr) ||
2315             possibleNumberMatchedLength > 0 &&
2316             possibleNumberMatchedLength != potentialNationalNumberStr.length) {
2317           nationalNumber.append(potentialNationalNumberStr);
2318           if (storeCountryCodeSource) {
2319             phoneNumber.setCountryCodeSource(
2320                 i18n.phonenumbers.PhoneNumber.CountryCodeSource
2321                     .FROM_NUMBER_WITHOUT_PLUS_SIGN);
2322           }
2323           phoneNumber.setCountryCode(defaultCountryCode);
2324           return defaultCountryCode;
2325         }
2326       }
2327     }
2328   }
2329   // No country code present.
2330   phoneNumber.setCountryCode(0);
2331   return 0;
2332 };
2333
2334
2335 /**
2336  * Strips the IDD from the start of the number if present. Helper function used
2337  * by maybeStripInternationalPrefixAndNormalize.
2338  *
2339  * @param {RegExp} iddPattern the regular expression for the international
2340  *     prefix.
2341  * @param {!goog.string.StringBuffer} number the phone number that we wish to
2342  *     strip any international dialing prefix from.
2343  * @return {boolean} true if an international prefix was present.
2344  * @private
2345  */
2346 i18n.phonenumbers.PhoneNumberUtil.prototype.parsePrefixAsIdd_ =
2347     function(iddPattern, number) {
2348
2349   /** @type {string} */
2350   var numberStr = number.toString();
2351   if (numberStr.search(iddPattern) == 0) {
2352     /** @type {number} */
2353     var matchEnd = numberStr.match(iddPattern)[0].length;
2354     /** @type {Array.<string> } */
2355     var matchedGroups = numberStr.substring(matchEnd).match(
2356         i18n.phonenumbers.PhoneNumberUtil.CAPTURING_DIGIT_PATTERN_);
2357     if (matchedGroups && matchedGroups[1] != null &&
2358         matchedGroups[1].length > 0) {
2359       /** @type {string} */
2360       var normalizedGroup = i18n.phonenumbers.PhoneNumberUtil.normalizeHelper_(
2361           matchedGroups[1], i18n.phonenumbers.PhoneNumberUtil.DIGIT_MAPPINGS,
2362           true);
2363       if (normalizedGroup == '0') {
2364         return false;
2365       }
2366     }
2367     number.clear();
2368     number.append(numberStr.substring(matchEnd));
2369     return true;
2370   }
2371   return false;
2372 };
2373
2374
2375 /**
2376  * Strips any international prefix (such as +, 00, 011) present in the number
2377  * provided, normalizes the resulting number, and indicates if an international
2378  * prefix was present.
2379  *
2380  * @param {!goog.string.StringBuffer} number the non-normalized telephone number
2381  *     that we wish to strip any international dialing prefix from.
2382  * @param {string} possibleIddPrefix the international direct dialing prefix
2383  *     from the country we think this number may be dialed in.
2384  * @return {i18n.phonenumbers.PhoneNumber.CountryCodeSource} the corresponding
2385  *     CountryCodeSource if an international dialing prefix could be removed
2386  *     from the number, otherwise CountryCodeSource.FROM_DEFAULT_COUNTRY if
2387  *     the number did not seem to be in international format.
2388  */
2389 i18n.phonenumbers.PhoneNumberUtil.prototype.
2390     maybeStripInternationalPrefixAndNormalize = function(number,
2391                                                          possibleIddPrefix) {
2392   /** @type {string} */
2393   var numberStr = number.toString();
2394   if (numberStr.length == 0) {
2395     return i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_DEFAULT_COUNTRY;
2396   }
2397   // Check to see if the number begins with one or more plus signs.
2398   if (i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_PATTERN_.test(numberStr)) {
2399     numberStr = numberStr.replace(
2400         i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_PATTERN_, '');
2401     // Can now normalize the rest of the number since we've consumed the "+"
2402     // sign at the start.
2403     number.clear();
2404     number.append(i18n.phonenumbers.PhoneNumberUtil.normalize(numberStr));
2405     return i18n.phonenumbers.PhoneNumber.CountryCodeSource
2406         .FROM_NUMBER_WITH_PLUS_SIGN;
2407   }
2408   // Attempt to parse the first digits as an international prefix.
2409   /** @type {RegExp} */
2410   var iddPattern = new RegExp(possibleIddPrefix);
2411   if (this.parsePrefixAsIdd_(iddPattern, number)) {
2412     i18n.phonenumbers.PhoneNumberUtil.normalizeSB_(number);
2413     return i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_IDD;
2414   }
2415   // If still not found, then try and normalize the number and then try again.
2416   // This shouldn't be done before, since non-numeric characters (+ and ~) may
2417   // legally be in the international prefix.
2418   i18n.phonenumbers.PhoneNumberUtil.normalizeSB_(number);
2419   return this.parsePrefixAsIdd_(iddPattern, number) ?
2420       i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_IDD :
2421       i18n.phonenumbers.PhoneNumber.CountryCodeSource.FROM_DEFAULT_COUNTRY;
2422 };
2423
2424
2425 /**
2426  * Strips any national prefix (such as 0, 1) present in the number provided.
2427  *
2428  * @param {!goog.string.StringBuffer} number the normalized telephone number
2429  *     that we wish to strip any national dialing prefix from.
2430  * @param {?string} possibleNationalPrefix a regex that represents the national
2431  *     direct dialing prefix from the country we think this number may be dialed
2432  *     in.
2433  * @param {?string} transformRule the string that specifies how number should be
2434  *     transformed according to the regex specified in possibleNationalPrefix.
2435  * @param {RegExp} nationalNumberRule a regular expression that specifies what a
2436  *     valid phonenumber from this region should look like after any national
2437  *     prefix was stripped or transformed.
2438  */
2439 i18n.phonenumbers.PhoneNumberUtil.prototype.maybeStripNationalPrefix =
2440     function(number, possibleNationalPrefix, transformRule,
2441              nationalNumberRule) {
2442
2443   /** @type {string} */
2444   var numberStr = number.toString();
2445   /** @type {number} */
2446   var numberLength = numberStr.length;
2447   if (numberLength == 0 || possibleNationalPrefix == null ||
2448       possibleNationalPrefix.length == 0) {
2449     // Early return for numbers of zero length.
2450     return;
2451   }
2452   // Attempt to parse the first digits as a national prefix.
2453   /** @type {RegExp} */
2454   var re = new RegExp('^' + possibleNationalPrefix);
2455   /** @type {Array.<string>} */
2456   var m = re.exec(numberStr);
2457   if (m) {
2458     /** @type {string} */
2459     var transformedNumber;
2460     // m[1] == null implies nothing was captured by the capturing groups in
2461     // possibleNationalPrefix; therefore, no transformation is necessary, and
2462     // we just remove the national prefix.
2463     if (transformRule == null || transformRule.length == 0 || m[1] == null ||
2464         m[1].length == 0) {
2465       transformedNumber = numberStr.substring(m[0].length);
2466     } else {
2467       transformedNumber = numberStr.replace(re, transformRule);
2468     }
2469     // Check that the resultant number is viable. If not, return.
2470     if (!i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_(nationalNumberRule,
2471         transformedNumber)) {
2472       return;
2473     }
2474     number.clear();
2475     number.append(transformedNumber);
2476   }
2477 };
2478
2479
2480 /**
2481  * Strips any extension (as in, the part of the number dialled after the call is
2482  * connected, usually indicated with extn, ext, x or similar) from the end of
2483  * the number, and returns it.
2484  *
2485  * @param {!goog.string.StringBuffer} number the non-normalized telephone number
2486  *     that we wish to strip the extension from.
2487  * @return {string} the phone extension.
2488  */
2489 i18n.phonenumbers.PhoneNumberUtil.prototype.maybeStripExtension =
2490     function(number) {
2491
2492   /** @type {string} */
2493   var numberStr = number.toString();
2494   /** @type {number} */
2495   var mStart =
2496       numberStr.search(i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERN_);
2497   // If we find a potential extension, and the number preceding this is a viable
2498   // number, we assume it is an extension.
2499   if (mStart >= 0 && i18n.phonenumbers.PhoneNumberUtil.isViablePhoneNumber(
2500       numberStr.substring(0, mStart))) {
2501     // The numbers are captured into groups in the regular expression.
2502     /** @type {Array.<string>} */
2503     var matchedGroups =
2504         numberStr.match(i18n.phonenumbers.PhoneNumberUtil.EXTN_PATTERN_);
2505     /** @type {number} */
2506     var matchedGroupsLength = matchedGroups.length;
2507     for (var i = 1; i < matchedGroupsLength; ++i) {
2508       if (matchedGroups[i] != null && matchedGroups[i].length > 0) {
2509         number.clear();
2510         number.append(numberStr.substring(0, mStart));
2511         return matchedGroups[i];
2512       }
2513     }
2514   }
2515   return '';
2516 };
2517
2518
2519 /**
2520  * Checks to see that the region code used is valid, or if it is not valid, that
2521  * the number to parse starts with a + symbol so that we can attempt to infer
2522  * the country from the number.
2523  * @param {string} numberToParse number that we are attempting to parse.
2524  * @param {?string} defaultCountry the ISO 3166-1 two-letter country code that
2525  *     denotes the country that we are expecting the number to be from.
2526  * @return {boolean} false if it cannot use the region provided and the region
2527  *     cannot be inferred.
2528  * @private
2529  */
2530 i18n.phonenumbers.PhoneNumberUtil.prototype.checkRegionForParsing_ = function(
2531     numberToParse, defaultCountry) {
2532   // If the number is null or empty, we can't guess the country code.
2533   return this.isValidRegionCode_(defaultCountry) ||
2534       (numberToParse != null && numberToParse.length > 0 &&
2535           i18n.phonenumbers.PhoneNumberUtil.PLUS_CHARS_PATTERN_.test(
2536               numberToParse));
2537 };
2538
2539
2540 /**
2541  * Parses a string and returns it in proto buffer format. This method will throw
2542  * a i18n.phonenumbers.Error if the number is not considered to be a possible
2543  * number. Note that validation of whether the number is actually a valid number
2544  * for a particular country/region is not performed. This can be done separately
2545  * with isValidNumber.
2546  *
2547  * @param {string} numberToParse number that we are attempting to parse. This
2548  *     can contain formatting such as +, ( and -, as well as a phone number
2549  *     extension.
2550  * @param {?string} defaultCountry the ISO 3166-1 two-letter country code that
2551  *     denotes the country that we are expecting the number to be from. This is
2552  *     only used if the number being parsed is not written in international
2553  *     format. The country code for the number in this case would be stored as
2554  *     that of the default country supplied.  If the number is guaranteed to
2555  *     start with a '+' followed by the country code, then 'ZZ' or null can be
2556  *     supplied.
2557  * @return {i18n.phonenumbers.PhoneNumber} a phone number proto buffer filled
2558  *     with the parsed number.
2559  * @throws {i18n.phonenumbers.Error} if the string is not considered to be a
2560  *     viable phone number or if no default country was supplied and the number
2561  *     is not in international format (does not start with +).
2562  */
2563 i18n.phonenumbers.PhoneNumberUtil.prototype.parse = function(numberToParse,
2564                                                              defaultCountry) {
2565   return this.parseHelper_(numberToParse, defaultCountry, false, true);
2566 };
2567
2568
2569 /**
2570  * Parses a string and returns it in proto buffer format. This method differs
2571  * from parse() in that it always populates the raw_input field of the protocol
2572  * buffer with numberToParse as well as the country_code_source field.
2573  *
2574  * @param {string} numberToParse number that we are attempting to parse. This
2575  *     can contain formatting such as +, ( and -, as well as a phone number
2576  *     extension.
2577  * @param {?string} defaultCountry the ISO 3166-1 two-letter country code that
2578  *     denotes the country that we are expecting the number to be from. This is
2579  *     only used if the number being parsed is not written in international
2580  *     format. The country code for the number in this case would be stored as
2581  *     that of the default country supplied.
2582  * @return {i18n.phonenumbers.PhoneNumber} a phone number proto buffer filled
2583  *     with the parsed number.
2584  * @throws {i18n.phonenumbers.Error} if the string is not considered to be a
2585  *     viable phone number or if no default country was supplied and the number
2586  *     is not in international format (does not start with +).
2587  */
2588 i18n.phonenumbers.PhoneNumberUtil.prototype.parseAndKeepRawInput =
2589     function(numberToParse, defaultCountry) {
2590
2591   if (!this.isValidRegionCode_(defaultCountry)) {
2592     if (numberToParse.length > 0 && numberToParse.charAt(0) !=
2593         i18n.phonenumbers.PhoneNumberUtil.PLUS_SIGN) {
2594       throw i18n.phonenumbers.Error.INVALID_COUNTRY_CODE;
2595     }
2596   }
2597   return this.parseHelper_(numberToParse, defaultCountry, true, true);
2598 };
2599
2600
2601 /**
2602  * Parses a string and returns it in proto buffer format. This method is the
2603  * same as the public parse() method, with the exception that it allows the
2604  * default country to be null, for use by isNumberMatch().
2605  *
2606  * @param {string} numberToParse number that we are attempting to parse. This
2607  *     can contain formatting such as +, ( and -, as well as a phone number
2608  *     extension.
2609  * @param {?string} defaultCountry the ISO 3166-1 two-letter country code that
2610  *     denotes the country that we are expecting the number to be from. This is
2611  *     only used if the number being parsed is not written in international
2612  *     format. The country code for the number in this case would be stored as
2613  *     that of the default country supplied.
2614  * @param {boolean} keepRawInput whether to populate the raw_input field of the
2615  *     phoneNumber with numberToParse.
2616  * @param {boolean} checkRegion should be set to false if it is permitted for
2617  *     the default country to be null or unknown ('ZZ').
2618  * @return {i18n.phonenumbers.PhoneNumber} a phone number proto buffer filled
2619  *     with the parsed number.
2620  * @throws {i18n.phonenumbers.Error}
2621  * @private
2622  */
2623 i18n.phonenumbers.PhoneNumberUtil.prototype.parseHelper_ =
2624     function(numberToParse, defaultCountry, keepRawInput, checkRegion) {
2625
2626   if (numberToParse == null) {
2627     throw i18n.phonenumbers.Error.NOT_A_NUMBER;
2628   }
2629   // Extract a possible number from the string passed in (this strips leading
2630   // characters that could not be the start of a phone number.)
2631   /** @type {string} */
2632   var number =
2633       i18n.phonenumbers.PhoneNumberUtil.extractPossibleNumber(numberToParse);
2634   if (!i18n.phonenumbers.PhoneNumberUtil.isViablePhoneNumber(number)) {
2635     throw i18n.phonenumbers.Error.NOT_A_NUMBER;
2636   }
2637
2638   // Check the country supplied is valid, or that the extracted number starts
2639   // with some sort of + sign so the number's region can be determined.
2640   if (checkRegion && !this.checkRegionForParsing_(number, defaultCountry)) {
2641     throw i18n.phonenumbers.Error.INVALID_COUNTRY_CODE;
2642   }
2643
2644   /** @type {i18n.phonenumbers.PhoneNumber} */
2645   var phoneNumber = new i18n.phonenumbers.PhoneNumber();
2646   if (keepRawInput) {
2647     phoneNumber.setRawInput(numberToParse);
2648   }
2649   /** @type {!goog.string.StringBuffer} */
2650   var nationalNumber = new goog.string.StringBuffer(number);
2651   // Attempt to parse extension first, since it doesn't require
2652   // country-specific data and we want to have the non-normalised number here.
2653   /** @type {string} */
2654   var extension = this.maybeStripExtension(nationalNumber);
2655   if (extension.length > 0) {
2656     phoneNumber.setExtension(extension);
2657   }
2658
2659   /** @type {i18n.phonenumbers.PhoneMetadata} */
2660   var countryMetadata = this.getMetadataForRegion(defaultCountry);
2661   // Check to see if the number is given in international format so we know
2662   // whether this number is from the default country or not.
2663   /** @type {!goog.string.StringBuffer} */
2664   var normalizedNationalNumber = new goog.string.StringBuffer();
2665   /** @type {number} */
2666   var countryCode = this.maybeExtractCountryCode(nationalNumber.toString(),
2667       countryMetadata, normalizedNationalNumber, keepRawInput, phoneNumber);
2668   if (countryCode != 0) {
2669     /** @type {string} */
2670     var phoneNumberRegion = this.getRegionCodeForCountryCode(countryCode);
2671     if (phoneNumberRegion != defaultCountry) {
2672       countryMetadata = this.getMetadataForRegion(phoneNumberRegion);
2673     }
2674   } else {
2675     // If no extracted country code, use the region supplied instead. The
2676     // national number is just the normalized version of the number we were
2677     // given to parse.
2678     i18n.phonenumbers.PhoneNumberUtil.normalizeSB_(nationalNumber);
2679     normalizedNationalNumber.append(nationalNumber.toString());
2680     if (defaultCountry != null) {
2681       countryCode = countryMetadata.getCountryCodeOrDefault();
2682       phoneNumber.setCountryCode(countryCode);
2683     } else if (keepRawInput) {
2684       phoneNumber.clearCountryCodeSource();
2685     }
2686   }
2687   if (normalizedNationalNumber.getLength() <
2688       i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_) {
2689     throw i18n.phonenumbers.Error.TOO_SHORT_NSN;
2690   }
2691
2692   if (countryMetadata != null) {
2693     /** @type {RegExp} */
2694     var validNumberPattern =
2695         new RegExp(countryMetadata.getGeneralDesc().getNationalNumberPattern());
2696     this.maybeStripNationalPrefix(normalizedNationalNumber, countryMetadata
2697         .getNationalPrefixForParsing(), countryMetadata
2698         .getNationalPrefixTransformRule(), validNumberPattern);
2699   }
2700   /** @type {string} */
2701   var normalizedNationalNumberStr = normalizedNationalNumber.toString();
2702   /** @type {number} */
2703   var lengthOfNationalNumber = normalizedNationalNumberStr.length;
2704   if (lengthOfNationalNumber <
2705       i18n.phonenumbers.PhoneNumberUtil.MIN_LENGTH_FOR_NSN_) {
2706     throw i18n.phonenumbers.Error.TOO_SHORT_NSN;
2707   }
2708   if (lengthOfNationalNumber >
2709       i18n.phonenumbers.PhoneNumberUtil.MAX_LENGTH_FOR_NSN_) {
2710     throw i18n.phonenumbers.Error.TOO_LONG;
2711   }
2712   if (normalizedNationalNumberStr.charAt(0) == '0' &&
2713       i18n.phonenumbers.PhoneNumberUtil.isLeadingZeroCountry(countryCode)) {
2714     phoneNumber.setItalianLeadingZero(true);
2715   }
2716   phoneNumber.setNationalNumber(parseInt(normalizedNationalNumberStr, 10));
2717   return phoneNumber;
2718 };
2719
2720
2721 /**
2722  * Takes two phone numbers and compares them for equality.
2723  *
2724  * Returns EXACT_MATCH if the country code, NSN, presence of a leading zero for
2725  * Italian numbers and any extension present are the same. Returns NSN_MATCH if
2726  * either or both has no country specified, and the NSNs and extensions are the
2727  * same. Returns SHORT_NSN_MATCH if either or both has no country specified, or
2728  * the country specified is the same, and one NSN could be a shorter version of
2729  * the other number. This includes the case where one has an extension
2730  * specified, and the other does not. Returns NO_MATCH otherwise. For example,
2731  * the numbers +1 345 657 1234 and 657 1234 are a SHORT_NSN_MATCH. The numbers
2732  * +1 345 657 1234 and 345 657 are a NO_MATCH.
2733  *
2734  * @param {i18n.phonenumbers.PhoneNumber|string} firstNumberIn first number to
2735  *     compare. If it is a string it can contain formatting, and can have
2736  *     country code specified with + at the start.
2737  * @param {i18n.phonenumbers.PhoneNumber|string} secondNumberIn second number to
2738  *     compare. If it is a string it can contain formatting, and can have
2739  *     country code specified with + at the start.
2740  * @return {i18n.phonenumbers.PhoneNumberUtil.MatchType} NOT_A_NUMBER, NO_MATCH,
2741  *     SHORT_NSN_MATCH, NSN_MATCH or EXACT_MATCH depending on the level of
2742  *     equality of the two numbers, described in the method definition.
2743  */
2744 i18n.phonenumbers.PhoneNumberUtil.prototype.isNumberMatch =
2745     function(firstNumberIn, secondNumberIn) {
2746
2747   // If the input arguements are strings parse them to a proto buffer format.
2748   // Else make copies of the phone numbers so that the numbers passed in are not
2749   // edited.
2750   /** @type {i18n.phonenumbers.PhoneNumber} */
2751   var firstNumber;
2752   /** @type {i18n.phonenumbers.PhoneNumber} */
2753   var secondNumber;
2754   if (typeof firstNumberIn == 'string') {
2755     // First see if the first number has an implicit country code, by attempting
2756     // to parse it.
2757     try {
2758       firstNumber = this.parse(
2759           firstNumberIn, i18n.phonenumbers.PhoneNumberUtil.UNKNOWN_REGION_);
2760     } catch (e) {
2761       if (e != i18n.phonenumbers.Error.INVALID_COUNTRY_CODE) {
2762         return i18n.phonenumbers.PhoneNumberUtil.MatchType.NOT_A_NUMBER;
2763       }
2764       // The first number has no country code. EXACT_MATCH is no longer
2765       // possible. We parse it as if the region was the same as that for the
2766       // second number, and if EXACT_MATCH is returned, we replace this with
2767       // NSN_MATCH.
2768       if (typeof secondNumberIn != 'string') {
2769         /** @type {string} */
2770         var secondNumberRegion = this.getRegionCodeForCountryCode(
2771             secondNumberIn.getCountryCodeOrDefault());
2772         if (secondNumberRegion !=
2773             i18n.phonenumbers.PhoneNumberUtil.UNKNOWN_REGION_) {
2774           try {
2775             firstNumber = this.parse(firstNumberIn, secondNumberRegion);
2776           } catch (e2) {
2777             return i18n.phonenumbers.PhoneNumberUtil.MatchType.NOT_A_NUMBER;
2778           }
2779           /** @type {i18n.phonenumbers.PhoneNumberUtil.MatchType} */
2780           var match = this.isNumberMatch(firstNumber, secondNumberIn);
2781           if (match ==
2782               i18n.phonenumbers.PhoneNumberUtil.MatchType.EXACT_MATCH) {
2783             return i18n.phonenumbers.PhoneNumberUtil.MatchType.NSN_MATCH;
2784           }
2785           return match;
2786         }
2787       }
2788       // If the second number is a string or doesn't have a valid country code,
2789       // we parse the first number without country code.
2790       try {
2791         firstNumber = this.parseHelper_(firstNumberIn, null, false, false);
2792       } catch (e2) {
2793         return i18n.phonenumbers.PhoneNumberUtil.MatchType.NOT_A_NUMBER;
2794       }
2795     }
2796   } else {
2797     firstNumber = new i18n.phonenumbers.PhoneNumber();
2798     firstNumber.mergeFrom(firstNumberIn);
2799   }
2800   if (typeof secondNumberIn == 'string') {
2801     try {
2802       secondNumber = this.parse(
2803           secondNumberIn, i18n.phonenumbers.PhoneNumberUtil.UNKNOWN_REGION_);
2804       return this.isNumberMatch(firstNumberIn, secondNumber);
2805     } catch (e) {
2806       if (e != i18n.phonenumbers.Error.INVALID_COUNTRY_CODE) {
2807         return i18n.phonenumbers.PhoneNumberUtil.MatchType.NOT_A_NUMBER;
2808       }
2809       return this.isNumberMatch(secondNumberIn, firstNumber);
2810     }
2811   } else {
2812     secondNumber = new i18n.phonenumbers.PhoneNumber();
2813     secondNumber.mergeFrom(secondNumberIn);
2814   }
2815   // First clear raw_input and country_code_source field and any empty-string
2816   // extensions so that
2817   // we can use the PhoneNumber.exactlySameAs() method.
2818   firstNumber.clearRawInput();
2819   firstNumber.clearCountryCodeSource();
2820   secondNumber.clearRawInput();
2821   secondNumber.clearCountryCodeSource();
2822   if (firstNumber.hasExtension() && firstNumber.getExtension().length == 0) {
2823     firstNumber.clearExtension();
2824   }
2825   if (secondNumber.hasExtension() && secondNumber.getExtension().length == 0) {
2826     secondNumber.clearExtension();
2827   }
2828
2829   // Early exit if both had extensions and these are different.
2830   if (firstNumber.hasExtension() && secondNumber.hasExtension() &&
2831       firstNumber.getExtension() != secondNumber.getExtension()) {
2832     return i18n.phonenumbers.PhoneNumberUtil.MatchType.NO_MATCH;
2833   }
2834   /** @type {number} */
2835   var firstNumberCountryCode = firstNumber.getCountryCodeOrDefault();
2836   /** @type {number} */
2837   var secondNumberCountryCode = secondNumber.getCountryCodeOrDefault();
2838   // Both had country code specified.
2839   if (firstNumberCountryCode != 0 && secondNumberCountryCode != 0) {
2840     if (firstNumber.exactlySameAs(secondNumber)) {
2841       return i18n.phonenumbers.PhoneNumberUtil.MatchType.EXACT_MATCH;
2842     } else if (firstNumberCountryCode == secondNumberCountryCode &&
2843         this.isNationalNumberSuffixOfTheOther_(firstNumber, secondNumber)) {
2844       // A SHORT_NSN_MATCH occurs if there is a difference because of the
2845       // presence or absence of an 'Italian leading zero', the presence or
2846       // absence of an extension, or one NSN being a shorter variant of the
2847       // other.
2848       return i18n.phonenumbers.PhoneNumberUtil.MatchType.SHORT_NSN_MATCH;
2849     }
2850     // This is not a match.
2851     return i18n.phonenumbers.PhoneNumberUtil.MatchType.NO_MATCH;
2852   }
2853   // Checks cases where one or both country codes were not specified. To make
2854   // equality checks easier, we first set the country codes to be equal.
2855   firstNumber.setCountryCode(0);
2856   secondNumber.setCountryCode(0);
2857   // If all else was the same, then this is an NSN_MATCH.
2858   if (firstNumber.exactlySameAs(secondNumber)) {
2859     return i18n.phonenumbers.PhoneNumberUtil.MatchType.NSN_MATCH;
2860   }
2861   if (this.isNationalNumberSuffixOfTheOther_(firstNumber, secondNumber)) {
2862     return i18n.phonenumbers.PhoneNumberUtil.MatchType.SHORT_NSN_MATCH;
2863   }
2864   return i18n.phonenumbers.PhoneNumberUtil.MatchType.NO_MATCH;
2865 };
2866
2867
2868 /**
2869  * Returns true when one national number is the suffix of the other or both are
2870  * the same.
2871  *
2872  * @param {i18n.phonenumbers.PhoneNumber} firstNumber the first PhoneNumber
2873  *     object.
2874  * @param {i18n.phonenumbers.PhoneNumber} secondNumber the second PhoneNumber
2875  *     object.
2876  * @return {boolean} true if one PhoneNumber is the suffix of the other one.
2877  * @private
2878  */
2879 i18n.phonenumbers.PhoneNumberUtil.prototype.isNationalNumberSuffixOfTheOther_ =
2880     function(firstNumber, secondNumber) {
2881
2882   /** @type {string} */
2883   var firstNumberNationalNumber = '' + firstNumber.getNationalNumber();
2884   /** @type {string} */
2885   var secondNumberNationalNumber = '' + secondNumber.getNationalNumber();
2886   // Note that endsWith returns true if the numbers are equal.
2887   return goog.string.endsWith(firstNumberNationalNumber,
2888                               secondNumberNationalNumber) ||
2889          goog.string.endsWith(secondNumberNationalNumber,
2890                               firstNumberNationalNumber);
2891 };
2892
2893
2894 /**
2895  * Returns true if the number can only be dialled from within the country. If
2896  * unknown, or the number can be dialled from outside the country as well,
2897  * returns false. Does not check the number is a valid number.
2898  * TODO: Make this method public when we have enough metadata to make it
2899  * worthwhile. Currently visible for testing purposes only.
2900  *
2901  * @param {i18n.phonenumbers.PhoneNumber} number the phone-number for which we
2902  *     want to know whether it is only diallable from within the country.
2903  * @return {boolean} true if the number can only be dialled from within the
2904  *     country.
2905  */
2906 i18n.phonenumbers.PhoneNumberUtil.prototype.canBeInternationallyDialled =
2907     function(number) {
2908   /** @type {?string} */
2909   var regionCode = this.getRegionCodeForNumber(number);
2910   /** @type {string} */
2911   var nationalSignificantNumber =
2912       i18n.phonenumbers.PhoneNumberUtil.getNationalSignificantNumber(number);
2913   if (!this.isValidRegionCode_(regionCode)) {
2914     return true;
2915   }
2916   /** @type {i18n.phonenumbers.PhoneMetadata} */
2917   var metadata = this.getMetadataForRegion(regionCode);
2918   return !this.isNumberMatchingDesc_(nationalSignificantNumber,
2919                                      metadata.getNoInternationalDialling());
2920 };
2921
2922
2923 /**
2924  * Check whether the entire input sequence can be matched against the regular
2925  * expression.
2926  *
2927  * @param {RegExp|string} regex the regular expression to match against.
2928  * @param {string} str the string to test.
2929  * @return {boolean} true if str can be matched entirely against regex.
2930  * @private
2931  */
2932 i18n.phonenumbers.PhoneNumberUtil.matchesEntirely_ = function(regex, str) {
2933   /** @type {Array.<string>} */
2934   var matchedGroups = str.match(regex);
2935   if (matchedGroups && matchedGroups[0].length == str.length) {
2936     return true;
2937   }
2938   return false;
2939 };
2940
2941
2942 /**
2943  * @param {i18n.phonenumbers.PhoneNumber} other
2944  * @return {boolean}
2945  */
2946 i18n.phonenumbers.PhoneNumber.prototype.exactlySameAs = function(other) {
2947   return other != null &&
2948       this.getCountryCode() == other.getCountryCode() &&
2949       this.getNationalNumber() == other.getNationalNumber() &&
2950       this.getExtension() == other.getExtension() &&
2951       this.getItalianLeadingZero() == other.getItalianLeadingZero() &&
2952       this.getRawInput() == other.getRawInput() &&
2953       this.getCountryCodeSource() == other.getCountryCodeSource();
2954 };
2955
2956
2957 /**
2958  * @param {i18n.phonenumbers.PhoneNumberDesc} other
2959  * @return {boolean}
2960  */
2961 i18n.phonenumbers.PhoneNumberDesc.prototype.exactlySameAs = function(other) {
2962   return other != null &&
2963       this.getNationalNumberPattern() == other.getNationalNumberPattern() &&
2964       this.getPossibleNumberPattern() == other.getPossibleNumberPattern() &&
2965       this.getExampleNumber() == other.getExampleNumber();
2966 };
2967
2968
2969 /**
2970  * @param {i18n.phonenumbers.PhoneNumber} other
2971  * @return {i18n.phonenumbers.PhoneNumber}
2972  * @suppress {accessControls}
2973  */
2974 i18n.phonenumbers.PhoneNumber.prototype.mergeFrom = function(other) {
2975   if (other) {
2976     this.values_ = goog.cloneObject(other.values_);
2977   }
2978   return this;
2979 };
2980
2981
2982 /**
2983  * @param {i18n.phonenumbers.NumberFormat} other
2984  * @return {i18n.phonenumbers.NumberFormat}
2985  * @suppress {accessControls}
2986  */
2987 i18n.phonenumbers.NumberFormat.prototype.mergeFrom = function(other) {
2988   if (other) {
2989     this.values_ = goog.cloneObject(other.values_);
2990   }
2991   return this;
2992 };