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 }