xref: /aosp_15_r20/external/cldr/tools/cldr-code/src/main/java/org/unicode/cldr/tool/ChartUnitPreferences.java (revision 912701f9769bb47905792267661f0baf2b85bed5)
1 package org.unicode.cldr.tool;
2 
3 import com.google.common.base.Joiner;
4 import com.google.common.base.Splitter;
5 import com.google.common.collect.BiMap;
6 import com.google.common.collect.HashBiMap;
7 import com.google.common.collect.HashMultiset;
8 import com.google.common.collect.Multimap;
9 import com.google.common.collect.Multiset;
10 import java.io.IOException;
11 import java.util.Collection;
12 import java.util.Map;
13 import java.util.Map.Entry;
14 import java.util.Set;
15 import java.util.TreeSet;
16 import org.unicode.cldr.util.CldrUtility;
17 import org.unicode.cldr.util.Pair;
18 import org.unicode.cldr.util.Rational.FormatStyle;
19 import org.unicode.cldr.util.UnitConverter;
20 import org.unicode.cldr.util.UnitPreferences;
21 import org.unicode.cldr.util.UnitPreferences.UnitPreference;
22 
23 public class ChartUnitPreferences extends Chart {
24 
main(String[] args)25     public static void main(String[] args) {
26         new ChartUnitPreferences().writeChart(null);
27     }
28 
29     @Override
getDirectory()30     public String getDirectory() {
31         return FormattedFileWriter.CHART_TARGET_DIR;
32     }
33 
34     @Override
getTitle()35     public String getTitle() {
36         return "Unit Preferences";
37     }
38 
39     @Override
getExplanation()40     public String getExplanation() {
41         return "<p>Unit Preferences provide a way to get the units that are appropriate for a region, and usage, and threshold amounts. "
42                 + "The <a href='unit_conversions.html' target='unit_conversions'>Unit Conversions</a> are used to handle conversion of units needed to use the preferences."
43                 + "This release adds additional structure for usage and threshold amount, allowing for more additions of regions, usages, thresholds, and units in future releases.</p>"
44                 + "<ul>"
45                 + "<li>The Base Unit shows the unit whose amount is to be compared to the ‘If ≥’ amount of the Result Unit."
46                 + "<li>The unit identifiers are internal, and would be localized for display to users. See <a href='https://www.unicode.org/cldr/charts/latest/by_type/units.area.html#hectare' target='units.area.hectare'>Hectare</a>, for example."
47                 + "<li>The Usage shows the type of usage; <i>default</i> is used as a fallback no more specific match is found."
48                 + "<li>The Sample region  represents a set of regions if it has a superscript. See the table at the bottom. 001 (World) is the default if no more specific region is found.</li>"
49                 + "<li>The ‘If ≥’ column shows the thresholds: the first line for a given region where the input amount is greater or equal applies. "
50                 + "For example, for 0.5km as input for [area, default, 001] would result in <i>hectare</i>.</li>"
51                 + "<li>"
52                 + ChartUnitConversions.RATIONAL_MSG
53                 + "</li>\n"
54                 + "<li>"
55                 + ChartUnitConversions.QUANTITY_MSG
56                 + "</li>"
57                 + "<li>"
58                 + ChartUnitConversions.SPEC_GENERAL_MSG
59                 + ", and how to fall back if a given usage or region is not found.</li>\n"
60                 + "</ul>"
61                 + dataScrapeMessage(
62                         "/tr35-general.html#Contents",
63                         "common/testData/units/unitPreferencesTest.txt",
64                         "common/supplemental/units.xml");
65     }
66 
67     @Override
writeContents(FormattedFileWriter pw)68     public void writeContents(FormattedFileWriter pw) throws IOException {
69         // #   Quantity;   Usage;  Region; Input (r);  Input (d);  Input Unit; Output (r); Output
70         // (d); Output Unit
71 
72         TablePrinter tablePrinter =
73                 new TablePrinter()
74                         .addColumn(
75                                 "Base Unit",
76                                 "class='source'",
77                                 CldrUtility.getDoubleLinkMsg(),
78                                 "class='source'",
79                                 true)
80                         .setBreakSpans(true)
81                         .setRepeatHeader(true)
82                         .addColumn(
83                                 "Usage",
84                                 "class='source'",
85                                 CldrUtility.getDoubleLinkMsg(),
86                                 "class='source'",
87                                 true)
88                         .addColumn("Sample Region", "class='source'", null, "class='source'", true)
89                         .addColumn("If ≥", "class='source'", null, "class='source'", true)
90                         .setCellAttributes("class='target' style='text-align:right'")
91                         .addColumn("Result Unit", "class='target'", null, "class='target'", true)
92                         .addColumn("Skeleton", "class='target'", null, "class='target'", true)
93                         .addColumn("Quantity", "class='target'", null, "class='target'", true);
94 
95         UnitConverter converter = SDI.getUnitConverter();
96         UnitPreferences prefs = SDI.getUnitPreferences();
97         Samples samples = new Samples();
98 
99         for (Entry<String, Map<String, Multimap<Set<String>, UnitPreference>>> entry :
100                 prefs.getData().entrySet()) {
101             String quantity = entry.getKey();
102             String baseUnit = converter.getBaseUnitFromQuantity(quantity);
103             for (Entry<String, Multimap<Set<String>, UnitPreference>> entry2 :
104                     entry.getValue().entrySet()) {
105                 String usage = entry2.getKey();
106                 for (Entry<Set<String>, Collection<UnitPreference>> entry3 :
107                         entry2.getValue().asMap().entrySet()) {
108 
109                     Set<String> regions = entry3.getKey();
110                     Pair<String, Integer> sampleRegion = samples.getSample(regions);
111                     final String sampleRegionStr = sampleDisplay(sampleRegion);
112 
113                     for (UnitPreference pref : entry3.getValue()) {
114                         tablePrinter
115                                 .addRow()
116                                 .addCell(baseUnit)
117                                 .addCell(usage)
118                                 .addCell(sampleRegionStr)
119                                 .addCell(pref.geq.toString(FormatStyle.html))
120                                 .addCell(
121                                         Joiner.on(" & ")
122                                                 .join(Splitter.on("-and-").split(pref.unit)))
123                                 .addCell(pref.skeleton)
124                                 .addCell(quantity)
125                                 .finishRow();
126                     }
127                 }
128             }
129         }
130         pw.write(tablePrinter.toTable());
131         pw.write("<br><h1>Region Sets</h1>\n");
132         TablePrinter tablePrinter2 =
133                 new TablePrinter()
134                         .addColumn(
135                                 "Sample Region",
136                                 "class='source'",
137                                 CldrUtility.getDoubleLinkMsg(),
138                                 "class='source'",
139                                 true)
140                         .addColumn(
141                                 "Region Set",
142                                 "class='target'",
143                                 CldrUtility.getDoubleLinkMsg(),
144                                 "class='source'",
145                                 true);
146 
147         TreeSet<Pair<String, Integer>> sorted = new TreeSet<>(samples.setToSample.values());
148         for (Pair<String, Integer> pair : sorted) {
149             tablePrinter2
150                     .addRow()
151                     .addCell(sampleDisplay(pair))
152                     .addCell(Joiner.on(", ").join(samples.setToSample.inverse().get(pair)))
153                     .finishRow();
154         }
155         pw.write(tablePrinter2.toTable());
156     }
157 
sampleDisplay(Pair<String, Integer> sampleRegion)158     private String sampleDisplay(Pair<String, Integer> sampleRegion) {
159         return sampleRegion.getFirst()
160                 + (sampleRegion.getSecond() < 0
161                         ? ""
162                         : "<sup>" + sampleRegion.getSecond() + "</sup>");
163     }
164 
165     private static final class Samples {
166         BiMap<Set<String>, Pair<String, Integer>> setToSample = HashBiMap.create();
167         Multiset<String> counters = HashMultiset.create();
168 
getSample(Set<String> regions)169         private Pair<String, Integer> getSample(Set<String> regions) {
170             if (regions.size() == 1) {
171                 return new Pair<>(regions.iterator().next(), -1);
172             }
173             Pair<String, Integer> sample = setToSample.get(regions);
174             if (sample == null) {
175                 String sampleBase = regions.iterator().next() + ", …";
176                 counters.add(sampleBase);
177                 setToSample.put(
178                         regions, sample = new Pair<>(sampleBase, counters.count(sampleBase)));
179             }
180             return sample;
181         }
182     }
183 }
184