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