• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.unicode.cldr.util;
2 
3 import java.util.Collection;
4 import java.util.LinkedHashMap;
5 import java.util.Map;
6 import java.util.Map.Entry;
7 import java.util.Objects;
8 import java.util.Set;
9 import java.util.TreeMap;
10 import java.util.TreeSet;
11 
12 import com.google.common.base.Joiner;
13 import com.google.common.base.Splitter;
14 import com.google.common.collect.ImmutableSet;
15 import com.google.common.collect.LinkedHashMultimap;
16 import com.google.common.collect.Multimap;
17 import com.ibm.icu.impl.locale.XCldrStub.ImmutableMap;
18 import com.ibm.icu.util.Freezable;
19 
20 public class UnitPreferences implements Freezable<UnitPreferences> {
21     Map<String, Map<String, Multimap<Set<String>, UnitPreference>>> quantityToUsageToRegionsToInfo = new TreeMap<>();
22     Set<String> usages = new TreeSet<>();
23 
24     /**
25      * Special class encapsulating
26      * @author markdavis
27      *
28      */
29     public static final class UnitPreference implements Comparable<UnitPreference>{
30         public final Rational geq;
31         public final String unit;
32         public final String skeleton;
33 
UnitPreference(Rational geq, String unit, String skeleton)34         public UnitPreference(Rational geq, String unit, String skeleton) {
35             this.geq = geq;
36             this.unit = unit;
37             this.skeleton = skeleton == null ? "" : skeleton;
38         }
39 
40         @Override
compareTo(UnitPreference o)41         public int compareTo(UnitPreference o) {
42             int diff = geq.compareTo(o.geq);
43             if (diff != 0) {
44                 return diff;
45             }
46             return unit.compareTo(o.unit);
47         }
48         @Override
equals(Object obj)49         public boolean equals(Object obj) {
50             return compareTo((UnitPreference)obj) == 0;
51         }
52         @Override
hashCode()53         public int hashCode() {
54             return Objects.hash(geq, unit);
55         }
toString(String baseUnit)56         public String toString(String baseUnit) {
57             return geq + (baseUnit == null ? "": " " + baseUnit) + ", " + unit + (skeleton.isEmpty() ? "" : ", " + skeleton);
58         }
59         @Override
toString()60         public String toString() {
61             return toString(null);
62         }
63     }
64 
65     static private final Splitter SPLIT_SPACE = Splitter.on(' ').trimResults().omitEmptyStrings();
66     static public Splitter SPLIT_AND = Splitter.on("-and-");
67 
add(String quantity, String usage, String regions, String geq, String skeleton, String unit)68     public void add(String quantity, String usage, String regions, String geq, String skeleton, String unit) {
69         usages.add(usage);
70         Map<String, Multimap<Set<String>, UnitPreference>> usageToRegionsToInfo = quantityToUsageToRegionsToInfo.get(quantity);
71         if (usageToRegionsToInfo == null) {
72             quantityToUsageToRegionsToInfo.put(quantity, usageToRegionsToInfo = new TreeMap<>());
73         }
74         Multimap<Set<String>, UnitPreference> regionsToInfo = usageToRegionsToInfo.get(usage);
75         if (regionsToInfo == null) {
76             usageToRegionsToInfo.put(usage, regionsToInfo = LinkedHashMultimap.create());
77         }
78         Rational newGeq = geq == null || geq.isEmpty() ? Rational.ONE : Rational.of(geq);
79         final UnitPreference newUnitPref = new UnitPreference(newGeq, unit, skeleton);
80 
81         regionsToInfo.put(ImmutableSet.copyOf(new TreeSet<>(SPLIT_SPACE.splitToList(regions))), newUnitPref);
82     }
83 
84     boolean frozen;
85 
86     @Override
isFrozen()87     public boolean isFrozen() {
88         return frozen;
89     }
90 
91     @Override
freeze()92     public UnitPreferences freeze() {
93         if (!frozen) {
94             frozen = true;
95             quantityToUsageToRegionsToInfo = CldrUtility.protectCollection(quantityToUsageToRegionsToInfo);
96             usages = ImmutableSet.copyOf(usages);
97         }
98         return this;
99     }
100 
101     @Override
cloneAsThawed()102     public UnitPreferences cloneAsThawed() {
103         throw new UnsupportedOperationException();
104     }
105 
106     /**
107      * quantity => usage => region => geq => [unit, skeleton]
108      * @return
109      */
getData()110     public Map<String, Map<String, Multimap<Set<String>, UnitPreference>>> getData() {
111         return quantityToUsageToRegionsToInfo;
112     }
113 
114     static final Joiner JOIN_SPACE = Joiner.on(' ');
115 
116     @Override
toString()117     public String toString() {
118         StringBuilder buffer = new StringBuilder();
119         int order = 0;
120         for (Entry<String, Map<String, Multimap<Set<String>, UnitPreference>>> entry1 : quantityToUsageToRegionsToInfo.entrySet()) {
121             String quantity = entry1.getKey();
122             for (Entry<String, Multimap<Set<String>, UnitPreference>> entry2 : entry1.getValue().entrySet()) {
123                 String usage = entry2.getKey();
124                 for (Entry<Set<String>, Collection<UnitPreference>> entry : entry2.getValue().asMap().entrySet()) {
125                     Set<String> regions = entry.getKey();
126                     for (UnitPreference up : entry.getValue()) {
127                         buffer.append("\n" + up.unit + "\t;\t" + getPath(order++, quantity, usage, regions, up.geq, up.skeleton));
128                     }
129                 }
130             }
131         }
132         return buffer.toString();
133     }
134 
getPath(int order, String quantity, String usage, Collection<String> regions, Rational geq, String skeleton)135     public String getPath(int order, String quantity, String usage, Collection<String> regions, Rational geq, String skeleton) {
136         //      <unitPreferences category="length" usage="person" scope="small">
137         // <unitPreference regions="001">centimeter</unitPreference>
138         return "//supplementalData/unitPreferenceData/unitPreferences"
139         + "[@category=\"" + quantity + "\"]"
140         + "[@usage=\"" + usage + "\"]"
141         + "/unitPreference"
142         + "[@_q=\"" + order + "\"]"
143         + "[@regions=\"" + JOIN_SPACE.join(regions) + "\"]"
144         + (geq == Rational.ONE ? "" : "[@geq=\"" + geq + "\"]")
145         + (skeleton.isEmpty() ? "" : "[@skeleton=\"" + skeleton + "\"]")
146         ;
147     }
148 
149     /**
150      * Returns the data converted to single regions, and using base units
151      * @return
152      */
getFastMap(UnitConverter converter)153     public Map<String, Map<String, Map<String, UnitPreference>>> getFastMap(UnitConverter converter) {
154         Map<String, Map<String, Map<String, UnitPreference>>> result = new LinkedHashMap<>();
155         for (Entry<String, Map<String, Multimap<Set<String>, UnitPreference>>> entry1 : quantityToUsageToRegionsToInfo.entrySet()) {
156             String quantity = entry1.getKey();
157             Map<String, Map<String, UnitPreference>> result2 = new LinkedHashMap<>();
158             result.put(quantity, result2);
159 
160             for (Entry<String, Multimap<Set<String>, UnitPreference>> entry2 : entry1.getValue().entrySet()) {
161                 String usage = entry2.getKey();
162                 Map<String, UnitPreference> result3 = new LinkedHashMap<>();
163                 result2.put(usage, result3);
164                 for (Entry<Set<String>, Collection<UnitPreference>> entry : entry2.getValue().asMap().entrySet()) {
165                     Set<String> regions = entry.getKey();
166                     for (UnitPreference up : entry.getValue()) {
167                         String unit = SPLIT_AND.split(up.unit).iterator().next(); // first unit
168                         quantity = converter.getQuantityFromUnit(unit, false);
169                         String baseUnit = converter.getBaseUnitFromQuantity(quantity);
170                         Rational geq = converter.parseRational(String.valueOf(up.geq));
171                         Rational value = converter.convert(geq, unit, baseUnit, false);
172                         if (value.equals(Rational.NaN)) {
173                             converter.convert(geq, unit, baseUnit, true); // debug
174                         }
175                         UnitPreference up2 = new UnitPreference(value, up.unit, up.skeleton);
176                         for (String region : regions) {
177                             result3.put(region, up2);
178                         }
179                     }
180                 }
181             }
182         }
183         return ImmutableMap.copyOf(result);
184     }
185 
getUsages()186     public Set<String> getUsages() {
187         return usages;
188     }
189 }
190