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