private boolean matchesEmergencyNumberHelper(String number, String regionCode,
                                                     boolean allowPrefixMatch)
        {
            number = PhoneNumberUtil.extractPossibleNumber(number);
            if (PhoneNumberUtil.PLUS_CHARS_PATTERN.matcher(number).lookingAt())
            {
                // Returns false if the number starts with a plus sign. We don't believe dialing the country
                // code before emergency numbers (e.g. +1911) works, but later, if that proves to work, we can
                // add additional logic here to handle it.
                return(false);
            }
            PhoneMetadata metadata = MetadataManager.getShortNumberMetadataForRegion(regionCode);

            if (metadata == null || !metadata.hasEmergency())
            {
                return(false);
            }
            Pattern emergencyNumberPattern =
                Pattern.compile(metadata.getEmergency().getNationalNumberPattern());
            String normalizedNumber = PhoneNumberUtil.normalizeDigitsOnly(number);

            // In Brazil and Chile, emergency numbers don't work when additional digits are appended.
            return((!allowPrefixMatch || regionCode == "BR" || regionCode == "CL")
        ? emergencyNumberPattern.matcher(normalizedNumber).matches()
        : emergencyNumberPattern.matcher(normalizedNumber).lookingAt());
        }
        /**
         * Gets a valid short number for the specified cost category.
         *
         * @param regionCode the region for which an example short number is needed
         * @param cost the cost category of number that is needed
         * @return a valid short number for the specified region and cost category. Returns an empty
         *     string when the metadata does not contain such information, or the cost is UNKNOWN_COST.
         */
        // @VisibleForTesting
        internal String getExampleShortNumberForCost(String regionCode, ShortNumberCost cost)
        {
            PhoneMetadata phoneMetadata = MetadataManager.getShortNumberMetadataForRegion(regionCode);

            if (phoneMetadata == null)
            {
                return("");
            }
            PhoneNumberDesc desc = null;

            switch (cost)
            {
            case ShortNumberCost.TOLL_FREE:
                desc = phoneMetadata.getTollFree();
                break;

            case ShortNumberCost.STANDARD_RATE:
                desc = phoneMetadata.getStandardRate();
                break;

            case ShortNumberCost.PREMIUM_RATE:
                desc = phoneMetadata.getPremiumRate();
                break;

            default:
                // UNKNOWN_COST numbers are computed by the process of elimination from the other cost
                // categories.
                break;
            }
            if (desc != null && desc.hasExampleNumber())
            {
                return(desc.getExampleNumber());
            }
            return("");
        }
        // Helper method to get the region code for a given phone number, from a list of possible region
        // codes. If the list contains more than one region, the first region for which the number is
        // valid is returned.
        private String getRegionCodeForShortNumberFromRegionList(PhoneNumber number,
                                                                 List <String> regionCodes)
        {
            if (regionCodes.size() == 0)
            {
                return(null);
            }
            else if (regionCodes.size() == 1)
            {
                return(regionCodes.get(0));
            }
            String nationalNumber = phoneUtil.getNationalSignificantNumber(number);

            foreach (String regionCode in regionCodes)
            {
                PhoneMetadata phoneMetadata = MetadataManager.getShortNumberMetadataForRegion(regionCode);
                if (phoneMetadata != null &&
                    phoneUtil.isNumberMatchingDesc(nationalNumber, phoneMetadata.getShortCode()))
                {
                    // The number is valid for this region.
                    return(regionCode);
                }
            }
            return(null);
        }
        /**
         * Gets the expected cost category of a short number (however, nothing is implied about its
         * validity). If it is important that the number is valid, then its validity must first be checked
         * using {@link isValidShortNumber}. Note that emergency numbers are always considered toll-free.
         * Example usage:
         * <pre>{@code
         * PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
         * ShortNumberInfo shortInfo = ShortNumberInfo.getInstance();
         * PhoneNumber number = phoneUtil.parse("110", "FR");
         * if (shortInfo.isValidShortNumber(number)) {
         *   ShortNumberInfo.ShortNumberCost cost = shortInfo.getExpectedCost(number);
         *   // Do something with the cost information here.
         * }}</pre>
         *
         * @param number the short number for which we want to know the expected cost category
         * @return the expected cost category of the short number. Returns UNKNOWN_COST if the number does
         *     not match a cost category. Note that an invalid number may match any cost category.
         */
        public ShortNumberCost getExpectedCost(PhoneNumber number)
        {
            List <String> regionCodes = phoneUtil.getRegionCodesForCountryCode(number.getCountryCode());
            String        regionCode  = getRegionCodeForShortNumberFromRegionList(number, regionCodes);

            // Note that regionCode may be null, in which case phoneMetadata will also be null.
            PhoneMetadata phoneMetadata = MetadataManager.getShortNumberMetadataForRegion(regionCode);

            if (phoneMetadata == null)
            {
                return(ShortNumberCost.UNKNOWN_COST);
            }
            String nationalNumber = phoneUtil.getNationalSignificantNumber(number);

            // The cost categories are tested in order of decreasing expense, since if for some reason the
            // patterns overlap the most expensive matching cost category should be returned.
            if (phoneUtil.isNumberMatchingDesc(nationalNumber, phoneMetadata.getPremiumRate()))
            {
                return(ShortNumberCost.PREMIUM_RATE);
            }
            if (phoneUtil.isNumberMatchingDesc(nationalNumber, phoneMetadata.getStandardRate()))
            {
                return(ShortNumberCost.STANDARD_RATE);
            }
            if (phoneUtil.isNumberMatchingDesc(nationalNumber, phoneMetadata.getTollFree()))
            {
                return(ShortNumberCost.TOLL_FREE);
            }
            if (isEmergencyNumber(nationalNumber, regionCode))
            {
                // Emergency numbers are implicitly toll-free.
                return(ShortNumberCost.TOLL_FREE);
            }
            return(ShortNumberCost.UNKNOWN_COST);
        }
        /**
         * Tests whether a short number matches a valid pattern. Note that this doesn't verify the number
         * is actually in use, which is impossible to tell by just looking at the number itself.
         *
         * @param shortNumber the short number to check as a string
         * @param regionDialingFrom the region from which the number is dialed
         * @return whether the short number matches a valid pattern
         */
        public boolean isValidShortNumber(String shortNumber, String regionDialingFrom)
        {
            PhoneMetadata phoneMetadata =
                MetadataManager.getShortNumberMetadataForRegion(regionDialingFrom);

            if (phoneMetadata == null)
            {
                return(false);
            }
            PhoneNumberDesc generalDesc = phoneMetadata.getGeneralDesc();

            if (!generalDesc.hasNationalNumberPattern() ||
                !phoneUtil.isNumberMatchingDesc(shortNumber, generalDesc))
            {
                return(false);
            }
            PhoneNumberDesc shortNumberDesc = phoneMetadata.getShortCode();

            if (!shortNumberDesc.hasNationalNumberPattern())
            {
                logger.log(Level.WARNING, "No short code national number pattern found for region: " +
                           regionDialingFrom);
                return(false);
            }
            return(phoneUtil.isNumberMatchingDesc(shortNumber, shortNumberDesc));
        }
        [TestMethod] public void testShortNumberMetadataContainsData()
        {
            // We should have some data for France.
            PhoneMetadata franceShortNumberMetadata = MetadataManager.getShortNumberMetadataForRegion("FR");

            assertNotNull(franceShortNumberMetadata);
            assertTrue(franceShortNumberMetadata.hasShortCode());
        }
        /**
         * Given a valid short number, determines whether it is carrier-specific (however, nothing is
         * implied about its validity). If it is important that the number is valid, then its validity
         * must first be checked using {@link isValidShortNumber}.
         *
         * @param number the valid short number to check
         * @return whether the short number is carrier-specific (assuming the input was a valid short
         *     number).
         */
        public boolean isCarrierSpecific(PhoneNumber number)
        {
            List <String> regionCodes    = phoneUtil.getRegionCodesForCountryCode(number.getCountryCode());
            String        regionCode     = getRegionCodeForShortNumberFromRegionList(number, regionCodes);
            String        nationalNumber = phoneUtil.getNationalSignificantNumber(number);
            PhoneMetadata phoneMetadata  = MetadataManager.getShortNumberMetadataForRegion(regionCode);

            return((phoneMetadata != null) &&
                   (phoneUtil.isNumberMatchingDesc(nationalNumber, phoneMetadata.getCarrierSpecific())));
        }
        /**
         * Check whether a short number is a possible number, given the number in the form of a string,
         * and the region where the number is dialed from. This provides a more lenient check than
         * {@link #isValidShortNumber}.
         *
         * @param shortNumber the short number to check as a string
         * @param regionDialingFrom the region from which the number is dialed
         * @return whether the number is a possible short number
         */
        public boolean isPossibleShortNumber(String shortNumber, String regionDialingFrom)
        {
            PhoneMetadata phoneMetadata =
                MetadataManager.getShortNumberMetadataForRegion(regionDialingFrom);

            if (phoneMetadata == null)
            {
                return(false);
            }
            PhoneNumberDesc generalDesc = phoneMetadata.getGeneralDesc();

            return(phoneUtil.isNumberPossibleForDesc(shortNumber, generalDesc));
        }
        /**
         * Gets a valid short number for the specified region.
         *
         * @param regionCode the region for which an example short number is needed
         * @return a valid short number for the specified region. Returns an empty string when the
         *     metadata does not contain such information.
         */
        // @VisibleForTesting
        internal String getExampleShortNumber(String regionCode)
        {
            PhoneMetadata phoneMetadata = MetadataManager.getShortNumberMetadataForRegion(regionCode);

            if (phoneMetadata == null)
            {
                return("");
            }
            PhoneNumberDesc desc = phoneMetadata.getShortCode();

            if (desc.hasExampleNumber())
            {
                return(desc.getExampleNumber());
            }
            return("");
        }
        [TestMethod] public void testEmergency()
        {
            int wrongTypeCounter = 0;

            foreach (String regionCode in shortNumberInfo.getSupportedRegions())
            {
                if (regionCode == RegionCode.PG)
                {
                    // The only short number for Papua New Guinea is 000, which fails the test, since the
                    // national prefix is 0. This needs to be fixed.
                    continue;
                }
                PhoneNumberDesc desc =
                    MetadataManager.getShortNumberMetadataForRegion(regionCode).getEmergency();
                if (desc.hasExampleNumber())
                {
                    String exampleNumber = desc.getExampleNumber();
                    if (!exampleNumber.matches(desc.getPossibleNumberPattern()) ||
                        !shortNumberInfo.isEmergencyNumber(exampleNumber, regionCode))
                    {
                        wrongTypeCounter++;
                        LOGGER.log(Level.SEVERE, "Emergency example number test failed for " + regionCode);
                    }
                    else
                    {
                        PhoneNumber emergencyNumber = phoneNumberUtil.parse(exampleNumber, regionCode);
                        if (shortNumberInfo.getExpectedCost(emergencyNumber) !=
                            ShortNumberInfo.ShortNumberCost.TOLL_FREE)
                        {
                            wrongTypeCounter++;
                            LOGGER.log(Level.SEVERE, "Emergency example number not toll free for " + regionCode);
                        }
                    }
                }
            }
            assertEquals(0, wrongTypeCounter);
        }
        [TestMethod] public void testShortNumberMetadataFailsGracefully()
        {
            PhoneMetadata noShortNumberMetadata = MetadataManager.getShortNumberMetadataForRegion("XXX");

            assertNull(noShortNumberMetadata);
        }