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.basic;
18  
19  import io.github.tonywasher.joceanus.metis.data.MetisDataDifference;
20  import io.github.tonywasher.joceanus.metis.data.MetisDataEditState;
21  import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataFieldId;
22  import io.github.tonywasher.joceanus.metis.data.MetisDataResource;
23  import io.github.tonywasher.joceanus.metis.data.MetisDataState;
24  import io.github.tonywasher.joceanus.metis.field.MetisFieldItem;
25  import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
26  import io.github.tonywasher.joceanus.metis.field.MetisFieldVersionedSet;
27  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseCashCategory.MoneyWiseCashCategoryList;
28  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseCashInfo.MoneyWiseCashInfoList;
29  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWisePayee.MoneyWisePayeeList;
30  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseAccountInfoClass;
31  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseAccountInfoType.MoneyWiseAccountInfoTypeList;
32  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseCashCategoryClass;
33  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseCurrency;
34  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseCurrency.MoneyWiseCurrencyList;
35  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseStaticDataType;
36  import io.github.tonywasher.joceanus.moneywise.exc.MoneyWiseDataException;
37  import io.github.tonywasher.joceanus.moneywise.exc.MoneyWiseLogicException;
38  import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
39  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusMoney;
40  import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
41  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataItem;
42  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataMapItem;
43  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataResource;
44  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataValues;
45  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataValues.PrometheusInfoItem;
46  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataValues.PrometheusInfoSetItem;
47  import io.github.tonywasher.joceanus.prometheus.views.PrometheusEditSet;
48  
49  import java.util.Iterator;
50  
51  /**
52   * Cash class.
53   */
54  public class MoneyWiseCash
55          extends MoneyWiseAssetBase
56          implements PrometheusInfoSetItem {
57      /**
58       * Object name.
59       */
60      public static final String OBJECT_NAME = MoneyWiseBasicDataType.CASH.getItemName();
61  
62      /**
63       * List name.
64       */
65      public static final String LIST_NAME = MoneyWiseBasicDataType.CASH.getListName();
66  
67      /**
68       * Local Report fields.
69       */
70      private static final MetisFieldVersionedSet<MoneyWiseCash> FIELD_DEFS = MetisFieldVersionedSet.newVersionedFieldSet(MoneyWiseCash.class);
71  
72      /*
73       * FieldIds.
74       */
75      static {
76          FIELD_DEFS.declareLocalField(PrometheusDataResource.DATAINFOSET_NAME, MoneyWiseCash::getInfoSet);
77          FIELD_DEFS.buildFieldMap(MoneyWiseAccountInfoClass.class, MoneyWiseCash::getFieldValue);
78      }
79  
80      /**
81       * Do we have an InfoSet.
82       */
83      private final boolean hasInfoSet;
84  
85      /**
86       * Should we use infoSet for DataState etc.
87       */
88      private final boolean useInfoSet;
89  
90      /**
91       * CashInfoSet.
92       */
93      private final MoneyWiseCashInfoSet theInfoSet;
94  
95      /**
96       * Copy Constructor.
97       *
98       * @param pList the list
99       * @param pCash The Cash to copy
100      */
101     protected MoneyWiseCash(final MoneyWiseCashList pList,
102                             final MoneyWiseCash pCash) {
103         /* Set standard values */
104         super(pList, pCash);
105 
106         /* switch on list type */
107         switch (getList().getStyle()) {
108             case EDIT:
109                 theInfoSet = new MoneyWiseCashInfoSet(this, pList.getActInfoTypes(), pList.getCashInfo());
110                 theInfoSet.cloneDataInfoSet(pCash.getInfoSet());
111                 hasInfoSet = true;
112                 useInfoSet = true;
113                 break;
114             case CLONE, CORE:
115                 theInfoSet = new MoneyWiseCashInfoSet(this, pList.getActInfoTypes(), pList.getCashInfo());
116                 hasInfoSet = true;
117                 useInfoSet = false;
118                 break;
119             default:
120                 theInfoSet = null;
121                 hasInfoSet = false;
122                 useInfoSet = false;
123                 break;
124         }
125     }
126 
127     /**
128      * Values constructor.
129      *
130      * @param pList   the List to add to
131      * @param pValues the values constructor
132      * @throws OceanusException on error
133      */
134     private MoneyWiseCash(final MoneyWiseCashList pList,
135                           final PrometheusDataValues pValues) throws OceanusException {
136         /* Initialise the item */
137         super(pList, pValues);
138 
139         /* Create the InfoSet */
140         theInfoSet = new MoneyWiseCashInfoSet(this, pList.getActInfoTypes(), pList.getCashInfo());
141         hasInfoSet = true;
142         useInfoSet = false;
143     }
144 
145     /**
146      * Edit Constructor.
147      *
148      * @param pList the list
149      */
150     public MoneyWiseCash(final MoneyWiseCashList pList) {
151         super(pList);
152 
153         /* Build InfoSet */
154         theInfoSet = new MoneyWiseCashInfoSet(this, pList.getActInfoTypes(), pList.getCashInfo());
155         hasInfoSet = true;
156         useInfoSet = true;
157     }
158 
159     @Override
160     public MetisFieldSetDef getDataFieldSet() {
161         return FIELD_DEFS;
162     }
163 
164     @Override
165     public boolean includeXmlField(final MetisDataFieldId pField) {
166         /* Determine whether fields should be included */
167         if (MoneyWiseBasicResource.CATEGORY_NAME.equals(pField)) {
168             return true;
169         }
170         if (MoneyWiseStaticDataType.CURRENCY.equals(pField)) {
171             return true;
172         }
173 
174         /* Pass call on */
175         return super.includeXmlField(pField);
176     }
177 
178     @Override
179     public Long getExternalId() {
180         return MoneyWiseAssetType.createExternalId(isAutoExpense() ? MoneyWiseAssetType.AUTOEXPENSE : MoneyWiseAssetType.CASH, getIndexedId());
181     }
182 
183     @Override
184     public MoneyWiseCashInfoSet getInfoSet() {
185         return theInfoSet;
186     }
187 
188     /**
189      * Obtain fieldValue for infoSet.
190      *
191      * @param pFieldId the fieldId
192      * @return the value
193      */
194     private Object getFieldValue(final MetisDataFieldId pFieldId) {
195         return theInfoSet != null ? theInfoSet.getFieldValue(pFieldId) : null;
196     }
197 
198     /**
199      * Obtain Notes.
200      *
201      * @return the notes
202      */
203     public char[] getNotes() {
204         return hasInfoSet
205                 ? theInfoSet.getValue(MoneyWiseAccountInfoClass.NOTES, char[].class)
206                 : null;
207     }
208 
209     /**
210      * Obtain AutoExpense.
211      *
212      * @return the autoExpense category
213      */
214     public MoneyWiseTransCategory getAutoExpense() {
215         return hasInfoSet
216                 ? theInfoSet.getEventCategory(MoneyWiseAccountInfoClass.AUTOEXPENSE)
217                 : null;
218     }
219 
220     /**
221      * Obtain AutoPayee.
222      *
223      * @return the autoExpense category
224      */
225     public MoneyWisePayee getAutoPayee() {
226         return hasInfoSet
227                 ? theInfoSet.getPayee(MoneyWiseAccountInfoClass.AUTOPAYEE)
228                 : null;
229     }
230 
231     @Override
232     public OceanusMoney getOpeningBalance() {
233         return hasInfoSet
234                 ? theInfoSet.getValue(MoneyWiseAccountInfoClass.OPENINGBALANCE, OceanusMoney.class)
235                 : null;
236     }
237 
238     @Override
239     public MoneyWiseCashCategory getCategory() {
240         return getValues().getValue(MoneyWiseBasicResource.CATEGORY_NAME, MoneyWiseCashCategory.class);
241     }
242 
243     /**
244      * Obtain CategoryId.
245      *
246      * @return the categoryId
247      */
248     public Integer getCategoryId() {
249         final MoneyWiseCashCategory myCategory = getCategory();
250         return myCategory == null
251                 ? null
252                 : myCategory.getIndexedId();
253     }
254 
255     /**
256      * Obtain CategoryName.
257      *
258      * @return the categoryName
259      */
260     public String getCategoryName() {
261         final MoneyWiseCashCategory myCategory = getCategory();
262         return myCategory == null
263                 ? null
264                 : myCategory.getName();
265     }
266 
267     /**
268      * Obtain CashCategoryClass.
269      *
270      * @return the categoryClass
271      */
272     public MoneyWiseCashCategoryClass getCategoryClass() {
273         final MoneyWiseCashCategory myCategory = getCategory();
274         return myCategory == null
275                 ? null
276                 : myCategory.getCategoryTypeClass();
277     }
278 
279     @Override
280     public boolean isForeign() {
281         final MoneyWiseCurrency myDefault = getDataSet().getReportingCurrency();
282         return !myDefault.equals(getAssetCurrency());
283     }
284 
285     @Override
286     public boolean isAutoExpense() {
287         return MoneyWiseCashCategoryClass.AUTOEXPENSE.equals(getCategoryClass());
288     }
289 
290     @Override
291     public MoneyWiseAssetType getAssetType() {
292         return isAutoExpense()
293                 ? MoneyWiseAssetType.AUTOEXPENSE
294                 : MoneyWiseAssetType.CASH;
295     }
296 
297     @Override
298     public MoneyWiseCash getBase() {
299         return (MoneyWiseCash) super.getBase();
300     }
301 
302     @Override
303     public MoneyWiseCashList getList() {
304         return (MoneyWiseCashList) super.getList();
305     }
306 
307     @Override
308     public MetisDataState getState() {
309         /* Pop history for self */
310         MetisDataState myState = super.getState();
311 
312         /* If we should use the InfoSet */
313         if ((myState == MetisDataState.CLEAN) && useInfoSet) {
314             /* Get state for infoSet */
315             myState = theInfoSet.getState();
316         }
317 
318         /* Return the state */
319         return myState;
320     }
321 
322     @Override
323     public MetisDataEditState getEditState() {
324         /* Pop history for self */
325         MetisDataEditState myState = super.getEditState();
326 
327         /* If we should use the InfoSet */
328         if (myState == MetisDataEditState.CLEAN
329                 && useInfoSet) {
330             /* Get state for infoSet */
331             myState = theInfoSet.getEditState();
332         }
333 
334         /* Return the state */
335         return myState;
336     }
337 
338     @Override
339     public boolean hasHistory() {
340         /* Check for history for self */
341         boolean hasHistory = super.hasHistory();
342 
343         /* If we should use the InfoSet */
344         if (!hasHistory && useInfoSet) {
345             /* Check history for infoSet */
346             hasHistory = theInfoSet.hasHistory();
347         }
348 
349         /* Return details */
350         return hasHistory;
351     }
352 
353     @Override
354     public void pushHistory() {
355         /* Push history for self */
356         super.pushHistory();
357 
358         /* If we should use the InfoSet */
359         if (useInfoSet) {
360             /* Push history for infoSet */
361             theInfoSet.pushHistory();
362         }
363     }
364 
365     @Override
366     public void popHistory() {
367         /* Pop history for self */
368         super.popHistory();
369 
370         /* If we should use the InfoSet */
371         if (useInfoSet) {
372             /* Pop history for infoSet */
373             theInfoSet.popHistory();
374         }
375     }
376 
377     @Override
378     public boolean checkForHistory() {
379         /* Check for history for self */
380         boolean bChanges = super.checkForHistory();
381 
382         /* If we should use the InfoSet */
383         if (useInfoSet) {
384             /* Check for history for infoSet */
385             bChanges |= theInfoSet.checkForHistory();
386         }
387 
388         /* return result */
389         return bChanges;
390     }
391 
392     @Override
393     public MetisDataDifference fieldChanged(final MetisDataFieldId pField) {
394         /* Handle InfoSet fields */
395         final MoneyWiseAccountInfoClass myClass = MoneyWiseCashInfoSet.getClassForField(pField);
396         if (myClass != null) {
397             return useInfoSet
398                     ? theInfoSet.fieldChanged(myClass)
399                     : MetisDataDifference.IDENTICAL;
400         }
401 
402         /* Check super fields */
403         return super.fieldChanged(pField);
404     }
405 
406     @Override
407     public void setDeleted(final boolean bDeleted) {
408         /* Pass call to infoSet if required */
409         if (useInfoSet) {
410             theInfoSet.setDeleted(bDeleted);
411         }
412 
413         /* Pass call onwards */
414         super.setDeleted(bDeleted);
415     }
416 
417     /**
418      * Set defaults.
419      *
420      * @throws OceanusException on error
421      */
422     public void setDefaults() throws OceanusException {
423         getList().getValidator().setDefaults(this);
424     }
425 
426     /**
427      * autoCorrect values after change.
428      *
429      * @throws OceanusException on error
430      */
431     public void autoCorrect() throws OceanusException {
432         getList().getValidator().autoCorrect(this);
433     }
434 
435     @Override
436     public int compareValues(final PrometheusDataItem pThat) {
437         /* Check the category and then the name */
438         final MoneyWiseCash myThat = (MoneyWiseCash) pThat;
439         int iDiff = MetisDataDifference.compareObject(getCategory(), myThat.getCategory());
440         if (iDiff == 0) {
441             iDiff = MetisDataDifference.compareObject(getName(), myThat.getName());
442         }
443         return iDiff;
444     }
445 
446     @Override
447     public void resolveDataSetLinks() throws OceanusException {
448         /* Update the Encryption details */
449         super.resolveDataSetLinks();
450 
451         /* Resolve data links */
452         final MoneyWiseDataSet myData = getDataSet();
453         resolveDataLink(MoneyWiseBasicResource.CATEGORY_NAME, myData.getCashCategories());
454         resolveDataLink(MoneyWiseStaticDataType.CURRENCY, myData.getAccountCurrencies());
455     }
456 
457     @Override
458     protected void resolveEditSetLinks() throws OceanusException {
459         /* Access the editSet */
460         final PrometheusEditSet myEditSet = getList().getEditSet();
461 
462         /* Resolve Category/Currency if required */
463         if (myEditSet.hasDataType(MoneyWiseBasicDataType.CASHCATEGORY)) {
464             resolveDataLink(MoneyWiseBasicResource.CATEGORY_NAME, myEditSet.getDataList(MoneyWiseBasicDataType.CASHCATEGORY, MoneyWiseCashCategoryList.class));
465         }
466         if (myEditSet.hasDataType(MoneyWiseStaticDataType.CURRENCY)) {
467             resolveDataLink(MoneyWiseStaticDataType.CURRENCY, myEditSet.getDataList(MoneyWiseStaticDataType.CURRENCY, MoneyWiseCurrencyList.class));
468         }
469 
470         /* Resolve links in infoSet */
471         theInfoSet.resolveEditSetLinks(myEditSet);
472     }
473 
474     /**
475      * Set a new Notes.
476      *
477      * @param pNotes the new notes
478      * @throws OceanusException on error
479      */
480     public void setNotes(final char[] pNotes) throws OceanusException {
481         setInfoSetValue(MoneyWiseAccountInfoClass.NOTES, pNotes);
482     }
483 
484     /**
485      * Set a new autoExpense.
486      *
487      * @param pCategory the new autoExpense
488      * @throws OceanusException on error
489      */
490     public void setAutoExpense(final MoneyWiseTransCategory pCategory) throws OceanusException {
491         setInfoSetValue(MoneyWiseAccountInfoClass.AUTOEXPENSE, pCategory);
492     }
493 
494     /**
495      * Set a new autoPayee.
496      *
497      * @param pPayee the new autoPayee
498      * @throws OceanusException on error
499      */
500     public void setAutoPayee(final MoneyWisePayee pPayee) throws OceanusException {
501         setInfoSetValue(MoneyWiseAccountInfoClass.AUTOPAYEE, pPayee);
502     }
503 
504     /**
505      * Set a new opening balance.
506      *
507      * @param pBalance the new opening balance
508      * @throws OceanusException on error
509      */
510     public void setOpeningBalance(final OceanusMoney pBalance) throws OceanusException {
511         setInfoSetValue(MoneyWiseAccountInfoClass.OPENINGBALANCE, pBalance);
512     }
513 
514     /**
515      * Set an infoSet value.
516      *
517      * @param pInfoClass the class of info to set
518      * @param pValue     the value to set
519      * @throws OceanusException on error
520      */
521     private void setInfoSetValue(final MoneyWiseAccountInfoClass pInfoClass,
522                                  final Object pValue) throws OceanusException {
523         /* Reject if there is no infoSet */
524         if (!hasInfoSet) {
525             throw new MoneyWiseLogicException(ERROR_BADINFOSET);
526         }
527 
528         /* Set the value */
529         theInfoSet.setValue(pInfoClass, pValue);
530     }
531 
532     @Override
533     public void touchUnderlyingItems() {
534         /* touch the category and currency */
535         getCategory().touchItem(this);
536         getAssetCurrency().touchItem(this);
537 
538         /* touch infoSet items */
539         theInfoSet.touchUnderlyingItems();
540     }
541 
542     @Override
543     public void touchOnUpdate() {
544         /* Adjust infoSet update touches */
545         theInfoSet.touchOnUpdate();
546     }
547 
548     /**
549      * Update base cash from an edited cash.
550      *
551      * @param pCash the edited cash
552      * @return whether changes have been made
553      */
554     @Override
555     public boolean applyChanges(final PrometheusDataItem pCash) {
556         /* Can only update from a cash */
557         if (!(pCash instanceof MoneyWiseCash myCash)) {
558             return false;
559         }
560 
561         /* Store the current detail into history */
562         pushHistory();
563 
564         /* Apply basic changes */
565         applyBasicChanges(myCash);
566 
567         /* Check for changes */
568         return checkForHistory();
569     }
570 
571     @Override
572     public void adjustMapForItem() {
573         final MoneyWiseCashList myList = getList();
574         final MoneyWiseCashDataMap myMap = myList.getDataMap();
575         myMap.adjustForItem(this);
576     }
577 
578     @Override
579     public void removeItem() {
580         theInfoSet.removeItems();
581         super.removeItem();
582     }
583 
584     /**
585      * The Cash List class.
586      */
587     public static class MoneyWiseCashList
588             extends MoneyWiseAssetBaseList<MoneyWiseCash> {
589         /**
590          * Report fields.
591          */
592         private static final MetisFieldSet<MoneyWiseCashList> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseCashList.class);
593 
594         /**
595          * The CashInfo List.
596          */
597         private MoneyWiseCashInfoList theInfoList;
598 
599         /**
600          * The AccountInfoType list.
601          */
602         private MoneyWiseAccountInfoTypeList theInfoTypeList;
603 
604         /**
605          * Construct an empty CORE list.
606          *
607          * @param pData the DataSet for the list
608          */
609         public MoneyWiseCashList(final MoneyWiseDataSet pData) {
610             super(pData, MoneyWiseCash.class, MoneyWiseBasicDataType.CASH);
611         }
612 
613         /**
614          * Constructor for a cloned List.
615          *
616          * @param pSource the source List
617          */
618         protected MoneyWiseCashList(final MoneyWiseCashList pSource) {
619             super(pSource);
620         }
621 
622         @Override
623         public MetisFieldSet<MoneyWiseCashList> getDataFieldSet() {
624             return FIELD_DEFS;
625         }
626 
627         @Override
628         public String listName() {
629             return LIST_NAME;
630         }
631 
632         @Override
633         public MetisFieldSetDef getItemFields() {
634             return MoneyWiseCash.FIELD_DEFS;
635         }
636 
637         @Override
638         protected MoneyWiseCashDataMap getDataMap() {
639             return (MoneyWiseCashDataMap) super.getDataMap();
640         }
641 
642         /**
643          * Obtain the depositInfoList.
644          *
645          * @return the deposit info list
646          */
647         public MoneyWiseCashInfoList getCashInfo() {
648             if (theInfoList == null) {
649                 theInfoList = getDataSet().getCashInfo();
650             }
651             return theInfoList;
652         }
653 
654         /**
655          * Obtain the accountInfoTypeList.
656          *
657          * @return the account info type list
658          */
659         public MoneyWiseAccountInfoTypeList getActInfoTypes() {
660             if (theInfoTypeList == null) {
661                 theInfoTypeList = getEditSet() == null
662                         ? getDataSet().getActInfoTypes()
663                         : getEditSet().getDataList(MoneyWiseStaticDataType.ACCOUNTINFOTYPE, MoneyWiseAccountInfoTypeList.class);
664             }
665             return theInfoTypeList;
666         }
667 
668         @Override
669         protected MoneyWiseCashList getEmptyList(final PrometheusListStyle pStyle) {
670             final MoneyWiseCashList myList = new MoneyWiseCashList(this);
671             myList.setStyle(pStyle);
672             return myList;
673         }
674 
675         /**
676          * Derive Edit list.
677          *
678          * @param pEditSet the editSet
679          * @return the edit list
680          * @throws OceanusException on error
681          */
682         public MoneyWiseCashList deriveEditList(final PrometheusEditSet pEditSet) throws OceanusException {
683             /* Build an empty List */
684             final MoneyWiseCashList myList = getEmptyList(PrometheusListStyle.EDIT);
685             final MoneyWisePayeeList myPayees = pEditSet.getDataList(MoneyWiseBasicDataType.PAYEE, MoneyWisePayeeList.class);
686             myList.ensureMap(myPayees);
687             pEditSet.setEditEntryList(MoneyWiseBasicDataType.CASH, myList);
688             myList.getValidator().setEditSet(pEditSet);
689 
690             /* Store InfoType list */
691             myList.theInfoTypeList = pEditSet.getDataList(MoneyWiseStaticDataType.ACCOUNTINFOTYPE, MoneyWiseAccountInfoTypeList.class);
692 
693             /* Create info List */
694             final MoneyWiseCashInfoList myCashInfo = getCashInfo();
695             myList.theInfoList = myCashInfo.getEmptyList(PrometheusListStyle.EDIT);
696             pEditSet.setEditEntryList(MoneyWiseBasicDataType.CASHINFO, myList.theInfoList);
697 
698             /* Store the editSet */
699             myList.setEditSet(pEditSet);
700 
701             /* Loop through the cash */
702             final Iterator<MoneyWiseCash> myIterator = iterator();
703             while (myIterator.hasNext()) {
704                 final MoneyWiseCash myCurr = myIterator.next();
705 
706                 /* Ignore deleted deposits */
707                 if (myCurr.isDeleted()) {
708                     continue;
709                 }
710 
711                 /* Build the new linked cash and add it to the list */
712                 final MoneyWiseCash myCash = new MoneyWiseCash(myList, myCurr);
713                 myList.add(myCash);
714                 myCash.resolveEditSetLinks();
715 
716                 /* Adjust the map */
717                 myCash.adjustMapForItem();
718             }
719 
720             /* Return the list */
721             return myList;
722         }
723 
724         @Override
725         public MoneyWiseCash findItemByName(final String pName) {
726             /* look up the name in the map */
727             return getDataMap().findItemByName(pName);
728         }
729 
730         @Override
731         public boolean checkAvailableName(final String pName) {
732             /* check availability in map */
733             return getDataMap().availableName(pName);
734         }
735 
736         @Override
737         public boolean validNameCount(final String pName) {
738             /* check availability in map */
739             return getDataMap().validNameCount(pName);
740         }
741 
742         @Override
743         public MoneyWiseCash addCopyItem(final PrometheusDataItem pCash) {
744             /* Can only clone a Cash */
745             if (!(pCash instanceof MoneyWiseCash)) {
746                 throw new UnsupportedOperationException();
747             }
748 
749             final MoneyWiseCash myCash = new MoneyWiseCash(this, (MoneyWiseCash) pCash);
750             add(myCash);
751             return myCash;
752         }
753 
754         @Override
755         public MoneyWiseCash addNewItem() {
756             final MoneyWiseCash myCash = new MoneyWiseCash(this);
757             add(myCash);
758             return myCash;
759         }
760 
761         @Override
762         public MoneyWiseCash addValuesItem(final PrometheusDataValues pValues) throws OceanusException {
763             /* Create the deposit */
764             final MoneyWiseCash myCash = new MoneyWiseCash(this, pValues);
765 
766             /* Check that this CashId has not been previously added */
767             if (!isIdUnique(myCash.getIndexedId())) {
768                 myCash.addError(ERROR_DUPLICATE, MetisDataResource.DATA_ID);
769                 throw new MoneyWiseDataException(myCash, ERROR_VALIDATION);
770             }
771 
772             /* Add to the list */
773             add(myCash);
774 
775             /* Loop through the info items */
776             if (pValues.hasInfoItems()) {
777                 /* Loop through the items */
778                 final Iterator<PrometheusInfoItem> myIterator = pValues.infoIterator();
779                 while (myIterator.hasNext()) {
780                     final PrometheusInfoItem myItem = myIterator.next();
781 
782                     /* Build info */
783                     final PrometheusDataValues myValues = myItem.getValues(myCash);
784                     theInfoList.addValuesItem(myValues);
785                 }
786             }
787 
788             /* Return it */
789             return myCash;
790         }
791 
792         /**
793          * Ensure Map based on the payee list.
794          *
795          * @param pPayees the payee list
796          */
797         private void ensureMap(final MoneyWisePayeeList pPayees) {
798             setDataMap(new MoneyWiseCashDataMap(pPayees));
799         }
800 
801         @Override
802         protected MoneyWiseCashDataMap allocateDataMap() {
803             return new MoneyWiseCashDataMap(getDataSet().getPayees());
804         }
805 
806         @Override
807         public void postProcessOnLoad() throws OceanusException {
808             /* Resolve links and sort the data */
809             super.resolveDataSetLinks();
810             reSort();
811         }
812     }
813 
814     /**
815      * The dataMap class.
816      */
817     protected static class MoneyWiseCashDataMap
818             implements PrometheusDataMapItem, MetisFieldItem {
819         /**
820          * Report fields.
821          */
822         private static final MetisFieldSet<MoneyWiseCashDataMap> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseCashDataMap.class);
823 
824         /*
825          * UnderlyingMap Field Id.
826          */
827         static {
828             FIELD_DEFS.declareLocalField(MoneyWiseBasicResource.MONEYWISEDATA_MAP_UNDERLYING, MoneyWiseCashDataMap::getUnderlyingMap);
829         }
830 
831         /**
832          * The assetMap.
833          */
834         private final MoneyWiseAssetDataMap theUnderlyingMap;
835 
836         /**
837          * Constructor.
838          *
839          * @param pPayees the payee list
840          */
841         protected MoneyWiseCashDataMap(final MoneyWisePayeeList pPayees) {
842             theUnderlyingMap = pPayees.getDataMap().getUnderlyingMap();
843         }
844 
845         @Override
846         public MetisFieldSet<MoneyWiseCashDataMap> getDataFieldSet() {
847             return FIELD_DEFS;
848         }
849 
850         @Override
851         public String formatObject(final OceanusDataFormatter pFormatter) {
852             return FIELD_DEFS.getName();
853         }
854 
855         /**
856          * Obtain the underlying map.
857          *
858          * @return the underlying map
859          */
860         private MoneyWiseAssetDataMap getUnderlyingMap() {
861             return theUnderlyingMap;
862         }
863 
864         @Override
865         public void resetMap() {
866             /* No action */
867         }
868 
869         @Override
870         public void adjustForItem(final PrometheusDataItem pItem) {
871             /* Adjust name count */
872             theUnderlyingMap.adjustForItem(pItem);
873         }
874 
875         /**
876          * find item by name.
877          *
878          * @param pName the name to look up
879          * @return the matching item
880          */
881         public MoneyWiseCash findItemByName(final String pName) {
882             final MoneyWiseAssetBase myAsset = theUnderlyingMap.findAssetByName(pName);
883             return myAsset instanceof MoneyWiseCash myCash
884                     ? myCash
885                     : null;
886         }
887 
888         /**
889          * Check validity of name.
890          *
891          * @param pName the name to look up
892          * @return true/false
893          */
894         public boolean validNameCount(final String pName) {
895             return theUnderlyingMap.validNameCount(pName);
896         }
897 
898         /**
899          * Check availability of name.
900          *
901          * @param pName the key to look up
902          * @return true/false
903          */
904         public boolean availableName(final String pName) {
905             return theUnderlyingMap.availableKey(pName);
906         }
907     }
908 }