View Javadoc
1   /*
2    * MoneyWise: Finance Application
3    * Copyright 2012-2026. Tony Washer
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6    * use this file except in compliance with the License.  You may obtain a copy
7    * of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
14   * License for the specific language governing permissions and limitations under
15   * the License.
16   */
17  package io.github.tonywasher.joceanus.moneywise.data.statics;
18  
19  import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataFieldId;
20  import io.github.tonywasher.joceanus.metis.data.MetisDataResource;
21  import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
22  import io.github.tonywasher.joceanus.metis.field.MetisFieldVersionValues;
23  import io.github.tonywasher.joceanus.metis.field.MetisFieldVersionedSet;
24  import io.github.tonywasher.joceanus.moneywise.exc.MoneyWiseDataException;
25  import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
26  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusMoney;
27  import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
28  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataItem;
29  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataSet;
30  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataValues;
31  import io.github.tonywasher.joceanus.prometheus.data.PrometheusListStyle;
32  import io.github.tonywasher.joceanus.prometheus.data.PrometheusStaticDataClass;
33  import io.github.tonywasher.joceanus.prometheus.data.PrometheusStaticDataItem;
34  
35  import java.util.Currency;
36  
37  /**
38   * AssetCurrency data type.
39   *
40   * @author Tony Washer
41   */
42  public class MoneyWiseCurrency
43          extends PrometheusStaticDataItem {
44      /**
45       * Object name.
46       */
47      public static final String OBJECT_NAME = MoneyWiseStaticDataType.CURRENCY.getItemName();
48  
49      /**
50       * List name.
51       */
52      public static final String LIST_NAME = MoneyWiseStaticDataType.CURRENCY.getListName();
53  
54      /**
55       * Report fields.
56       */
57      private static final MetisFieldVersionedSet<MoneyWiseCurrency> FIELD_DEFS = MetisFieldVersionedSet.newVersionedFieldSet(MoneyWiseCurrency.class);
58  
59      /*
60       * FieldIds.
61       */
62      static {
63          FIELD_DEFS.declareBooleanField(MoneyWiseStaticResource.CURRENCY_REPORTING);
64      }
65  
66      /**
67       * Copy Constructor.
68       *
69       * @param pList     The list to associate the Account Currency with
70       * @param pCurrency The Account Currency to copy
71       */
72      protected MoneyWiseCurrency(final MoneyWiseCurrencyList pList,
73                                  final MoneyWiseCurrency pCurrency) {
74          super(pList, pCurrency);
75      }
76  
77      /**
78       * Basic constructor.
79       *
80       * @param pList The list to associate the Account Currency with
81       * @param pName Name of Account Currency
82       * @throws OceanusException on error
83       */
84      private MoneyWiseCurrency(final MoneyWiseCurrencyList pList,
85                                final String pName) throws OceanusException {
86          super(pList, pName);
87          setValueReporting(Boolean.FALSE);
88          setValueEnabled(Boolean.TRUE);
89          setValueDesc(getCurrencyClass().getCurrency().getDisplayName());
90      }
91  
92      /**
93       * Basic constructor.
94       *
95       * @param pList  The list to associate the Account Currency with
96       * @param pClass Class of Account Currency
97       * @throws OceanusException on error
98       */
99      private MoneyWiseCurrency(final MoneyWiseCurrencyList pList,
100                               final MoneyWiseCurrencyClass pClass) throws OceanusException {
101         super(pList, pClass);
102         setValueReporting(Boolean.FALSE);
103         setValueEnabled(Boolean.TRUE);
104         setValueDesc(pClass.getCurrency().getDisplayName());
105     }
106 
107     /**
108      * Values constructor.
109      *
110      * @param pList   The list to associate the item with
111      * @param pValues the values
112      * @throws OceanusException on error
113      */
114     private MoneyWiseCurrency(final MoneyWiseCurrencyList pList,
115                               final PrometheusDataValues pValues) throws OceanusException {
116         super(pList, pValues);
117 
118         /* Store the Default */
119         final Object myValue = pValues.getValue(MoneyWiseStaticResource.CURRENCY_REPORTING);
120         switch (myValue) {
121             case Boolean b -> setValueReporting(b);
122             case String s -> {
123                 final OceanusDataFormatter myFormatter = getDataSet().getDataFormatter();
124                 setValueReporting(myFormatter.parseValue(s, Boolean.class));
125             }
126             default -> setValueReporting(Boolean.FALSE);
127         }
128     }
129 
130     @Override
131     public MetisFieldSetDef getDataFieldSet() {
132         return FIELD_DEFS;
133     }
134 
135     @Override
136     public boolean includeXmlField(final MetisDataFieldId pField) {
137         /* Determine whether fields should be included */
138         if (MoneyWiseStaticResource.CURRENCY_REPORTING.equals(pField)) {
139             return true;
140         }
141 
142         /* Pass call on */
143         return super.includeXmlField(pField);
144     }
145 
146     /**
147      * Is this the reporting currency.
148      *
149      * @return true/false
150      */
151     public Boolean isReporting() {
152         return getValues().getValue(MoneyWiseStaticResource.CURRENCY_REPORTING, Boolean.class);
153     }
154 
155     /**
156      * Set reporting indication.
157      *
158      * @param pValue the value
159      */
160     private void setValueReporting(final Boolean pValue) {
161         getValues().setUncheckedValue(MoneyWiseStaticResource.CURRENCY_REPORTING, pValue);
162     }
163 
164     /**
165      * Return the Currency class of the AccountCurrency.
166      *
167      * @return the class
168      */
169     public MoneyWiseCurrencyClass getCurrencyClass() {
170         return (MoneyWiseCurrencyClass) super.getStaticClass();
171     }
172 
173     @Override
174     public MoneyWiseCurrency getBase() {
175         return (MoneyWiseCurrency) super.getBase();
176     }
177 
178     @Override
179     public MoneyWiseCurrencyList getList() {
180         return (MoneyWiseCurrencyList) super.getList();
181     }
182 
183     /**
184      * Return the Currency of the AccountCurrency.
185      *
186      * @return the currency
187      */
188     public Currency getCurrency() {
189         return getCurrencyClass().getCurrency();
190     }
191 
192     @Override
193     public int compareValues(final PrometheusDataItem pThat) {
194         /* Handle differences in default value */
195         final MoneyWiseCurrency myThat = (MoneyWiseCurrency) pThat;
196         if (!isReporting().equals(myThat.isReporting())) {
197             return Boolean.TRUE.equals(isReporting())
198                     ? -1
199                     : 1;
200         }
201 
202         /* Handle normally */
203         return super.compareValues(pThat);
204     }
205 
206     @Override
207     public void resolveDataSetLinks() throws OceanusException {
208         /* Update the Encryption details */
209         super.resolveDataSetLinks();
210 
211         /* Access Relevant lists */
212         final MetisFieldVersionValues myValues = getValues();
213 
214         /* Adjust Default */
215         final Object myReporting = myValues.getValue(MoneyWiseStaticResource.CURRENCY_REPORTING);
216         if (myReporting == null) {
217             setValueReporting(Boolean.FALSE);
218         }
219     }
220 
221     /**
222      * Set reporting indication.
223      *
224      * @param pReporting the new indication
225      */
226     public void setReporting(final Boolean pReporting) {
227         setValueReporting(pReporting);
228     }
229 
230     @Override
231     public boolean applyChanges(final PrometheusDataItem pData) {
232         /* Can only apply changes for AccountCurrency */
233         if (!(pData instanceof MoneyWiseCurrency)) {
234             return false;
235         }
236 
237         /* Access the data */
238         final MoneyWiseCurrency myData = (MoneyWiseCurrency) pData;
239 
240         /* Store the current detail into history */
241         pushHistory();
242 
243         /* Apply basic changes */
244         applyBasicChanges(myData);
245 
246         /* Update the reporting indication if required */
247         if (!isReporting().equals(myData.isReporting())) {
248             setReporting(myData.isReporting());
249         }
250 
251         /* Check for changes */
252         return checkForHistory();
253     }
254 
255     /**
256      * Represents a list of {@link MoneyWiseCurrency} objects.
257      */
258     public static class MoneyWiseCurrencyList
259             extends PrometheusStaticList<MoneyWiseCurrency> {
260         /**
261          * Report fields.
262          */
263         private static final MetisFieldSet<MoneyWiseCurrencyList> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseCurrencyList.class);
264 
265         /**
266          * Construct an empty CORE account currency list.
267          *
268          * @param pData the DataSet for the list
269          */
270         public MoneyWiseCurrencyList(final PrometheusDataSet pData) {
271             super(MoneyWiseCurrency.class, pData, MoneyWiseStaticDataType.CURRENCY, PrometheusListStyle.CORE);
272         }
273 
274         /**
275          * Constructor for a cloned List.
276          *
277          * @param pSource the source List
278          */
279         private MoneyWiseCurrencyList(final MoneyWiseCurrencyList pSource) {
280             super(pSource);
281         }
282 
283         @Override
284         public MetisFieldSet<MoneyWiseCurrencyList> getDataFieldSet() {
285             return FIELD_DEFS;
286         }
287 
288         @Override
289         public String listName() {
290             return LIST_NAME;
291         }
292 
293         @Override
294         public MetisFieldSetDef getItemFields() {
295             return MoneyWiseCurrency.FIELD_DEFS;
296         }
297 
298         @Override
299         protected Class<MoneyWiseCurrencyClass> getEnumClass() {
300             return MoneyWiseCurrencyClass.class;
301         }
302 
303         @Override
304         public MoneyWiseCurrencyDataMap getDataMap() {
305             return (MoneyWiseCurrencyDataMap) super.getDataMap();
306         }
307 
308         @Override
309         protected MoneyWiseCurrencyList getEmptyList(final PrometheusListStyle pStyle) {
310             final MoneyWiseCurrencyList myList = new MoneyWiseCurrencyList(this);
311             myList.setStyle(pStyle);
312             return myList;
313         }
314 
315         @Override
316         public MoneyWiseCurrency addCopyItem(final PrometheusDataItem pItem) {
317             /* Can only clone an AccountCurrency */
318             if (!(pItem instanceof MoneyWiseCurrency)) {
319                 throw new UnsupportedOperationException();
320             }
321 
322             final MoneyWiseCurrency myCurr = new MoneyWiseCurrency(this, (MoneyWiseCurrency) pItem);
323             add(myCurr);
324             return myCurr;
325         }
326 
327         @Override
328         public MoneyWiseCurrency addNewItem() {
329             throw new UnsupportedOperationException();
330         }
331 
332         /**
333          * Obtain the type of the item.
334          *
335          * @return the type of the item
336          */
337         public String itemType() {
338             return LIST_NAME;
339         }
340 
341         /**
342          * Add an AccountCurrency to the list.
343          *
344          * @param pCurrency the Name of the account currency
345          * @return the new currency
346          * @throws OceanusException on error
347          */
348         public MoneyWiseCurrency addBasicItem(final String pCurrency) throws OceanusException {
349             /* Create a new Account Currency */
350             final MoneyWiseCurrency myCurr = new MoneyWiseCurrency(this, pCurrency);
351 
352             /* Check that this AccountCurrencyId has not been previously added */
353             if (!isIdUnique(myCurr.getIndexedId())) {
354                 myCurr.addError(ERROR_DUPLICATE, MetisDataResource.DATA_ID);
355                 throw new MoneyWiseDataException(myCurr, ERROR_VALIDATION);
356             }
357 
358             /* Add the Account Currency to the list */
359             add(myCurr);
360             return myCurr;
361         }
362 
363         @Override
364         public MoneyWiseCurrency addValuesItem(final PrometheusDataValues pValues) throws OceanusException {
365             /* Create the currency */
366             final MoneyWiseCurrency myCurrency = new MoneyWiseCurrency(this, pValues);
367 
368             /* Check that this CurrencyId has not been previously added */
369             if (!isIdUnique(myCurrency.getIndexedId())) {
370                 myCurrency.addError(ERROR_DUPLICATE, MetisDataResource.DATA_ID);
371                 throw new MoneyWiseDataException(myCurrency, ERROR_VALIDATION);
372             }
373 
374             /* Add to the list */
375             add(myCurrency);
376 
377             /* Return it */
378             return myCurrency;
379         }
380 
381         @Override
382         public void populateDefaults() throws OceanusException {
383             /* Initialise the reporting currency */
384             initialiseReporting();
385 
386             /* Ensure that the list is sorted */
387             reSort();
388         }
389 
390         /**
391          * Initialise the reporting currency.
392          */
393         public void initialiseReporting() {
394             /* Determine the default currency */
395             final Currency myCurrency = OceanusMoney.getDefaultCurrency();
396 
397             /* Find the currency in the list */
398             MoneyWiseCurrency myCurr = findCurrency(myCurrency);
399             if (myCurr == null) {
400                 /* Default to GBP if local currency not found */
401                 myCurr = findItemByClass(MoneyWiseCurrencyClass.GBP);
402             }
403 
404             /* If we have a currency */
405             if (myCurr != null) {
406                 /* Set it as the reporting */
407                 myCurr.setReporting(Boolean.TRUE);
408                 myCurr.setValueEnabled(Boolean.TRUE);
409             }
410         }
411 
412         /**
413          * find a currency in the list.
414          *
415          * @param pCurrency the currency to find
416          * @return The currency
417          */
418         public MoneyWiseCurrency findCurrency(final Currency pCurrency) {
419             /* Look up the currency */
420             final MoneyWiseCurrencyClass myClass = MoneyWiseCurrencyClass.fromCurrency(pCurrency);
421             return findItemByClass(myClass);
422         }
423 
424         /**
425          * Find the reporting currency.
426          *
427          * @return The reporting currency
428          */
429         public MoneyWiseCurrency findReporting() {
430             /* look up the reporting in the map */
431             final MoneyWiseCurrencyDataMap myMap = getDataMap();
432             return myMap == null
433                     ? null
434                     : myMap.getReporting();
435         }
436 
437         @Override
438         protected MoneyWiseCurrency newItem(final PrometheusStaticDataClass pClass) throws OceanusException {
439             /* Create the currency */
440             final MoneyWiseCurrency myCurr = new MoneyWiseCurrency(this, (MoneyWiseCurrencyClass) pClass);
441 
442             /* Check that this CurrId has not been previously added */
443             if (!isIdUnique(myCurr.getIndexedId())) {
444                 myCurr.addError(ERROR_DUPLICATE, MetisDataResource.DATA_ID);
445                 throw new MoneyWiseDataException(myCurr, ERROR_VALIDATION);
446             }
447 
448             /* Add to the list */
449             add(myCurr);
450 
451             /* Return it */
452             return myCurr;
453         }
454 
455         /**
456          * Set reporting currency.
457          *
458          * @param pCurrency the new reporting currency.
459          */
460         public void setReportingCurrency(final MoneyWiseCurrency pCurrency) {
461             /* Find the reportingdefault currency */
462             final MoneyWiseCurrency myCurr = findReporting();
463 
464             /* If we are changing the currency */
465             if (!pCurrency.equals(myCurr)) {
466                 /* If we have a default value */
467                 if (myCurr != null) {
468                     /* Clear default value */
469                     myCurr.pushHistory();
470                     myCurr.setReporting(Boolean.FALSE);
471                 }
472 
473                 /* Set new currency */
474                 pCurrency.pushHistory();
475                 pCurrency.setReporting(Boolean.TRUE);
476             }
477         }
478 
479         @Override
480         protected MoneyWiseCurrencyDataMap allocateDataMap() {
481             return new MoneyWiseCurrencyDataMap();
482         }
483     }
484 
485     /**
486      * The dataMap class.
487      */
488     public static final class MoneyWiseCurrencyDataMap
489             extends PrometheusStaticDataMap<MoneyWiseCurrency> {
490         /**
491          * Report fields.
492          */
493         private static final MetisFieldSet<MoneyWiseCurrencyDataMap> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseCurrencyDataMap.class);
494 
495         /*
496          * Declare Fields.
497          */
498         static {
499             FIELD_DEFS.declareLocalField(MoneyWiseStaticResource.CURRENCY_REPORTING, MoneyWiseCurrencyDataMap::getReporting);
500         }
501 
502         /**
503          * Reporting value.
504          */
505         private MoneyWiseCurrency theReporting;
506 
507         /**
508          * Reporting count.
509          */
510         private Integer theReportingCount;
511 
512         /**
513          * Constructor.
514          */
515         private MoneyWiseCurrencyDataMap() {
516         }
517 
518         @Override
519         public MetisFieldSet<MoneyWiseCurrencyDataMap> getDataFieldSet() {
520             return FIELD_DEFS;
521         }
522 
523         @Override
524         public String formatObject(final OceanusDataFormatter pFormatter) {
525             return FIELD_DEFS.getName();
526         }
527 
528         @Override
529         public void resetMap() {
530             super.resetMap();
531             theReporting = null;
532             theReportingCount = null;
533         }
534 
535         @Override
536         public void adjustForItem(final PrometheusDataItem pItem) {
537             /* Adjust order count */
538             final MoneyWiseCurrency myItem = (MoneyWiseCurrency) pItem;
539             if (Boolean.TRUE.equals(myItem.isReporting())) {
540                 theReporting = myItem;
541                 theReportingCount = theReportingCount == null
542                         ? ONE
543                         : theReportingCount + 1;
544             }
545 
546             /* Adjust name/order count */
547             super.adjustForItem(pItem);
548         }
549 
550         /**
551          * find reporting currency.
552          *
553          * @return the reporting currency
554          */
555         public MoneyWiseCurrency getReporting() {
556             return theReporting;
557         }
558 
559         /**
560          * Check validity of report count.
561          *
562          * @return true/false
563          */
564         public boolean validReportCount() {
565             return ONE.equals(theReportingCount);
566         }
567     }
568 }