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