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