17935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/* 27935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ******************************************************************************* 37935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Copyright (C) 2009-2014, International Business Machines Corporation and * 47935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * others. All Rights Reserved. * 57935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ******************************************************************************* 67935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 77935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpackage com.ibm.icu.impl; 87935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 97935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.ArrayList; 107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Collections; 117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.HashSet; 127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.List; 137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Set; 147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.CurrencyMetaInfo; 167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.Currency.CurrencyUsage; 177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/** 197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * ICU's currency meta info data. 207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpublic class ICUCurrencyMetaInfo extends CurrencyMetaInfo { 227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private ICUResourceBundle regionInfo; 237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private ICUResourceBundle digitInfo; 247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public ICUCurrencyMetaInfo() { 267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ICUResourceBundle bundle = (ICUResourceBundle) ICUResourceBundle.getBundleInstance( 277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ICUResourceBundle.ICU_CURR_BASE_NAME, "supplementalData", 287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ICUResourceBundle.ICU_DATA_CLASS_LOADER); 297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert regionInfo = bundle.findTopLevel("CurrencyMap"); 307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert digitInfo = bundle.findTopLevel("CurrencyMeta"); 317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public List<CurrencyInfo> currencyInfo(CurrencyFilter filter) { 357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return collect(new InfoCollector(), filter); 367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public List<String> currencies(CurrencyFilter filter) { 407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return collect(new CurrencyCollector(), filter); 417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public List<String> regions(CurrencyFilter filter) { 457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return collect(new RegionCollector(), filter); 467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public CurrencyDigits currencyDigits(String isoCode) { 507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return currencyDigits(isoCode, CurrencyUsage.STANDARD); 517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public CurrencyDigits currencyDigits(String isoCode, CurrencyUsage currencyPurpose) { 557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ICUResourceBundle b = digitInfo.findWithFallback(isoCode); 567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (b == null) { 577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert b = digitInfo.findWithFallback("DEFAULT"); 587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int[] data = b.getIntVector(); 607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (currencyPurpose == CurrencyUsage.CASH) { 617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new CurrencyDigits(data[2], data[3]); 627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (currencyPurpose == CurrencyUsage.STANDARD) { 637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new CurrencyDigits(data[0], data[1]); 647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new CurrencyDigits(data[0], data[1]); 667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private <T> List<T> collect(Collector<T> collector, CurrencyFilter filter) { 707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // We rely on the fact that the data lists the regions in order, and the 717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // priorities in order within region. This means we don't need 727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // to sort the results to ensure the ordering matches the spec. 737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (filter == null) { 757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert filter = CurrencyFilter.all(); 767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int needed = collector.collects(); 787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (filter.region != null) { 797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert needed |= Region; 807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (filter.currency != null) { 827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert needed |= Currency; 837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (filter.from != Long.MIN_VALUE || filter.to != Long.MAX_VALUE) { 857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert needed |= Date; 867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (filter.tenderOnly) { 887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert needed |= Tender; 897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (needed != 0) { 927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (filter.region != null) { 937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ICUResourceBundle b = regionInfo.findWithFallback(filter.region); 947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (b != null) { 957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert collectRegion(collector, filter, needed, b); 967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < regionInfo.getSize(); i++) { 997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert collectRegion(collector, filter, needed, regionInfo.at(i)); 1007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return collector.getList(); 1057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private <T> void collectRegion(Collector<T> collector, CurrencyFilter filter, 1087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int needed, ICUResourceBundle b) { 1097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String region = b.getKey(); 1117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (needed == Region) { 1127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert collector.collect(b.getKey(), null, 0, 0, -1, false); 1137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return; 1147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < b.getSize(); i++) { 1177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ICUResourceBundle r = b.at(i); 1187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (r.getSize() == 0) { 1197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // AQ[0] is an empty array instead of a table, so the bundle is null. 1207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // There's no data here, so we skip this entirely. 1217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // We'd do a type test, but the ResourceArray type is private. 1227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 1237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String currency = null; 1257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long from = Long.MIN_VALUE; 1267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long to = Long.MAX_VALUE; 1277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean tender = true; 1287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ((needed & Currency) != 0) { 1307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ICUResourceBundle currBundle = r.at("id"); 1317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert currency = currBundle.getString(); 1327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (filter.currency != null && !filter.currency.equals(currency)) { 1337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 1347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ((needed & Date) != 0) { 1387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert from = getDate(r.at("from"), Long.MIN_VALUE, false); 1397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert to = getDate(r.at("to"), Long.MAX_VALUE, true); 1407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // In the data, to is always > from. This means that when we have a range 1417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // from == to, the comparisons below will always do the right thing, despite 1427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // the range being technically empty. It really should be [from, from+1) but 1437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // this way we don't need to fiddle with it. 1447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (filter.from > to) { 1457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 1467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (filter.to < from) { 1487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 1497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ((needed & Tender) != 0) { 1527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ICUResourceBundle tenderBundle = r.at("tender"); 1537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tender = tenderBundle == null || "true".equals(tenderBundle.getString()); 1547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (filter.tenderOnly && !tender) { 1557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 1567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // data lists elements in priority order, so 'i' suffices 1607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert collector.collect(region, currency, from, to, i, tender); 1617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final long MASK = 4294967295L; 1657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private long getDate(ICUResourceBundle b, long defaultValue, boolean endOfDay) { 1667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (b == null) { 1677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return defaultValue; 1687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int[] values = b.getIntVector(); 1707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return ((long) values[0] << 32) | (((long) values[1]) & MASK); 1717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Utility, just because I don't like the n^2 behavior of using list.contains to build a 1747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // list of unique items. If we used java 6 we could use their class for this. 1757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static class UniqueList<T> { 1767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private Set<T> seen = new HashSet<T>(); 1777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private List<T> list = new ArrayList<T>(); 1787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static <T> UniqueList<T> create() { 1807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new UniqueList<T>(); 1817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert void add(T value) { 1847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!seen.contains(value)) { 1857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert list.add(value); 1867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert seen.add(value); 1877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert List<T> list() { 1917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return Collections.unmodifiableList(list); 1927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static class InfoCollector implements Collector<CurrencyInfo> { 1967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Data is already unique by region/priority, so we don't need to be concerned 1977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // about duplicates. 1987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private List<CurrencyInfo> result = new ArrayList<CurrencyInfo>(); 1997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void collect(String region, String currency, long from, long to, int priority, boolean tender) { 2017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.add(new CurrencyInfo(region, currency, from, to, priority, tender)); 2027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public List<CurrencyInfo> getList() { 2057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return Collections.unmodifiableList(result); 2067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int collects() { 2097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return Everything; 2107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static class RegionCollector implements Collector<String> { 2147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final UniqueList<String> result = UniqueList.create(); 2157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void collect( 2177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String region, String currency, long from, long to, int priority, boolean tender) { 2187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.add(region); 2197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int collects() { 2227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return Region; 2237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public List<String> getList() { 2267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result.list(); 2277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static class CurrencyCollector implements Collector<String> { 2317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final UniqueList<String> result = UniqueList.create(); 2327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void collect( 2347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String region, String currency, long from, long to, int priority, boolean tender) { 2357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.add(currency); 2367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int collects() { 2397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return Currency; 2407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public List<String> getList() { 2437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result.list(); 2447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final int Region = 1; 2487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final int Currency = 2; 2497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final int Date = 4; 2507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final int Tender = 8; 2517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final int Everything = Integer.MAX_VALUE; 2527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static interface Collector<T> { 2547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * A bitmask of Region/Currency/Date indicating which features we collect. 2567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the bitmask 2577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int collects(); 2597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Called with data passed by filter. Values not collected by filter should be ignored. 2627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param region the region code (null if ignored) 2637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param currency the currency code (null if ignored) 2647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param from start time (0 if ignored) 2657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param to end time (0 if ignored) 2667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param priority priority (-1 if ignored) 2677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param tender true if currency is legal tender. 2687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert void collect(String region, String currency, long from, long to, int priority, boolean tender); 2707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Return the list of unique items in the order in which we encountered them for the 2737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * first time. The returned list is unmodifiable. 2747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the list 2757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert List<T> getList(); 2777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert} 279