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