1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.github.tonywasher.joceanus.oceanus.format;
18
19 import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
20 import io.github.tonywasher.joceanus.oceanus.base.OceanusLocale;
21 import io.github.tonywasher.joceanus.oceanus.convert.OceanusDataConverter;
22 import io.github.tonywasher.joceanus.oceanus.date.OceanusDate;
23 import io.github.tonywasher.joceanus.oceanus.date.OceanusDateFormatter;
24 import io.github.tonywasher.joceanus.oceanus.date.OceanusDateRange;
25 import io.github.tonywasher.joceanus.oceanus.decimal.OceanusDecimal;
26 import io.github.tonywasher.joceanus.oceanus.decimal.OceanusDecimalFormatter;
27 import io.github.tonywasher.joceanus.oceanus.decimal.OceanusDecimalParser;
28 import io.github.tonywasher.joceanus.oceanus.decimal.OceanusMoney;
29 import io.github.tonywasher.joceanus.oceanus.decimal.OceanusPrice;
30 import io.github.tonywasher.joceanus.oceanus.decimal.OceanusRate;
31 import io.github.tonywasher.joceanus.oceanus.decimal.OceanusRatio;
32 import io.github.tonywasher.joceanus.oceanus.decimal.OceanusUnits;
33 import io.github.tonywasher.joceanus.oceanus.profile.OceanusProfile;
34
35 import java.math.BigDecimal;
36 import java.math.BigInteger;
37 import java.time.LocalDate;
38 import java.util.ArrayList;
39 import java.util.List;
40 import java.util.Locale;
41 import java.util.Map;
42
43
44
45
46 public class OceanusDataFormatter {
47
48
49
50 public interface OceanusDataFormatterExtension {
51
52
53
54
55
56
57 String formatObject(Object pValue);
58 }
59
60
61
62
63 private static final String ERROR_CLASS = "Invalid Class: ";
64
65
66
67
68 private final OceanusDateFormatter theDateFormatter;
69
70
71
72
73 private final OceanusDecimalFormatter theDecimalFormatter;
74
75
76
77
78 private final OceanusDecimalParser theDecimalParser;
79
80
81
82
83 private final List<OceanusDataFormatterExtension> theExtensions;
84
85
86
87
88 public OceanusDataFormatter() {
89 this(OceanusLocale.getDefaultLocale());
90 }
91
92
93
94
95
96
97 public OceanusDataFormatter(final Locale pLocale) {
98 theDateFormatter = new OceanusDateFormatter(pLocale);
99 theDecimalFormatter = new OceanusDecimalFormatter(pLocale);
100 theDecimalParser = new OceanusDecimalParser(pLocale);
101 theExtensions = new ArrayList<>();
102 }
103
104
105
106
107
108
109 public OceanusDateFormatter getDateFormatter() {
110 return theDateFormatter;
111 }
112
113
114
115
116
117
118 public OceanusDecimalFormatter getDecimalFormatter() {
119 return theDecimalFormatter;
120 }
121
122
123
124
125
126
127 public OceanusDecimalParser getDecimalParser() {
128 return theDecimalParser;
129 }
130
131
132
133
134
135
136 public void extendFormatter(final OceanusDataFormatterExtension pExtension) {
137 theExtensions.add(pExtension);
138 }
139
140
141
142
143
144
145 public void setAccountingWidth(final int pWidth) {
146
147 theDecimalFormatter.setAccountingWidth(pWidth);
148 }
149
150
151
152
153 public void clearAccounting() {
154
155 theDecimalFormatter.clearAccounting();
156 }
157
158
159
160
161
162
163 public final void setFormat(final String pFormat) {
164
165 theDateFormatter.setFormat(pFormat);
166 }
167
168
169
170
171
172
173 public final void setLocale(final Locale pLocale) {
174
175 theDateFormatter.setLocale(pLocale);
176 theDecimalFormatter.setLocale(pLocale);
177 theDecimalParser.setLocale(pLocale);
178 }
179
180
181
182
183
184
185 public Locale getLocale() {
186
187 return theDateFormatter.getLocale();
188 }
189
190
191
192
193
194
195
196 public String formatObject(final Object pValue) {
197
198 if (pValue == null) {
199 return null;
200 }
201
202
203 for (OceanusDataFormatterExtension myExtension : theExtensions) {
204 final String myResult = myExtension.formatObject(pValue);
205 if (myResult != null) {
206 return myResult;
207 }
208 }
209
210
211 final Class<?> myClass = pValue.getClass();
212
213
214 if (pValue instanceof String s) {
215 return s;
216 }
217 if (pValue instanceof Boolean) {
218 return Boolean.TRUE.equals(pValue)
219 ? "true"
220 : "false";
221 }
222 if (pValue instanceof Short
223 || pValue instanceof Integer
224 || pValue instanceof Long) {
225 return pValue.toString();
226 }
227 if (pValue instanceof Float
228 || pValue instanceof Double) {
229 return pValue.toString();
230 }
231 if (pValue instanceof BigInteger
232 || pValue instanceof BigDecimal) {
233 return pValue.toString();
234 }
235
236
237 if (pValue instanceof Enum) {
238 return pValue.toString();
239 }
240
241
242 if (pValue instanceof Class<?> myClazz) {
243 return myClazz.getCanonicalName();
244 }
245
246
247 if (pValue instanceof byte[] ba) {
248 return OceanusDataConverter.bytesToHexString(ba);
249 }
250 if (pValue instanceof char[] ca) {
251 return new String(ca);
252 }
253
254
255 if (pValue instanceof LocalDate myDate) {
256 return theDateFormatter.formatLocalDate(myDate);
257 }
258 if (pValue instanceof OceanusDate myDate) {
259 return theDateFormatter.formatDate(myDate);
260 }
261 if (pValue instanceof OceanusDateRange myRange) {
262 return theDateFormatter.formatDateRange(myRange);
263 }
264
265
266 if (pValue instanceof OceanusDecimal myDecimal) {
267 return theDecimalFormatter.formatDecimal(myDecimal);
268 }
269
270
271 if (pValue instanceof OceanusProfile myProfile) {
272
273 return myProfile.getName()
274 + ": "
275 + (myProfile.isRunning()
276 ? myProfile.getStatus()
277 : myProfile.getElapsed());
278 }
279
280
281 if (pValue instanceof OceanusException) {
282 return myClass.getSimpleName();
283 }
284
285
286 return formatBasicValue(pValue);
287 }
288
289
290
291
292
293
294
295
296
297
298
299 public <T> T parseValue(final String pSource,
300 final Class<T> pClazz) {
301 if (Boolean.class.equals(pClazz)) {
302 return pClazz.cast(Boolean.parseBoolean(pSource));
303 }
304 if (Short.class.equals(pClazz)) {
305 return pClazz.cast(Short.parseShort(pSource));
306 }
307 if (Integer.class.equals(pClazz)) {
308 return pClazz.cast(Integer.parseInt(pSource));
309 }
310 if (Long.class.equals(pClazz)) {
311 return pClazz.cast(Long.parseLong(pSource));
312 }
313 if (Float.class.equals(pClazz)) {
314 return pClazz.cast(Float.parseFloat(pSource));
315 }
316 if (Double.class.equals(pClazz)) {
317 return pClazz.cast(Double.parseDouble(pSource));
318 }
319 if (BigInteger.class.equals(pClazz)) {
320 return pClazz.cast(new BigInteger(pSource));
321 }
322 if (BigDecimal.class.equals(pClazz)) {
323 return pClazz.cast(new BigDecimal(pSource));
324 }
325 if (OceanusDate.class.equals(pClazz)) {
326
327 return pClazz.cast(theDateFormatter.parseDate(pSource));
328 }
329 if (LocalDate.class.equals(pClazz)) {
330
331 return pClazz.cast(theDateFormatter.parseLocalDate(pSource));
332 }
333 if (OceanusPrice.class.equals(pClazz)) {
334
335 return pClazz.cast(theDecimalParser.parsePriceValue(pSource));
336 }
337 if (OceanusMoney.class.equals(pClazz)) {
338
339 return pClazz.cast(theDecimalParser.parseMoneyValue(pSource));
340 }
341 if (OceanusRate.class.equals(pClazz)) {
342
343 return pClazz.cast(theDecimalParser.parseRateValue(pSource));
344 }
345 if (OceanusUnits.class.equals(pClazz)) {
346
347 return pClazz.cast(theDecimalParser.parseUnitsValue(pSource));
348 }
349 if (OceanusRatio.class.equals(pClazz)) {
350
351 return pClazz.cast(theDecimalParser.parseRatioValue(pSource));
352 }
353 throw new IllegalArgumentException(ERROR_CLASS + pClazz.getSimpleName());
354 }
355
356
357
358
359
360
361
362
363
364
365 public <T> T parseValue(final Double pSource,
366 final Class<T> pClazz) {
367 if (OceanusPrice.class.equals(pClazz)) {
368
369 return pClazz.cast(theDecimalParser.createPriceFromDouble(pSource));
370 }
371 if (OceanusMoney.class.equals(pClazz)) {
372
373 return pClazz.cast(theDecimalParser.createMoneyFromDouble(pSource));
374 }
375 if (OceanusRate.class.equals(pClazz)) {
376
377 return pClazz.cast(theDecimalParser.createRateFromDouble(pSource));
378 }
379 if (OceanusUnits.class.equals(pClazz)) {
380
381 return pClazz.cast(theDecimalParser.createUnitsFromDouble(pSource));
382 }
383 if (OceanusRatio.class.equals(pClazz)) {
384
385 return pClazz.cast(theDecimalParser.createRatioFromDouble(pSource));
386 }
387 throw new IllegalArgumentException(ERROR_CLASS + pClazz.getSimpleName());
388 }
389
390
391
392
393
394
395
396
397
398
399
400 public <T> T parseValue(final Double pSource,
401 final String pCurrCode,
402 final Class<T> pClazz) {
403 if (OceanusPrice.class.equals(pClazz)) {
404
405 return pClazz.cast(theDecimalParser.createPriceFromDouble(pSource, pCurrCode));
406 }
407 if (OceanusMoney.class.equals(pClazz)) {
408
409 return pClazz.cast(theDecimalParser.createMoneyFromDouble(pSource, pCurrCode));
410 }
411 throw new IllegalArgumentException(ERROR_CLASS + pClazz.getSimpleName());
412 }
413
414
415
416
417
418
419
420 private static String formatBasicValue(final Object pValue) {
421
422 final Class<?> myClass = pValue.getClass();
423
424
425 final StringBuilder myBuilder = new StringBuilder();
426 myBuilder.append(myClass.getCanonicalName());
427
428
429 if (pValue instanceof List<?> myList) {
430 formatSize(myBuilder, myList.size());
431 } else if (pValue instanceof Map<?, ?> myMap) {
432 formatSize(myBuilder, myMap.size());
433 }
434
435
436 return myBuilder.toString();
437 }
438
439
440
441
442
443
444
445 private static void formatSize(final StringBuilder pBuilder,
446 final Object pSize) {
447
448 pBuilder.append('(');
449 pBuilder.append(pSize);
450 pBuilder.append(')');
451 }
452 }