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