12ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/* GENERATED SOURCE. DO NOT MODIFY. */
2f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert// © 2016 and later: Unicode, Inc. and others.
3f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html#License
42ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/*
52ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *******************************************************************************
6f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert * Copyright (C) 2011-2016, International Business Machines Corporation
7f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert * All Rights Reserved.
82ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *******************************************************************************
92ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */
102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpackage android.icu.util;
112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.ArrayList;
132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Arrays;
142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Collections;
152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.HashMap;
162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.List;
172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Map;
182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Set;
192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.TreeSet;
202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
21f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubertimport android.icu.impl.ICUData;
222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.impl.ICUResourceBundle;
232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/**
252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <code>Region</code> is the class representing a Unicode Region Code, also known as a
262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Unicode Region Subtag, which is defined based upon the BCP 47 standard. We often think of
272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * "regions" as "countries" when defining the characteristics of a locale.  Region codes There are different
282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * types of region codes that are important to distinguish.
292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>
302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  Macroregion - A code for a "macro geographical (continental) region, geographical sub-region, or
312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  selected economic and other grouping" as defined in
322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  UN M.49 (http://unstats.un.org/unsd/methods/m49/m49regin.htm).
332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  These are typically 3-digit codes, but contain some 2-letter codes, such as the LDML code QO
342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  added for Outlying Oceania.  Not all UNM.49 codes are defined in LDML, but most of them are.
352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  Macroregions are represented in ICU by one of three region types: WORLD ( region code 001 ),
362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  CONTINENTS ( regions contained directly by WORLD ), and SUBCONTINENTS ( things contained directly
372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  by a continent ).
382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  <p>
392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  TERRITORY - A Region that is not a Macroregion. These are typically codes for countries, but also
402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  include areas that are not separate countries, such as the code "AQ" for Antarctica or the code
412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  "HK" for Hong Kong (SAR China). Overseas dependencies of countries may or may not have separate
422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  codes. The codes are typically 2-letter codes aligned with the ISO 3166 standard, but BCP47 allows
432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  for the use of 3-digit codes in the future.
442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  <p>
452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  UNKNOWN - The code ZZ is defined by Unicode LDML for use to indicate that the Region is unknown,
462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  or that the value supplied as a region was invalid.
472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  <p>
482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  DEPRECATED - Region codes that have been defined in the past but are no longer in modern usage,
492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  usually due to a country splitting into multiple territories or changing its name.
502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  <p>
512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  GROUPING - A widely understood grouping of territories that has a well defined membership such
522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  that a region code has been assigned for it.  Some of these are UNM.49 codes that do't fall into
532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  the world/continent/sub-continent hierarchy, while others are just well known groupings that have
542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  their own region code. Region "EU" (European Union) is one such region code that is a grouping.
552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  Groupings will never be returned by the getContainingRegion() API, since a different type of region
562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *  ( WORLD, CONTINENT, or SUBCONTINENT ) will always be the containing region instead.
572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @author       John Emmons
59836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller * @hide Only a subset of ICU is exposed in Android
602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */
612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpublic class Region implements Comparable<Region> {
632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * RegionType is an enumeration defining the different types of regions.  Current possible
662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * values are WORLD, CONTINENT, SUBCONTINENT, TERRITORY, GROUPING, DEPRECATED, and UNKNOWN.
672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public enum RegionType {
702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Type representing the unknown region.
722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        UNKNOWN,
742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Type representing a territory.
772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        TERRITORY,
792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Type representing the whole world.
822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        WORLD,
842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Type representing a continent.
862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        CONTINENT,
882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Type representing a sub-continent.
902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        SUBCONTINENT,
922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Type representing a grouping of territories that is not to be used in
942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * the normal WORLD/CONTINENT/SUBCONTINENT/TERRITORY containment tree.
952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        GROUPING,
972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /**
982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Type representing a region whose code has been deprecated, usually
992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * due to a country splitting into multiple territories or changing its name.
1002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
1012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        DEPRECATED,
1022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
1032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private String id;
1052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int code;
1062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private RegionType type;
1072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private Region containingRegion = null;
1082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private Set<Region> containedRegions = new TreeSet<Region>();
1092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private List<Region> preferredValues = null;
1102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static boolean regionDataIsLoaded = false;
1122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static Map<String,Region> regionIDMap = null;       // Map from ID the regions
1142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static Map<Integer,Region> numericCodeMap = null;   // Map from numeric code to the regions
1152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static Map<String,Region> regionAliases = null;     // Aliases
1162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static ArrayList<Region> regions = null;            // This is the main data structure where the Regions are stored.
1182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static ArrayList<Set<Region>> availableRegions = null;
1192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final String UNKNOWN_REGION_ID = "ZZ";
1212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final String OUTLYING_OCEANIA_REGION_ID = "QO";
1222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final String WORLD_ID = "001";
1232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
1252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Private default constructor.  Use factory methods only.
1262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
1272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private Region () {}
1282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
1302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Initializes the region data from the ICU resource bundles.  The region data
1312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * contains the basic relationships such as which regions are known, what the numeric
1322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * codes are, any known aliases, and the territory containment data.
1332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
1342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * If the region data has already loaded, then this method simply returns without doing
1352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * anything meaningful.
1362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
1372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
1382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static synchronized void loadRegionData() {
1392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( regionDataIsLoaded ) {
1412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return;
1422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        regionAliases = new HashMap<String,Region>();
1452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        regionIDMap = new HashMap<String,Region>();
1462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        numericCodeMap = new HashMap<Integer,Region>();
1472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        availableRegions = new ArrayList<Set<Region>>(RegionType.values().length);
1492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        UResourceBundle metadataAlias = null;
1522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        UResourceBundle territoryAlias = null;
1532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        UResourceBundle codeMappings = null;
1542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        UResourceBundle idValidity = null;
1552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        UResourceBundle regionList = null;
1562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        UResourceBundle regionRegular = null;
1572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        UResourceBundle regionMacro = null;
1582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        UResourceBundle regionUnknown = null;
1592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        UResourceBundle worldContainment = null;
1602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        UResourceBundle territoryContainment = null;
1612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        UResourceBundle groupingContainment = null;
1622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
163f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        UResourceBundle metadata = UResourceBundle.getBundleInstance(ICUData.ICU_BASE_NAME,"metadata",ICUResourceBundle.ICU_DATA_CLASS_LOADER);
1642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        metadataAlias = metadata.get("alias");
1652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        territoryAlias = metadataAlias.get("territory");
1662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
167f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        UResourceBundle supplementalData = UResourceBundle.getBundleInstance(ICUData.ICU_BASE_NAME,"supplementalData", ICUResourceBundle.ICU_DATA_CLASS_LOADER);
1682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        codeMappings = supplementalData.get("codeMappings");
1692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        idValidity = supplementalData.get("idValidity");
1702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        regionList = idValidity.get("region");
1712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        regionRegular = regionList.get("regular");
1722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        regionMacro = regionList.get("macroregion");
1732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        regionUnknown = regionList.get("unknown");
1742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        territoryContainment = supplementalData.get("territoryContainment");
1762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        worldContainment = territoryContainment.get("001");
1772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        groupingContainment = territoryContainment.get("grouping");
1782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        String[] continentsArr = worldContainment.getStringArray();
1802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        List<String> continents = Arrays.asList(continentsArr);
1812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        String[] groupingArr = groupingContainment.getStringArray();
1822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        List<String> groupings = Arrays.asList(groupingArr);
1832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        List<String> regionCodes = new ArrayList<String>();
1842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        List<String> allRegions = new ArrayList<String>();
1862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        allRegions.addAll(Arrays.asList(regionRegular.getStringArray()));
1872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        allRegions.addAll(Arrays.asList(regionMacro.getStringArray()));
1882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        allRegions.add(regionUnknown.getString());
1892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for ( String r : allRegions ) {
1912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int rangeMarkerLocation = r.indexOf("~");
1922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( rangeMarkerLocation > 0 ) {
1932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                StringBuilder regionName = new StringBuilder(r);
1942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                char endRange = regionName.charAt(rangeMarkerLocation+1);
1952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                regionName.setLength(rangeMarkerLocation);
1962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                char lastChar = regionName.charAt(rangeMarkerLocation-1);
1972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                while ( lastChar <= endRange ) {
1982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    String newRegion = regionName.toString();
1992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    regionCodes.add(newRegion);
2002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    lastChar++;
2012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    regionName.setCharAt(rangeMarkerLocation-1,lastChar);
2022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
2032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
2042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                regionCodes.add(r);
2052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
2062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        regions = new ArrayList<Region>(regionCodes.size());
2092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // First process the region codes and create the master array of regions.
2112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for ( String id : regionCodes) {
2122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            Region r = new Region();
2132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            r.id = id;
2142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            r.type = RegionType.TERRITORY; // Only temporary - figure out the real type later once the aliases are known.
2152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            regionIDMap.put(id, r);
2162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( id.matches("[0-9]{3}")) {
2172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                r.code = Integer.valueOf(id).intValue();
2182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                numericCodeMap.put(r.code, r);
2192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                r.type = RegionType.SUBCONTINENT;
2202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
2212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                r.code = -1;
2222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
2232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            regions.add(r);
2242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Process the territory aliases
2282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for ( int i = 0 ; i < territoryAlias.getSize(); i++ ) {
2292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            UResourceBundle res = territoryAlias.get(i);
2302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            String aliasFrom = res.getKey();
2312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            String aliasTo = res.get("replacement").getString();
2322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( regionIDMap.containsKey(aliasTo) && !regionIDMap.containsKey(aliasFrom) ) { // This is just an alias from some string to a region
2342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                regionAliases.put(aliasFrom, regionIDMap.get(aliasTo));
2352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
2362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                Region r;
2372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if ( regionIDMap.containsKey(aliasFrom) ) {  // This is a deprecated region
2382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    r = regionIDMap.get(aliasFrom);
2392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else { // Deprecated region code not in the master codes list - so need to create a deprecated region for it.
2402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    r = new Region();
2412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    r.id = aliasFrom;
2422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    regionIDMap.put(aliasFrom, r);
2432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if ( aliasFrom.matches("[0-9]{3}")) {
2442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        r.code = Integer.valueOf(aliasFrom).intValue();
2452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        numericCodeMap.put(r.code, r);
2462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    } else {
2472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        r.code = -1;
2482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
2492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    regions.add(r);
2502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
2512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                r.type = RegionType.DEPRECATED;
2522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                List<String> aliasToRegionStrings = Arrays.asList(aliasTo.split(" "));
2532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                r.preferredValues = new ArrayList<Region>();
2542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                for ( String s : aliasToRegionStrings ) {
2552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (regionIDMap.containsKey(s)) {
2562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        r.preferredValues.add(regionIDMap.get(s));
2572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
2582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
2592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
2602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Process the code mappings - This will allow us to assign numeric codes to most of the territories.
2632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for ( int i = 0 ; i < codeMappings.getSize(); i++ ) {
2642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            UResourceBundle mapping = codeMappings.get(i);
2652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( mapping.getType() == UResourceBundle.ARRAY ) {
2662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                String [] codeMappingStrings = mapping.getStringArray();
2672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                String codeMappingID = codeMappingStrings[0];
2682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                Integer codeMappingNumber = Integer.valueOf(codeMappingStrings[1]);
2692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                String codeMapping3Letter = codeMappingStrings[2];
2702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if ( regionIDMap.containsKey(codeMappingID)) {
2722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    Region r = regionIDMap.get(codeMappingID);
2732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    r.code = codeMappingNumber.intValue();
2742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    numericCodeMap.put(r.code, r);
2752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    regionAliases.put(codeMapping3Letter, r);
2762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
2772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
2782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Now fill in the special cases for WORLD, UNKNOWN, CONTINENTS, and GROUPINGS
2812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Region r;
2822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( regionIDMap.containsKey(WORLD_ID)) {
2832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            r = regionIDMap.get(WORLD_ID);
2842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            r.type = RegionType.WORLD;
2852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( regionIDMap.containsKey(UNKNOWN_REGION_ID)) {
2882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            r = regionIDMap.get(UNKNOWN_REGION_ID);
2892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            r.type = RegionType.UNKNOWN;
2902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for ( String continent : continents ) {
2932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (regionIDMap.containsKey(continent)) {
2942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                r = regionIDMap.get(continent);
2952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                r.type = RegionType.CONTINENT;
2962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
2972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for ( String grouping : groupings ) {
3002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (regionIDMap.containsKey(grouping)) {
3012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                r = regionIDMap.get(grouping);
3022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                r.type = RegionType.GROUPING;
3032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
3042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Special case: The region code "QO" (Outlying Oceania) is a subcontinent code added by CLDR
3072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // even though it looks like a territory code.  Need to handle it here.
3082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( regionIDMap.containsKey(OUTLYING_OCEANIA_REGION_ID)) {
3102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            r = regionIDMap.get(OUTLYING_OCEANIA_REGION_ID);
3112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            r.type = RegionType.SUBCONTINENT;
3122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Load territory containment info from the supplemental data.
3152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for ( int i = 0 ; i < territoryContainment.getSize(); i++ ) {
3162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            UResourceBundle mapping = territoryContainment.get(i);
3172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            String parent = mapping.getKey();
3182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (parent.equals("containedGroupings") || parent.equals("deprecated")) {
3192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                continue; // handle new pseudo-parent types added in ICU data per cldrbug 7808; for now just skip.
3202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // #11232 is to do something useful with these.
3212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
3222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            Region parentRegion = regionIDMap.get(parent);
3232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for ( int j = 0 ; j < mapping.getSize(); j++ ) {
3242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                String child = mapping.getString(j);
3252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                Region childRegion = regionIDMap.get(child);
3262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if ( parentRegion != null && childRegion != null ) {
3272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // Add the child region to the set of regions contained by the parent
3292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    parentRegion.containedRegions.add(childRegion);
3302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // Set the parent region to be the containing region of the child.
3322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // Regions of type GROUPING can't be set as the parent, since another region
3332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // such as a SUBCONTINENT, CONTINENT, or WORLD must always be the parent.
3342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if ( parentRegion.getType() != RegionType.GROUPING) {
3352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        childRegion.containingRegion = parentRegion;
3362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
3372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
3382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
3392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Create the availableRegions lists
3422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (int i = 0 ; i < RegionType.values().length ; i++) {
3442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            availableRegions.add(new TreeSet<Region>());
3452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for ( Region ar : regions ) {
3482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            Set<Region> currentSet = availableRegions.get(ar.type.ordinal());
3492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            currentSet.add(ar);
3502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            availableRegions.set(ar.type.ordinal(),currentSet);
3512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        regionDataIsLoaded = true;
3542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
3552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /** Returns a Region using the given region ID.  The region ID can be either a 2-letter ISO code,
3572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * 3-letter ISO code,  UNM.49 numeric code, or other valid Unicode Region Code as defined by the CLDR.
3582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param id The id of the region to be retrieved.
3592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return The corresponding region.
3602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws NullPointerException if the supplied id is null.
3612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalArgumentException if the supplied ID cannot be canonicalized to a Region ID that is known by ICU.
3622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static Region getInstance(String id) {
3652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( id == null ) {
3672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new NullPointerException();
3682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        loadRegionData();
3712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Region r = regionIDMap.get(id);
3732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( r == null ) {
3752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            r = regionAliases.get(id);
3762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( r == null ) {
3792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException("Unknown region id: " + id);
3802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( r.type == RegionType.DEPRECATED && r.preferredValues.size() == 1) {
3832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            r = r.preferredValues.get(0);
3842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return r;
3872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
3882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /** Returns a Region using the given numeric code as defined by UNM.49
3912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param code The numeric code of the region to be retrieved.
3922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return The corresponding region.
3932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalArgumentException if the supplied numeric code is not recognized.
3942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static Region getInstance(int code) {
3972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        loadRegionData();
3992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Region r = numericCodeMap.get(code);
4012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( r == null ) { // Just in case there's an alias that's numeric, try to find it.
4032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            String pad = "";
4042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( code < 10 ) {
4052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                pad = "00";
4062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if ( code < 100 ) {
4072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                pad = "0";
4082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
4092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            String id = pad + Integer.toString(code);
4102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            r = regionAliases.get(id);
4112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
4122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( r == null ) {
4142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException("Unknown region code: " + code);
4152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
4162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( r.type == RegionType.DEPRECATED && r.preferredValues.size() == 1) {
4182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            r = r.preferredValues.get(0);
4192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
4202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return r;
4222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
4232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /** Used to retrieve all available regions of a specific type.
4262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
4272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param type The type of regions to be returned ( TERRITORY, MACROREGION, etc. )
4282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return An unmodifiable set of all known regions that match the given type.
4292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static Set<Region> getAvailable(RegionType type) {
4322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        loadRegionData();
4342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return Collections.unmodifiableSet(availableRegions.get(type.ordinal()));
4352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
4362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /** Used to determine the macroregion that geographically contains this region.
4392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
4402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return The region that geographically contains this region.  Returns NULL if this region is
4412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  code "001" (World) or "ZZ" (Unknown region).  For example, calling this method with region "IT" (Italy)
4422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  returns the region "039" (Southern Europe).
4432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Region getContainingRegion() {
4462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        loadRegionData();
4472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return containingRegion;
4482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
4492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /** Used to determine the macroregion that geographically contains this region and that matches the given type.
4512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
4522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return The region that geographically contains this region and matches the given type.  May return NULL if
4532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  no containing region can be found that matches the given type.  For example, calling this method with region "IT" (Italy)
4542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  and type CONTINENT returns the region "150" (Europe).
4552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Region getContainingRegion(RegionType type) {
4582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        loadRegionData();
4592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( containingRegion == null ) {
4602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return null;
4612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
4622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( containingRegion.type.equals(type)) {
4632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return containingRegion;
4642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
4652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return containingRegion.getContainingRegion(type);
4662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
4672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
4682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /** Used to determine the sub-regions that are contained within this region.
4702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
4712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return An unmodifiable set containing all the regions that are immediate children
4722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * of this region in the region hierarchy.  These returned regions could be either macro
4732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * regions, territories, or a mixture of the two, depending on the containment data as defined
4742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * in CLDR.  This API may return an empty set if this region doesn't have any sub-regions.
4752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * For example, calling this method with region "150" (Europe) returns a set containing
4762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the various sub regions of Europe - "039" (Southern Europe) - "151" (Eastern Europe)
4772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * - "154" (Northern Europe) and "155" (Western Europe).
4782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Set<Region> getContainedRegions() {
4812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        loadRegionData();
4822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return Collections.unmodifiableSet(containedRegions);
4832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
4842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /** Used to determine all the regions that are contained within this region and that match the given type
4862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
4872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return An unmodifiable set containing all the regions that are children of this region
4882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * anywhere in the region hierarchy and match the given type.  This API may return an empty set
4892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * if this region doesn't have any sub-regions that match the given type.
4902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * For example, calling this method with region "150" (Europe) and type "TERRITORY" returns a set
4912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  containing all the territories in Europe ( "FR" (France) - "IT" (Italy) - "DE" (Germany) etc. )
4922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Set<Region> getContainedRegions(RegionType type) {
4952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        loadRegionData();
4972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Set<Region> result = new TreeSet<Region>();
4992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Set<Region> cr = getContainedRegions();
5002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for ( Region r : cr ) {
5022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( r.getType() == type ) {
5032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result.add(r);
5042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
5052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result.addAll(r.getContainedRegions(type));
5062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
5072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return Collections.unmodifiableSet(result);
5092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
5102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
5122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return For deprecated regions, return an unmodifiable list of the regions that are the preferred replacement regions for this region.
5132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Returns null for a non-deprecated region.  For example, calling this method with region "SU" (Soviet Union) would
5142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * return a list of the regions containing "RU" (Russia), "AM" (Armenia), "AZ" (Azerbaijan), etc...
5152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
5162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public List<Region> getPreferredValues() {
5172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        loadRegionData();
5192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( type == RegionType.DEPRECATED) {
5212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return Collections.unmodifiableList(preferredValues);
5222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
5232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return null;
5242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
5262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
5282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return Returns true if this region contains the supplied other region anywhere in the region hierarchy.
5292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
5302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public boolean contains(Region other) {
5312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        loadRegionData();
5332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (containedRegions.contains(other)) {
5352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return true;
5362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
5372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for (Region cr : containedRegions) {
5382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (cr.contains(other)) {
5392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return true;
5402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
5412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
5422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return false;
5452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
5462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /** Returns the string representation of this region
5482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
5492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return The string representation of this region, which is its ID.
5502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
5512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public String toString() {
5532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return id;
5542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
5552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
5572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Returns the numeric code for this region
5582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
5592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return The numeric code for this region. Returns a negative value if the given region does not have a numeric
5602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         code assigned to it. This is a very rare case and only occurs for a few very small territories.
5612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
5622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int getNumericCode() {
5642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return code;
5652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
5662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /** Returns this region's type.
5682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
5692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return This region's type classification, such as MACROREGION or TERRITORY.
5702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
5712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public RegionType getType() {
5732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return type;
5742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
5752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
5772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * {@inheritDoc}
5782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
5792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int compareTo(Region other) {
5802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return id.compareTo(other.id);
5812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
5822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller}
583