/**
 * Parses a string and returns it in proto buffer format. This method differs from {@link #parse}
 * in that it always populates the raw_input field of the protocol buffer with numberToParse as
 * well as the country_code_source field.
 *
 * @param numberToParse     number that we are attempting to parse. This can contain formatting
 *                          such as +, ( and -, as well as a phone number extension.
 * @param defaultRegion     region that we are expecting the number to be from. This is only used
 *                          if the number being parsed is not written in international format.
 *                          The country calling code for the number in this case would be stored
 *                          as that of the default region supplied.
 * @return                  a phone number proto buffer filled with the parsed number
 * @throws NumberParseException  if the string is not considered to be a viable phone number or if
 *                               no default region was supplied
 */
 public PhoneNumber ParseAndKeepRawInput(String numberToParse, String defaultRegion)
 {
     var phoneNumber = new PhoneNumber.Builder();
     ParseAndKeepRawInput(numberToParse, defaultRegion, phoneNumber);
     return phoneNumber.Build();
 }
 /**
 * Takes two phone numbers and compares them for equality. This is a convenience wrapper for
 * {@link #isNumberMatch(PhoneNumber, PhoneNumber)}. No default region is known.
 *
 * @param firstNumber  first number to compare in proto buffer format.
 * @param secondNumber  second number to compare. Can contain formatting, and can have country
 *     calling code specified with + at the start.
 * @return  NOT_A_NUMBER, NO_MATCH, SHORT_NSN_MATCH, NSN_MATCH, EXACT_MATCH. See
 *     {@link #isNumberMatch(PhoneNumber, PhoneNumber)} for more details.
 */
 public MatchType IsNumberMatch(PhoneNumber firstNumber, String secondNumber)
 {
     // First see if the second number has an implicit country calling code, by attempting to parse
     // it.
     try
     {
         PhoneNumber secondNumberAsProto = Parse(secondNumber, UNKNOWN_REGION);
         return IsNumberMatch(firstNumber, secondNumberAsProto);
     }
     catch (NumberParseException e)
     {
         if (e.ErrorType == ErrorType.INVALID_COUNTRY_CODE)
         {
             // The second number has no country calling code. EXACT_MATCH is no longer possible.
             // We parse it as if the region was the same as that for the first number, and if
             // EXACT_MATCH is returned, we replace this with NSN_MATCH.
             String firstNumberRegion = GetRegionCodeForCountryCode(firstNumber.CountryCode);
             try
             {
                 if (!firstNumberRegion.Equals(UNKNOWN_REGION))
                 {
                     PhoneNumber secondNumberWithFirstNumberRegion = Parse(secondNumber, firstNumberRegion);
                     MatchType match = IsNumberMatch(firstNumber, secondNumberWithFirstNumberRegion);
                     if (match == MatchType.EXACT_MATCH)
                         return MatchType.NSN_MATCH;
                     return match;
                 }
                 else
                 {
                     // If the first number didn't have a valid country calling code, then we parse the
                     // second number without one as well.
                     var secondNumberProto = new PhoneNumber.Builder();
                     ParseHelper(secondNumber, null, false, false, secondNumberProto);
                     return IsNumberMatch(firstNumber, secondNumberProto.Build());
                 }
             }
             catch (NumberParseException)
             {
                 // Fall-through to return NOT_A_NUMBER.
             }
         }
     }
     // One or more of the phone numbers we are trying to match is not a viable phone number.
     return MatchType.NOT_A_NUMBER;
 }
 /**
 * Takes two phone numbers as strings and compares them for equality. This is a convenience
 * wrapper for {@link #isNumberMatch(PhoneNumber, PhoneNumber)}. No default region is known.
 *
 * @param firstNumber  first number to compare. Can contain formatting, and can have country
 *     calling code specified with + at the start.
 * @param secondNumber  second number to compare. Can contain formatting, and can have country
 *     calling code specified with + at the start.
 * @return  NOT_A_NUMBER, NO_MATCH, SHORT_NSN_MATCH, NSN_MATCH, EXACT_MATCH. See
 *     {@link #isNumberMatch(PhoneNumber, PhoneNumber)} for more details.
 */
 public MatchType IsNumberMatch(String firstNumber, String secondNumber)
 {
     try
     {
         PhoneNumber firstNumberAsProto = Parse(firstNumber, UNKNOWN_REGION);
         return IsNumberMatch(firstNumberAsProto, secondNumber);
     }
     catch (NumberParseException e)
     {
         if (e.ErrorType == ErrorType.INVALID_COUNTRY_CODE)
         {
             try
             {
                 PhoneNumber secondNumberAsProto = Parse(secondNumber, UNKNOWN_REGION);
                 return IsNumberMatch(secondNumberAsProto, firstNumber);
             }
             catch (NumberParseException e2)
             {
                 if (e2.ErrorType == ErrorType.INVALID_COUNTRY_CODE)
                 {
                     try
                     {
                         var firstNumberProto = new PhoneNumber.Builder();
                         var secondNumberProto = new PhoneNumber.Builder();
                         ParseHelper(firstNumber, null, false, false, firstNumberProto);
                         ParseHelper(secondNumber, null, false, false, secondNumberProto);
                         return IsNumberMatch(firstNumberProto.Build(), secondNumberProto.Build());
                     }
                     catch (NumberParseException)
                     {
                         // Fall through and return MatchType.NOT_A_NUMBER.
                     }
                 }
             }
         }
     }
     // One or more of the phone numbers we are trying to match is not a viable phone number.
     return MatchType.NOT_A_NUMBER;
 }
        /**
        * Takes two phone numbers and compares them for equality.
        *
        * <p>Returns EXACT_MATCH if the country_code, NSN, presence of a leading zero for Italian numbers
        * and any extension present are the same.
        * Returns NSN_MATCH if either or both has no region specified, and the NSNs and extensions are
        * the same.
        * Returns SHORT_NSN_MATCH if either or both has no region specified, or the region specified is
        * the same, and one NSN could be a shorter version of the other number. This includes the case
        * where one has an extension specified, and the other does not.
        * Returns NO_MATCH otherwise.
        * For example, the numbers +1 345 657 1234 and 657 1234 are a SHORT_NSN_MATCH.
        * The numbers +1 345 657 1234 and 345 657 are a NO_MATCH.
        *
        * @param firstNumberIn  first number to compare
        * @param secondNumberIn  second number to compare
        *
        * @return  NO_MATCH, SHORT_NSN_MATCH, NSN_MATCH or EXACT_MATCH depending on the level of equality
        *     of the two numbers, described in the method definition.
        */
        public MatchType IsNumberMatch(PhoneNumber firstNumberIn, PhoneNumber secondNumberIn)
        {
            // Make copies of the phone number so that the numbers passed in are not edited.
            var firstNumber = new PhoneNumber.Builder();
            firstNumber.MergeFrom(firstNumberIn);
            var secondNumber = new PhoneNumber.Builder();
            secondNumber.MergeFrom(secondNumberIn);
            // First clear raw_input, country_code_source and preferred_domestic_carrier_code fields and any
            // empty-string extensions so that we can use the proto-buffer equality method.
            firstNumber.ClearRawInput();
            firstNumber.ClearCountryCodeSource();
            firstNumber.ClearPreferredDomesticCarrierCode();
            secondNumber.ClearRawInput();
            secondNumber.ClearCountryCodeSource();
            secondNumber.ClearPreferredDomesticCarrierCode();
            if (firstNumber.HasExtension &&
                firstNumber.Extension.Length == 0)
                firstNumber.ClearExtension();

            if (secondNumber.HasExtension &&
                secondNumber.Extension.Length == 0)
                secondNumber.ClearExtension();

            // Early exit if both had extensions and these are different.
            if (firstNumber.HasExtension && secondNumber.HasExtension &&
                !firstNumber.Extension.Equals(secondNumber.Extension))
                return MatchType.NO_MATCH;

            int firstNumberCountryCode = firstNumber.CountryCode;
            int secondNumberCountryCode = secondNumber.CountryCode;
            // Both had country_code specified.
            if (firstNumberCountryCode != 0 && secondNumberCountryCode != 0)
            {
                if (AreEqual(firstNumber, secondNumber))
                    return MatchType.EXACT_MATCH;
                else if (firstNumberCountryCode == secondNumberCountryCode &&
                    IsNationalNumberSuffixOfTheOther(firstNumber, secondNumber))
                {
                    // A SHORT_NSN_MATCH occurs if there is a difference because of the presence or absence of
                    // an 'Italian leading zero', the presence or absence of an extension, or one NSN being a
                    // shorter variant of the other.
                    return MatchType.SHORT_NSN_MATCH;
                }
                // This is not a match.
                return MatchType.NO_MATCH;
            }
            // Checks cases where one or both country_code fields were not specified. To make equality
            // checks easier, we first set the country_code fields to be equal.
            firstNumber.SetCountryCode(secondNumberCountryCode);
            // If all else was the same, then this is an NSN_MATCH.
            if (AreEqual(firstNumber, secondNumber))
                return MatchType.NSN_MATCH;

            if (IsNationalNumberSuffixOfTheOther(firstNumber, secondNumber))
                return MatchType.SHORT_NSN_MATCH;
            return MatchType.NO_MATCH;
        }
        /**
        * Gets the length of the national destination code (NDC) from the PhoneNumber object passed in,
        * so that clients could use it to split a national significant number into NDC and subscriber
        * number. The NDC of a phone number is normally the first group of digit(s) right after the
        * country calling code when the number is formatted in the international format, if there is a
        * subscriber number part that follows. An example of how this could be used:
        *
        * <pre>
        * PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
        * PhoneNumber number = phoneUtil.parse("18002530000", "US");
        * String nationalSignificantNumber = phoneUtil.getNationalSignificantNumber(number);
        * String nationalDestinationCode;
        * String subscriberNumber;
        *
        * int nationalDestinationCodeLength = phoneUtil.getLengthOfNationalDestinationCode(number);
        * if (nationalDestinationCodeLength > 0) {
        *   nationalDestinationCode = nationalSignificantNumber.substring(0,
        *       nationalDestinationCodeLength);
        *   subscriberNumber = nationalSignificantNumber.substring(nationalDestinationCodeLength);
        * } else {
        *   nationalDestinationCode = "";
        *   subscriberNumber = nationalSignificantNumber;
        * }
        * </pre>
        *
        * Refer to the unittests to see the difference between this function and
        * {@link #getLengthOfGeographicalAreaCode}.
        *
        * @param number  the PhoneNumber object for which clients want to know the length of the NDC.
        * @return  the length of NDC of the PhoneNumber object passed in.
        */
        public int GetLengthOfNationalDestinationCode(PhoneNumber number)
        {
            PhoneNumber copiedProto;
            if (number.HasExtension)
            {
                // We don't want to alter the proto given to us, but we don't want to include the extension
                // when we format it, so we copy it and clear the extension here.
                var builder = new PhoneNumber.Builder();
                builder.MergeFrom(number);
                builder.ClearExtension();
                copiedProto = builder.Build();
            }
            else
            {
                copiedProto = number;
            }
            var nationalSignificantNumber = Format(copiedProto, PhoneNumberFormat.INTERNATIONAL);
            var numberGroups = NON_DIGITS_PATTERN.Split(nationalSignificantNumber);
            // The pattern will start with "+COUNTRY_CODE " so the first group will always be the empty
            // string (before the + symbol) and the second group will be the country calling code. The third
            // group will be area code if it is not the last group.
            if (numberGroups.Length <= 3)
                return 0;

            if (GetRegionCodeForCountryCode(number.CountryCode) == "AR" && GetNumberType(number) == PhoneNumberType.MOBILE)
                // Argentinian mobile numbers, when formatted in the international format, are in the form of
                // +54 9 NDC XXXX.... As a result, we take the length of the third group (NDC) and add 1 for
                // the digit 9, which also forms part of the national significant number.
                //
                // TODO: Investigate the possibility of better modeling the metadata to make it
                // easier to obtain the NDC.
                return numberGroups[3].Length + 1;
            return numberGroups[2].Length;
        }
        /**
        * Returns a number formatted in such a way that it can be dialed from a mobile phone in a
        * specific region. If the number cannot be reached from the region (e.g. some countries block
        * toll-free numbers from being called outside of the country), the method returns an empty
        * string.
        *
        * @param number  the phone number to be formatted
        * @param regionCallingFrom  the region where the call is being placed
        * @param withFormatting  whether the number should be returned with formatting symbols, such as
        *     spaces and dashes.
        * @return  the formatted phone number
        */
        public String FormatNumberForMobileDialing(PhoneNumber number, String regionCallingFrom,
            bool withFormatting)
        {
            int countryCallingCode = number.CountryCode;
            if (!HasValidCountryCallingCode(countryCallingCode))
            {
                return number.HasRawInput ? number.RawInput : "";
            }

            String formattedNumber;
            // Clear the extension, as that part cannot normally be dialed together with the main number.
            PhoneNumber numberNoExt = new PhoneNumber.Builder().MergeFrom(number).ClearExtension().Build();
            PhoneNumberType numberType = GetNumberType(numberNoExt);
            String regionCode = GetRegionCodeForCountryCode(countryCallingCode);
            if (regionCode.Equals("CO") && regionCallingFrom.Equals("CO"))
            {
                if (numberType == PhoneNumberType.FIXED_LINE)
                {
                    formattedNumber =
                        FormatNationalNumberWithCarrierCode(numberNoExt, COLOMBIA_MOBILE_TO_FIXED_LINE_PREFIX);
                }
                else
                {
                    // E164 doesn't work at all when dialing within Colombia.
                    formattedNumber = Format(numberNoExt, PhoneNumberFormat.NATIONAL);
                }
            }
            else if (regionCode.Equals("PE") && regionCallingFrom.Equals("PE"))
            {
                // In Peru, numbers cannot be dialled using E164 format from a mobile phone for Movistar.
                // Instead they must be dialled in national format.
                formattedNumber = Format(numberNoExt, PhoneNumberFormat.NATIONAL);
            }
            else if (regionCode.Equals("BR") && regionCallingFrom.Equals("BR") &&
                ((numberType == PhoneNumberType.FIXED_LINE) || (numberType == PhoneNumberType.MOBILE) ||
                (numberType == PhoneNumberType.FIXED_LINE_OR_MOBILE)))
            {
                formattedNumber = numberNoExt.HasPreferredDomesticCarrierCode
                    ? FormatNationalNumberWithPreferredCarrierCode(numberNoExt, "")
                    // Brazilian fixed line and mobile numbers need to be dialed with a carrier code when
                    // called within Brazil. Without that, most of the carriers won't connect the call.
                    // Because of that, we return an empty string here.
                    : "";
            }
            else if (CanBeInternationallyDialled(numberNoExt))
            {
                return withFormatting ? Format(numberNoExt, PhoneNumberFormat.INTERNATIONAL)
                    : Format(numberNoExt, PhoneNumberFormat.E164);
            }
            else
            {
                formattedNumber = (regionCallingFrom == regionCode)
                    ? Format(numberNoExt, PhoneNumberFormat.NATIONAL) : "";
            }
            return withFormatting ? formattedNumber
                : NormalizeHelper(formattedNumber, DIALLABLE_CHAR_MAPPINGS,
                    true /* remove non matches */);
        }