]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-52_1/main/classes/currdata/src/com/ibm/icu/impl/ICUCurrencyMetaInfo.java
Clean up imports.
[Dictionary.git] / jars / icu4j-52_1 / main / classes / currdata / src / com / ibm / icu / impl / ICUCurrencyMetaInfo.java
1 /*
2  *******************************************************************************
3  * Copyright (C) 2009-2013, International Business Machines Corporation and    *
4  * others. All Rights Reserved.                                                *
5  *******************************************************************************
6  */
7 package com.ibm.icu.impl;
8
9 import java.util.ArrayList;
10 import java.util.Collections;
11 import java.util.HashSet;
12 import java.util.List;
13 import java.util.Set;
14
15 import com.ibm.icu.text.CurrencyMetaInfo;
16
17 /**
18  * ICU's currency meta info data.
19  */
20 public class ICUCurrencyMetaInfo extends CurrencyMetaInfo {
21     private ICUResourceBundle regionInfo;
22     private ICUResourceBundle digitInfo;
23
24     public ICUCurrencyMetaInfo() {
25         ICUResourceBundle bundle = (ICUResourceBundle) ICUResourceBundle.getBundleInstance(
26             ICUResourceBundle.ICU_CURR_BASE_NAME, "supplementalData",
27             ICUResourceBundle.ICU_DATA_CLASS_LOADER);
28         regionInfo = bundle.findTopLevel("CurrencyMap");
29         digitInfo = bundle.findTopLevel("CurrencyMeta");
30     }
31
32     @Override
33     public List<CurrencyInfo> currencyInfo(CurrencyFilter filter) {
34         return collect(new InfoCollector(), filter);
35     }
36
37     @Override
38     public List<String> currencies(CurrencyFilter filter) {
39         return collect(new CurrencyCollector(), filter);
40    }
41
42     @Override
43     public List<String> regions(CurrencyFilter filter) {
44         return collect(new RegionCollector(), filter);
45     }
46
47     @Override
48     public CurrencyDigits currencyDigits(String isoCode) {
49         ICUResourceBundle b = digitInfo.findWithFallback(isoCode);
50         if (b == null) {
51             b = digitInfo.findWithFallback("DEFAULT");
52         }
53         int[] data = b.getIntVector();
54         return new CurrencyDigits(data[0], data[1]);
55     }
56
57     private <T> List<T> collect(Collector<T> collector, CurrencyFilter filter) {
58         // We rely on the fact that the data lists the regions in order, and the
59         // priorities in order within region.  This means we don't need
60         // to sort the results to ensure the ordering matches the spec.
61
62         if (filter == null) {
63             filter = CurrencyFilter.all();
64         }
65         int needed = collector.collects();
66         if (filter.region != null) {
67             needed |= Region;
68         }
69         if (filter.currency != null) {
70             needed |= Currency;
71         }
72         if (filter.from != Long.MIN_VALUE || filter.to != Long.MAX_VALUE) {
73             needed |= Date;
74         }
75         if (filter.tenderOnly) {
76             needed |= Tender;
77         }
78
79         if (needed != 0) {
80             if (filter.region != null) {
81                 ICUResourceBundle b = regionInfo.findWithFallback(filter.region);
82                 if (b != null) {
83                     collectRegion(collector, filter, needed, b);
84                 }
85             } else {
86                 for (int i = 0; i < regionInfo.getSize(); i++) {
87                     collectRegion(collector, filter, needed, regionInfo.at(i));
88                 }
89             }
90         }
91
92         return collector.getList();
93     }
94
95     private <T> void collectRegion(Collector<T> collector, CurrencyFilter filter,
96             int needed, ICUResourceBundle b) {
97
98         String region = b.getKey();
99         if (needed == Region) {
100             collector.collect(b.getKey(), null, 0, 0, -1, false);
101             return;
102         }
103
104         for (int i = 0; i < b.getSize(); i++) {
105             ICUResourceBundle r = b.at(i);
106             if (r.getSize() == 0) {
107                 // AQ[0] is an empty array instead of a table, so the bundle is null.
108                 // There's no data here, so we skip this entirely.
109                 // We'd do a type test, but the ResourceArray type is private.
110                 continue;
111             }
112             String currency = null;
113             long from = Long.MIN_VALUE;
114             long to = Long.MAX_VALUE;
115             boolean tender = true;
116
117             if ((needed & Currency) != 0) {
118                 ICUResourceBundle currBundle = r.at("id");
119                 currency = currBundle.getString();
120                 if (filter.currency != null && !filter.currency.equals(currency)) {
121                     continue;
122                 }
123             }
124
125             if ((needed & Date) != 0) {
126                 from = getDate(r.at("from"), Long.MIN_VALUE, false);
127                 to = getDate(r.at("to"), Long.MAX_VALUE, true);
128                 // In the data, to is always > from.  This means that when we have a range
129                 // from == to, the comparisons below will always do the right thing, despite
130                 // the range being technically empty.  It really should be [from, from+1) but
131                 // this way we don't need to fiddle with it.
132                 if (filter.from > to) {
133                     continue;
134                 }
135                 if (filter.to < from) {
136                     continue;
137                 }
138             }
139             if ((needed & Tender) != 0) {
140                 ICUResourceBundle tenderBundle = r.at("tender");
141                 tender = tenderBundle == null || "true".equals(tenderBundle.getString());
142                 if (filter.tenderOnly && !tender) {
143                     continue;
144                 }
145             }
146
147             // data lists elements in priority order, so 'i' suffices
148             collector.collect(region, currency, from, to, i, tender);
149         }
150     }
151
152     private static final long MASK = 4294967295L;
153     private long getDate(ICUResourceBundle b, long defaultValue, boolean endOfDay) {
154         if (b == null) {
155             return defaultValue;
156         }
157         int[] values = b.getIntVector();
158         return ((long) values[0] << 32) | (((long) values[1]) & MASK);
159     }
160
161     // Utility, just because I don't like the n^2 behavior of using list.contains to build a
162     // list of unique items.  If we used java 6 we could use their class for this.
163     private static class UniqueList<T> {
164         private Set<T> seen = new HashSet<T>();
165         private List<T> list = new ArrayList<T>();
166
167         private static <T> UniqueList<T> create() {
168             return new UniqueList<T>();
169         }
170
171         void add(T value) {
172             if (!seen.contains(value)) {
173                 list.add(value);
174                 seen.add(value);
175             }
176         }
177
178         List<T> list() {
179             return Collections.unmodifiableList(list);
180         }
181     }
182
183     private static class InfoCollector implements Collector<CurrencyInfo> {
184         // Data is already unique by region/priority, so we don't need to be concerned
185         // about duplicates.
186         private List<CurrencyInfo> result = new ArrayList<CurrencyInfo>();
187
188         public void collect(String region, String currency, long from, long to, int priority, boolean tender) {
189             result.add(new CurrencyInfo(region, currency, from, to, priority, tender));
190         }
191
192         public List<CurrencyInfo> getList() {
193             return Collections.unmodifiableList(result);
194         }
195
196         public int collects() {
197             return Everything;
198         }
199     }
200
201     private static class RegionCollector implements Collector<String> {
202         private final UniqueList<String> result = UniqueList.create();
203
204         public void collect(
205                 String region, String currency, long from, long to, int priority, boolean tender) {
206             result.add(region);
207         }
208
209         public int collects() {
210             return Region;
211         }
212
213         public List<String> getList() {
214             return result.list();
215         }
216     }
217
218     private static class CurrencyCollector implements Collector<String> {
219         private final UniqueList<String> result = UniqueList.create();
220
221         public void collect(
222                 String region, String currency, long from, long to, int priority, boolean tender) {
223             result.add(currency);
224         }
225
226         public int collects() {
227             return Currency;
228         }
229
230         public List<String> getList() {
231             return result.list();
232         }
233     }
234
235     private static final int Region = 1;
236     private static final int Currency = 2;
237     private static final int Date = 4;
238     private static final int Tender = 8;
239     private static final int Everything = Integer.MAX_VALUE;
240
241     private static interface Collector<T> {
242         /**
243          * A bitmask of Region/Currency/Date indicating which features we collect.
244          * @return the bitmask
245          */
246         int collects();
247
248         /**
249          * Called with data passed by filter.  Values not collected by filter should be ignored.
250          * @param region the region code (null if ignored)
251          * @param currency the currency code (null if ignored)
252          * @param from start time (0 if ignored)
253          * @param to end time (0 if ignored)
254          * @param priority priority (-1 if ignored)
255          * @param tender true if currency is legal tender.
256          */
257         void collect(String region, String currency, long from, long to, int priority, boolean tender);
258
259         /**
260          * Return the list of unique items in the order in which we encountered them for the
261          * first time.  The returned list is unmodifiable.
262          * @return the list
263          */
264         List<T> getList();
265     }
266 }