1 package org.unicode.cldr.util; 2 3 import java.util.ArrayList; 4 import java.util.Collection; 5 import java.util.Collections; 6 import java.util.HashMap; 7 import java.util.HashSet; 8 import java.util.LinkedHashMap; 9 import java.util.LinkedHashSet; 10 import java.util.List; 11 import java.util.Map; 12 import java.util.Set; 13 14 import com.google.common.collect.Multimap; 15 import com.ibm.icu.impl.Relation; 16 import com.ibm.icu.util.TimeZone; 17 18 public class Containment { 19 private static final SupplementalDataInfo supplementalData = SupplementalDataInfo.getInstance(); 20 static final Relation<String, String> containmentCore = supplementalData 21 .getContainmentCore(); 22 static final Set<String> continents = containmentCore.get("001"); 23 static final Set<String> subcontinents; 24 static { 25 LinkedHashSet<String> temp = new LinkedHashSet<>(); 26 for (String continent : continents) { containmentCore.get(continent)27 temp.addAll(containmentCore.get(continent)); 28 } 29 subcontinents = Collections.unmodifiableSet(temp); 30 } 31 static final Relation<String, String> containmentFull = supplementalData 32 .getTerritoryToContained(); 33 static final Relation<String, String> containedToContainer = Relation 34 .of(new HashMap<String, Set<String>>(), 35 HashSet.class) 36 .addAllInverted(containmentFull) 37 .freeze(); 38 39 static final Relation<String, String> leavesToContainers; 40 static { 41 leavesToContainers = Relation 42 .of(new HashMap<String, Set<String>>(), 43 HashSet.class); 44 // for each container, get all of its leaf nodes 45 Set<String> containers = supplementalData.getContainers(); 46 for (String s : containers) { 47 HashSet<String> leaves = new HashSet<>(); addLeaves(s, leaves, containers)48 addLeaves(s, leaves, containers); leavesToContainers.putAll(leaves, s)49 leavesToContainers.putAll(leaves, s); 50 } leavesToContainers.freeze()51 leavesToContainers.freeze(); 52 // for (Entry<String, Set<String>> e : leavesToContainers.keyValuesSet()) { 53 // System.out.println(e.getKey() + " " + e.getValue()); 54 // } 55 } 56 57 static final Relation<String, String> containedToContainerCore = Relation 58 .of(new HashMap<String, Set<String>>(), 59 HashSet.class) 60 .addAllInverted(containmentCore) 61 .freeze(); 62 static final Map<String, Integer> toOrder = new LinkedHashMap<>(); 63 static int level = 0; 64 static int order; 65 static { 66 initOrder("001"); 67 // Special cases. Cyprus is because it is in the wrong location because it gets picked up in the EU. 68 resetOrder("003", "021"); 69 resetOrder("419", "005"); 70 resetOrder("CY", "BH"); 71 } 72 73 // static Map<String, String> zone2country = StandardCodes.make().getZoneToCounty(); 74 getRegionFromZone(String tzid)75 public static String getRegionFromZone(String tzid) { 76 if ("Etc/Unknown".equals(tzid)) { 77 return "001"; 78 } 79 try { 80 return TimeZone.getRegion(tzid); 81 } catch (IllegalArgumentException e) { 82 return "ZZ"; 83 } 84 // return zone2country.get(source0); 85 } 86 addLeaves(String s, Set<String> target, Set<String> nonLeaf)87 private static void addLeaves(String s, Set<String> target, Set<String> nonLeaf) { 88 Set<String> contained = supplementalData.getContained(s); 89 if (contained == null) { 90 return; 91 } 92 for (String child : contained) { 93 if (!nonLeaf.contains(child)) { 94 target.add(child); 95 } else { 96 addLeaves(child, target, nonLeaf); 97 } 98 } 99 } 100 getContainer(String territory)101 public static String getContainer(String territory) { 102 Set<String> containers = containedToContainerCore.get(territory); 103 if (containers == null) { 104 containers = containedToContainer.get(territory); 105 } 106 String container = containers != null 107 ? containers.iterator().next() 108 : territory.equals("001") ? "001" : "ZZ"; 109 return container; 110 } 111 112 /** 113 * Return all the containers, including deprecated. 114 * @param territory 115 * @return 116 */ getContainers(String territory)117 public static Set<String> getContainers(String territory) { 118 return containedToContainer.get(territory); 119 } 120 121 /** 122 * Return the Continent containing the territory, or 001 if the territory is 001, otherwise ZZ 123 * 124 * @param territory 125 */ getContinent(String territory)126 public static String getContinent(String territory) { 127 while (true) { 128 if (territory == null 129 || territory.equals("001") 130 || territory.equals("ZZ") 131 || continents.contains(territory)) { 132 return territory; 133 } 134 String newTerritory = getContainer(territory); 135 if (newTerritory == null) { 136 return territory; 137 } 138 territory = newTerritory; 139 } 140 } 141 142 /** 143 * Return the Subcontinent containing the territory, or the continent if it is a continent, or 144 * 001 if it is 001, otherwise ZZ. 145 * 146 * @param territory 147 */ getSubcontinent(String territory)148 public static String getSubcontinent(String territory) { 149 while (true) { 150 if (territory.equals("001") 151 || territory.equals("ZZ") 152 || continents.contains(territory) 153 || subcontinents.contains(territory)) { 154 return territory; 155 } 156 territory = getContainer(territory); 157 } 158 } 159 getOrder(String territory)160 public static int getOrder(String territory) { 161 Integer temp = toOrder.get(territory); 162 return temp != null ? temp.intValue() : level; 163 } 164 initOrder(String territory)165 private static void initOrder(String territory) { 166 if (!toOrder.containsKey(territory)) { 167 toOrder.put(territory, ++level); 168 } 169 Set<String> contained = containmentFull.get(territory); 170 if (contained == null) { 171 return; 172 } 173 for (String subitem : contained) { 174 if (!toOrder.containsKey(subitem)) { 175 toOrder.put(subitem, ++level); 176 } 177 } 178 for (String subitem : contained) { 179 initOrder(subitem); 180 } 181 } 182 resetOrder(String newTerritory, String oldTerritory)183 private static void resetOrder(String newTerritory, String oldTerritory) { 184 // final Integer newOrder = toOrder.get(newTerritory); 185 // if (newOrder != null) { 186 // throw new IllegalArgumentException(newTerritory + " already defined as " + newOrder); 187 // } 188 final Integer oldOrder = toOrder.get(oldTerritory); 189 if (oldOrder == null) { 190 throw new IllegalArgumentException(oldTerritory + " not yet defined"); 191 } 192 toOrder.put(newTerritory, oldOrder); 193 } 194 getContinents()195 public Set<String> getContinents() { 196 return continents; 197 } 198 getSubontinents()199 public Set<String> getSubontinents() { 200 return subcontinents; 201 } 202 getAllDirected(Multimap<String, String> multimap, String lang)203 public static Set<List<String>> getAllDirected(Multimap<String, String> multimap, String lang) { 204 LinkedHashSet<List<String>> result = new LinkedHashSet<>(); 205 getAllDirected(multimap, lang, new ArrayList<String>(), result); 206 return result; 207 } 208 getAllDirected(Multimap<String, String> multimap, String lang, ArrayList<String> target, Set<List<String>> targets)209 private static void getAllDirected(Multimap<String, String> multimap, String lang, ArrayList<String> target, Set<List<String>> targets) { 210 target.add(lang); 211 Collection<String> parents = multimap.get(lang); 212 int size = parents.size(); 213 if (size == 0) { 214 targets.add(target); 215 } else if (size == 1) { 216 for (String parent : parents) { 217 getAllDirected(multimap, parent, target, targets); 218 } 219 } else { 220 for (String parent : parents) { 221 getAllDirected(multimap, parent, (ArrayList<String>) target.clone(), targets); 222 } 223 } 224 } 225 226 /** 227 * For each leaf region (eg "CO"), return all containers [019, 419, 005, 001] 228 * @param leaf 229 * @return 230 */ leafToContainer(String leaf)231 public static Set<String> leafToContainer(String leaf) { 232 return leavesToContainers.get(leaf); 233 } 234 isLeaf(String region)235 public static boolean isLeaf(String region) { 236 return leavesToContainers.containsKey(region); 237 } 238 }