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.MoneyWisePayeeInfo.MoneyWisePayeeInfoList;
28  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseAccountInfoClass;
29  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseAccountInfoType.MoneyWiseAccountInfoTypeList;
30  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWisePayeeClass;
31  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWisePayeeType;
32  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWisePayeeType.MoneyWisePayeeTypeList;
33  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseStaticDataType;
34  import io.github.tonywasher.joceanus.moneywise.exc.MoneyWiseDataException;
35  import io.github.tonywasher.joceanus.moneywise.exc.MoneyWiseLogicException;
36  import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
37  import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
38  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataInstanceMap;
39  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataItem;
40  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataMapItem;
41  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataResource;
42  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataSet;
43  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataValues;
44  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataValues.PrometheusInfoItem;
45  import io.github.tonywasher.joceanus.prometheus.data.PrometheusEncrypted.PrometheusDataInfoSetItemCtl;
46  import io.github.tonywasher.joceanus.prometheus.data.PrometheusListStyle;
47  import io.github.tonywasher.joceanus.prometheus.views.PrometheusEditSet;
48  
49  import java.util.HashMap;
50  import java.util.Iterator;
51  import java.util.Map;
52  
53  /**
54   * Payee class.
55   */
56  public class MoneyWisePayee
57          extends MoneyWiseAssetBase
58          implements PrometheusDataInfoSetItemCtl<MoneyWisePayeeInfo> {
59      /**
60       * Object name.
61       */
62      public static final String OBJECT_NAME = MoneyWiseBasicDataType.PAYEE.getItemName();
63  
64      /**
65       * List name.
66       */
67      public static final String LIST_NAME = MoneyWiseBasicDataType.PAYEE.getListName();
68  
69      /**
70       * Local Report fields.
71       */
72      private static final MetisFieldVersionedSet<MoneyWisePayee> FIELD_DEFS = MetisFieldVersionedSet.newVersionedFieldSet(MoneyWisePayee.class);
73  
74      /*
75       * FieldIds.
76       */
77      static {
78          FIELD_DEFS.declareLocalField(PrometheusDataResource.DATAINFOSET_NAME, MoneyWisePayee::getInfoSet);
79          FIELD_DEFS.buildFieldMap(MoneyWiseAccountInfoClass.class, MoneyWisePayee::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       * PayeeInfoSet.
94       */
95      private final MoneyWisePayeeInfoSet theInfoSet;
96  
97      /**
98       * Copy Constructor.
99       *
100      * @param pList  the list
101      * @param pPayee The Payee to copy
102      */
103     protected MoneyWisePayee(final MoneyWisePayeeList pList,
104                              final MoneyWisePayee pPayee) {
105         /* Set standard values */
106         super(pList, pPayee);
107 
108         /* switch on list type */
109         switch (getList().getStyle()) {
110             case EDIT:
111                 theInfoSet = new MoneyWisePayeeInfoSet(this, pList.getActInfoTypes(), pList.getPayeeInfo());
112                 theInfoSet.cloneDataInfoSet(pPayee.getInfoSet());
113                 hasInfoSet = true;
114                 useInfoSet = true;
115                 break;
116             case CLONE, CORE:
117                 theInfoSet = new MoneyWisePayeeInfoSet(this, pList.getActInfoTypes(), pList.getPayeeInfo());
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 MoneyWisePayee(final MoneyWisePayeeList pList,
137                            final PrometheusDataValues pValues) throws OceanusException {
138         /* Initialise the item */
139         super(pList, pValues);
140 
141         /* Create the InfoSet */
142         theInfoSet = new MoneyWisePayeeInfoSet(this, pList.getActInfoTypes(), pList.getPayeeInfo());
143         hasInfoSet = true;
144         useInfoSet = false;
145     }
146 
147     /**
148      * Edit Constructor.
149      *
150      * @param pList the list
151      */
152     public MoneyWisePayee(final MoneyWisePayeeList pList) {
153         super(pList);
154 
155         /* Build InfoSet */
156         theInfoSet = new MoneyWisePayeeInfoSet(this, pList.getActInfoTypes(), pList.getPayeeInfo());
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 
173         /* Pass call on */
174         return super.includeXmlField(pField);
175     }
176 
177     @Override
178     public Long getExternalId() {
179         return MoneyWiseAssetType.createExternalId(MoneyWiseAssetType.PAYEE, getIndexedId());
180     }
181 
182     @Override
183     public MoneyWisePayeeInfoSet getInfoSet() {
184         return theInfoSet;
185     }
186 
187     /**
188      * Obtain fieldValue for infoSet.
189      *
190      * @param pFieldId the fieldId
191      * @return the value
192      */
193     private Object getFieldValue(final MetisDataFieldId pFieldId) {
194         return theInfoSet != null ? theInfoSet.getFieldValue(pFieldId) : null;
195     }
196 
197     /**
198      * Obtain WebSite.
199      *
200      * @return the webSite
201      */
202     public char[] getWebSite() {
203         return hasInfoSet
204                 ? theInfoSet.getValue(MoneyWiseAccountInfoClass.WEBSITE, char[].class)
205                 : null;
206     }
207 
208     /**
209      * Obtain CustNo.
210      *
211      * @return the customer #
212      */
213     public char[] getCustNo() {
214         return hasInfoSet
215                 ? theInfoSet.getValue(MoneyWiseAccountInfoClass.CUSTOMERNO, char[].class)
216                 : null;
217     }
218 
219     /**
220      * Obtain UserId.
221      *
222      * @return the userId
223      */
224     public char[] getUserId() {
225         return hasInfoSet
226                 ? theInfoSet.getValue(MoneyWiseAccountInfoClass.USERID, char[].class)
227                 : null;
228     }
229 
230     /**
231      * Obtain Password.
232      *
233      * @return the password
234      */
235     public char[] getPassword() {
236         return hasInfoSet
237                 ? theInfoSet.getValue(MoneyWiseAccountInfoClass.PASSWORD, char[].class)
238                 : null;
239     }
240 
241     /**
242      * Obtain SortCode.
243      *
244      * @return the sort code
245      */
246     public char[] getSortCode() {
247         return hasInfoSet
248                 ? theInfoSet.getValue(MoneyWiseAccountInfoClass.SORTCODE, char[].class)
249                 : null;
250     }
251 
252     /**
253      * Obtain Reference.
254      *
255      * @return the reference
256      */
257     public char[] getReference() {
258         return hasInfoSet
259                 ? theInfoSet.getValue(MoneyWiseAccountInfoClass.REFERENCE, char[].class)
260                 : null;
261     }
262 
263     /**
264      * Obtain Account.
265      *
266      * @return the account
267      */
268     public char[] getAccount() {
269         return hasInfoSet
270                 ? theInfoSet.getValue(MoneyWiseAccountInfoClass.ACCOUNT, char[].class)
271                 : null;
272     }
273 
274     /**
275      * Obtain Notes.
276      *
277      * @return the notes
278      */
279     public char[] getNotes() {
280         return hasInfoSet
281                 ? theInfoSet.getValue(MoneyWiseAccountInfoClass.NOTES, char[].class)
282                 : null;
283     }
284 
285     @Override
286     public MoneyWisePayeeType getCategory() {
287         return getValues().getValue(MoneyWiseBasicResource.CATEGORY_NAME, MoneyWisePayeeType.class);
288     }
289 
290     /**
291      * Obtain categoryId.
292      *
293      * @return the categoryTypeId
294      */
295     public Integer getCategoryId() {
296         final MoneyWisePayeeType myType = getCategory();
297         return (myType == null)
298                 ? null
299                 : myType.getIndexedId();
300     }
301 
302     /**
303      * Obtain categoryName.
304      *
305      * @return the categoryName
306      */
307     public String getCategoryName() {
308         final MoneyWisePayeeType myType = getCategory();
309         return myType == null
310                 ? null
311                 : myType.getName();
312     }
313 
314     /**
315      * Obtain categoryClass.
316      *
317      * @return the categoryClass
318      */
319     public MoneyWisePayeeClass getCategoryClass() {
320         final MoneyWisePayeeType myType = getCategory();
321         return (myType == null)
322                 ? null
323                 : myType.getPayeeClass();
324     }
325 
326     @Override
327     public MoneyWisePayee getBase() {
328         return (MoneyWisePayee) super.getBase();
329     }
330 
331     @Override
332     public MoneyWisePayeeList getList() {
333         return (MoneyWisePayeeList) super.getList();
334     }
335 
336     @Override
337     public MetisDataState getState() {
338         /* Pop history for self */
339         MetisDataState myState = super.getState();
340 
341         /* If we should use the InfoSet */
342         if ((myState == MetisDataState.CLEAN) && useInfoSet) {
343             /* Get state for infoSet */
344             myState = theInfoSet.getState();
345         }
346 
347         /* Return the state */
348         return myState;
349     }
350 
351     @Override
352     public MetisDataEditState getEditState() {
353         /* Pop history for self */
354         MetisDataEditState myState = super.getEditState();
355 
356         /* If we should use the InfoSet */
357         if (myState == MetisDataEditState.CLEAN
358                 && useInfoSet) {
359             /* Get state for infoSet */
360             myState = theInfoSet.getEditState();
361         }
362 
363         /* Return the state */
364         return myState;
365     }
366 
367     @Override
368     public boolean hasHistory() {
369         /* Check for history for self */
370         boolean hasHistory = super.hasHistory();
371 
372         /* If we should use the InfoSet */
373         if (!hasHistory && useInfoSet) {
374             /* Check history for infoSet */
375             hasHistory = theInfoSet.hasHistory();
376         }
377 
378         /* Return details */
379         return hasHistory;
380     }
381 
382     @Override
383     public void pushHistory() {
384         /* Push history for self */
385         super.pushHistory();
386 
387         /* If we should use the InfoSet */
388         if (useInfoSet) {
389             /* Push history for infoSet */
390             theInfoSet.pushHistory();
391         }
392     }
393 
394     @Override
395     public void popHistory() {
396         /* Pop history for self */
397         super.popHistory();
398 
399         /* If we should use the InfoSet */
400         if (useInfoSet) {
401             /* Pop history for infoSet */
402             theInfoSet.popHistory();
403         }
404     }
405 
406     @Override
407     public boolean checkForHistory() {
408         /* Check for history for self */
409         boolean bChanges = super.checkForHistory();
410 
411         /* If we should use the InfoSet */
412         if (useInfoSet) {
413             /* Check for history for infoSet */
414             bChanges |= theInfoSet.checkForHistory();
415         }
416 
417         /* return result */
418         return bChanges;
419     }
420 
421     @Override
422     public MetisDataDifference fieldChanged(final MetisDataFieldId pField) {
423         /* Handle InfoSet fields */
424         final MoneyWiseAccountInfoClass myClass = MoneyWisePayeeInfoSet.getClassForField(pField);
425         if (myClass != null) {
426             return useInfoSet
427                     ? theInfoSet.fieldChanged(myClass)
428                     : MetisDataDifference.IDENTICAL;
429         }
430 
431         /* Check super fields */
432         return super.fieldChanged(pField);
433     }
434 
435     @Override
436     public void setDeleted(final boolean bDeleted) {
437         /* Pass call to infoSet if required */
438         if (useInfoSet) {
439             theInfoSet.setDeleted(bDeleted);
440         }
441 
442         /* Pass call onwards */
443         super.setDeleted(bDeleted);
444     }
445 
446     /**
447      * Is this payee the required class.
448      *
449      * @param pClass the required payee class.
450      * @return true/false
451      */
452     public boolean isPayeeClass(final MoneyWisePayeeClass pClass) {
453         /* Check for match */
454         return getCategoryClass() == pClass;
455     }
456 
457     /**
458      * Is the category hidden?
459      *
460      * @return true/false
461      */
462     @Override
463     public boolean isHidden() {
464         final MoneyWisePayeeClass myClass = this.getCategoryClass();
465         return myClass != null
466                 && myClass.isHiddenType();
467     }
468 
469     /**
470      * Set defaults.
471      *
472      * @throws OceanusException on error
473      */
474     public void setDefaults() throws OceanusException {
475         getList().getValidator().setDefaults(this);
476     }
477 
478     @Override
479     public int compareValues(final PrometheusDataItem pThat) {
480         /* Check the category and then the name */
481         final MoneyWisePayee myThat = (MoneyWisePayee) pThat;
482         int iDiff = MetisDataDifference.compareObject(getCategory(), myThat.getCategory());
483         if (iDiff == 0) {
484             iDiff = MetisDataDifference.compareObject(getName(), myThat.getName());
485         }
486         return iDiff;
487     }
488 
489     @Override
490     public void resolveDataSetLinks() throws OceanusException {
491         /* Update the Base details */
492         super.resolveDataSetLinks();
493 
494         /* Resolve data links */
495         resolveDataLink(MoneyWiseBasicResource.CATEGORY_NAME, MoneyWiseStaticDataType.PAYEETYPE);
496     }
497 
498     @Override
499     protected void resolveEditSetLinks() throws OceanusException {
500         /* Access the editSet */
501         final PrometheusEditSet myEditSet = getList().getEditSet();
502 
503         /* Resolve Parent/Category/Currency if required */
504         if (myEditSet.hasDataType(MoneyWiseStaticDataType.PAYEETYPE)) {
505             resolveDataLink(MoneyWiseBasicResource.CATEGORY_NAME, myEditSet.getDataList(MoneyWiseStaticDataType.PAYEETYPE, MoneyWisePayeeTypeList.class));
506         }
507 
508         /* Resolve links in infoSet */
509         theInfoSet.resolveEditSetLinks(myEditSet);
510     }
511 
512     /**
513      * Set a new WebSite.
514      *
515      * @param pWebSite the new webSite
516      * @throws OceanusException on error
517      */
518     public void setWebSite(final char[] pWebSite) throws OceanusException {
519         setInfoSetValue(MoneyWiseAccountInfoClass.WEBSITE, pWebSite);
520     }
521 
522     /**
523      * Set a new CustNo.
524      *
525      * @param pCustNo the new custNo
526      * @throws OceanusException on error
527      */
528     public void setCustNo(final char[] pCustNo) throws OceanusException {
529         setInfoSetValue(MoneyWiseAccountInfoClass.CUSTOMERNO, pCustNo);
530     }
531 
532     /**
533      * Set a new UserId.
534      *
535      * @param pUserId the new userId
536      * @throws OceanusException on error
537      */
538     public void setUserId(final char[] pUserId) throws OceanusException {
539         setInfoSetValue(MoneyWiseAccountInfoClass.USERID, pUserId);
540     }
541 
542     /**
543      * Set a new Password.
544      *
545      * @param pPassword the new password
546      * @throws OceanusException on error
547      */
548     public void setPassword(final char[] pPassword) throws OceanusException {
549         setInfoSetValue(MoneyWiseAccountInfoClass.PASSWORD, pPassword);
550     }
551 
552     /**
553      * Set a new SortCode.
554      *
555      * @param pSortCode the new sort code
556      * @throws OceanusException on error
557      */
558     public void setSortCode(final char[] pSortCode) throws OceanusException {
559         setInfoSetValue(MoneyWiseAccountInfoClass.SORTCODE, pSortCode);
560     }
561 
562     /**
563      * Set a new Account.
564      *
565      * @param pAccount the new account
566      * @throws OceanusException on error
567      */
568     public void setAccount(final char[] pAccount) throws OceanusException {
569         setInfoSetValue(MoneyWiseAccountInfoClass.ACCOUNT, pAccount);
570     }
571 
572     /**
573      * Set a new Reference.
574      *
575      * @param pReference the new reference
576      * @throws OceanusException on error
577      */
578     public void setReference(final char[] pReference) throws OceanusException {
579         setInfoSetValue(MoneyWiseAccountInfoClass.REFERENCE, pReference);
580     }
581 
582     /**
583      * Set a new Notes.
584      *
585      * @param pNotes the new notes
586      * @throws OceanusException on error
587      */
588     public void setNotes(final char[] pNotes) throws OceanusException {
589         setInfoSetValue(MoneyWiseAccountInfoClass.NOTES, pNotes);
590     }
591 
592     /**
593      * Set an infoSet value.
594      *
595      * @param pInfoClass the class of info to set
596      * @param pValue     the value to set
597      * @throws OceanusException on error
598      */
599     private void setInfoSetValue(final MoneyWiseAccountInfoClass pInfoClass,
600                                  final Object pValue) throws OceanusException {
601         /* Reject if there is no infoSet */
602         if (!hasInfoSet) {
603             throw new MoneyWiseLogicException(ERROR_BADINFOSET);
604         }
605 
606         /* Set the value */
607         theInfoSet.setValue(pInfoClass, pValue);
608     }
609 
610     @Override
611     public void touchUnderlyingItems() {
612         /* touch the payee type */
613         getCategory().touchItem(this);
614 
615         /* touch infoSet items */
616         theInfoSet.touchUnderlyingItems();
617     }
618 
619     @Override
620     public void touchOnUpdate() {
621         /* Reset touches from update set */
622         clearTouches(MoneyWiseBasicDataType.CASHINFO);
623         clearTouches(MoneyWiseBasicDataType.SECURITY);
624         clearTouches(MoneyWiseBasicDataType.DEPOSIT);
625         clearTouches(MoneyWiseBasicDataType.LOAN);
626         clearTouches(MoneyWiseBasicDataType.PORTFOLIO);
627     }
628 
629     /**
630      * Update base payee from an edited payee.
631      *
632      * @param pPayee the edited payee
633      * @return whether changes have been made
634      */
635     @Override
636     public boolean applyChanges(final PrometheusDataItem pPayee) {
637         /* Can only update from a payee */
638         if (!(pPayee instanceof MoneyWisePayee myPayee)) {
639             return false;
640         }
641 
642         /* Store the current detail into history */
643         pushHistory();
644 
645         /* Apply basic changes */
646         applyBasicChanges(myPayee);
647 
648         /* Check for changes */
649         return checkForHistory();
650     }
651 
652     @Override
653     public void adjustMapForItem() {
654         final MoneyWisePayeeList myList = getList();
655         final MoneyWisePayeeDataMap myMap = myList.getDataMap();
656         myMap.adjustForItem(this);
657     }
658 
659     @Override
660     public void removeItem() {
661         theInfoSet.removeItems();
662         super.removeItem();
663     }
664 
665     /**
666      * The Payee List class.
667      */
668     public static class MoneyWisePayeeList
669             extends MoneyWiseAssetBaseList<MoneyWisePayee> {
670         /**
671          * Report fields.
672          */
673         private static final MetisFieldSet<MoneyWisePayeeList> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWisePayeeList.class);
674 
675         /**
676          * The PayeeInfo List.
677          */
678         private MoneyWisePayeeInfoList theInfoList;
679 
680         /**
681          * The AccountInfoType list.
682          */
683         private MoneyWiseAccountInfoTypeList theInfoTypeList;
684 
685         /**
686          * Construct an empty CORE Payee list.
687          *
688          * @param pData the DataSet for the list
689          */
690         public MoneyWisePayeeList(final PrometheusDataSet pData) {
691             super(pData, MoneyWisePayee.class, MoneyWiseBasicDataType.PAYEE);
692         }
693 
694         /**
695          * Constructor for a cloned List.
696          *
697          * @param pSource the source List
698          */
699         protected MoneyWisePayeeList(final MoneyWisePayeeList pSource) {
700             super(pSource);
701         }
702 
703         @Override
704         public MetisFieldSet<MoneyWisePayeeList> getDataFieldSet() {
705             return FIELD_DEFS;
706         }
707 
708         @Override
709         public String listName() {
710             return LIST_NAME;
711         }
712 
713         @Override
714         public MetisFieldSetDef getItemFields() {
715             return MoneyWisePayee.FIELD_DEFS;
716         }
717 
718         @Override
719         public MoneyWisePayeeDataMap getDataMap() {
720             return (MoneyWisePayeeDataMap) super.getDataMap();
721         }
722 
723         /**
724          * Obtain the payeeInfoList.
725          *
726          * @return the payee info list
727          */
728         public MoneyWisePayeeInfoList getPayeeInfo() {
729             if (theInfoList == null) {
730                 theInfoList = getDataSet().getDataList(MoneyWiseBasicDataType.PAYEEINFO, MoneyWisePayeeInfoList.class);
731             }
732             return theInfoList;
733         }
734 
735         /**
736          * Obtain the accountInfoTypeList.
737          *
738          * @return the account info type list
739          */
740         public MoneyWiseAccountInfoTypeList getActInfoTypes() {
741             if (theInfoTypeList == null) {
742                 theInfoTypeList = getEditSet() == null
743                         ? getDataSet().getDataList(MoneyWiseStaticDataType.ACCOUNTINFOTYPE, MoneyWiseAccountInfoTypeList.class)
744                         : getEditSet().getDataList(MoneyWiseStaticDataType.ACCOUNTINFOTYPE, MoneyWiseAccountInfoTypeList.class);
745             }
746             return theInfoTypeList;
747         }
748 
749         @Override
750         protected MoneyWisePayeeList getEmptyList(final PrometheusListStyle pStyle) {
751             final MoneyWisePayeeList myList = new MoneyWisePayeeList(this);
752             myList.setStyle(pStyle);
753             return myList;
754         }
755 
756         /**
757          * Derive Edit list.
758          *
759          * @param pEditSet the editSet
760          * @return the edit list
761          * @throws OceanusException on error
762          */
763         public MoneyWisePayeeList deriveEditList(final PrometheusEditSet pEditSet) throws OceanusException {
764             /* Build an empty List */
765             final MoneyWisePayeeList myList = getEmptyList(PrometheusListStyle.EDIT);
766             myList.ensureMap();
767             pEditSet.setEditEntryList(MoneyWiseBasicDataType.PAYEE, myList);
768             myList.getValidator().setEditSet(pEditSet);
769 
770             /* Store InfoType list */
771             myList.theInfoTypeList = pEditSet.getDataList(MoneyWiseStaticDataType.ACCOUNTINFOTYPE, MoneyWiseAccountInfoTypeList.class);
772 
773             /* Create info List */
774             final MoneyWisePayeeInfoList myPayeeInfo = getPayeeInfo();
775             myList.theInfoList = myPayeeInfo.getEmptyList(PrometheusListStyle.EDIT);
776             pEditSet.setEditEntryList(MoneyWiseBasicDataType.PAYEEINFO, myList.theInfoList);
777 
778             /* Store the editSet */
779             myList.setEditSet(pEditSet);
780 
781             /* Loop through the payees */
782             final Iterator<MoneyWisePayee> myIterator = iterator();
783             while (myIterator.hasNext()) {
784                 final MoneyWisePayee myCurr = myIterator.next();
785 
786                 /* Ignore deleted payees */
787                 if (myCurr.isDeleted()) {
788                     continue;
789                 }
790 
791                 /* Build the new linked payee and add it to the list */
792                 final MoneyWisePayee myPayee = new MoneyWisePayee(myList, myCurr);
793                 myList.add(myPayee);
794                 myPayee.resolveEditSetLinks();
795 
796                 /* Adjust the map */
797                 myPayee.adjustMapForItem();
798             }
799 
800             /* Return the list */
801             return myList;
802         }
803 
804         @Override
805         public MoneyWisePayee findItemByName(final String pName) {
806             /* Look up in map */
807             return getDataMap().findItemByName(pName);
808         }
809 
810         @Override
811         public boolean checkAvailableName(final String pName) {
812             /* check availability */
813             return findItemByName(pName) == null;
814         }
815 
816         @Override
817         public boolean validNameCount(final String pName) {
818             /* check availability in map */
819             return getDataMap().validNameCount(pName);
820         }
821 
822         /**
823          * Add a new item to the core list.
824          *
825          * @param pPayee item
826          * @return the newly added item
827          */
828         @Override
829         public MoneyWisePayee addCopyItem(final PrometheusDataItem pPayee) {
830             /* Can only clone a Payee */
831             if (!(pPayee instanceof MoneyWisePayee)) {
832                 throw new UnsupportedOperationException();
833             }
834 
835             final MoneyWisePayee myPayee = new MoneyWisePayee(this, (MoneyWisePayee) pPayee);
836             add(myPayee);
837             return myPayee;
838         }
839 
840         /**
841          * Add a new item to the edit list.
842          *
843          * @return the new item
844          */
845         @Override
846         public MoneyWisePayee addNewItem() {
847             final MoneyWisePayee myPayee = new MoneyWisePayee(this);
848             add(myPayee);
849             return myPayee;
850         }
851 
852         /**
853          * Obtain the first payee for the specified class.
854          *
855          * @param pClass the payee class
856          * @return the payee
857          */
858         public MoneyWisePayee getSingularClass(final MoneyWisePayeeClass pClass) {
859             /* Lookup in the map */
860             return getDataMap().findSingularItem(pClass);
861         }
862 
863         @Override
864         public MoneyWisePayee addValuesItem(final PrometheusDataValues pValues) throws OceanusException {
865             /* Create the payee */
866             final MoneyWisePayee myPayee = new MoneyWisePayee(this, pValues);
867 
868             /* Check that this PayeeId has not been previously added */
869             if (!isIdUnique(myPayee.getIndexedId())) {
870                 myPayee.addError(ERROR_DUPLICATE, MetisDataResource.DATA_ID);
871                 throw new MoneyWiseDataException(myPayee, ERROR_VALIDATION);
872             }
873 
874             /* Add to the list */
875             add(myPayee);
876 
877             /* Loop through the info items */
878             if (pValues.hasInfoItems()) {
879                 /* Loop through the items */
880                 final Iterator<PrometheusInfoItem> myIterator = pValues.infoIterator();
881                 while (myIterator.hasNext()) {
882                     final PrometheusInfoItem myItem = myIterator.next();
883 
884                     /* Build info */
885                     final PrometheusDataValues myValues = myItem.getValues(myPayee);
886                     theInfoList.addValuesItem(myValues);
887                 }
888             }
889 
890             /* Return it */
891             return myPayee;
892         }
893 
894         @Override
895         protected MoneyWisePayeeDataMap allocateDataMap() {
896             return new MoneyWisePayeeDataMap();
897         }
898 
899         @Override
900         public void postProcessOnLoad() throws OceanusException {
901             /* Resolve links and sort the data */
902             super.resolveDataSetLinks();
903             reSort();
904         }
905     }
906 
907     /**
908      * The dataMap class.
909      */
910     public static class MoneyWisePayeeDataMap
911             implements PrometheusDataMapItem, MetisFieldItem {
912         /**
913          * Report fields.
914          */
915         private static final MetisFieldSet<MoneyWisePayeeDataMap> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWisePayeeDataMap.class);
916 
917         /*
918          * UnderlyingMap Field Id.
919          */
920         static {
921             FIELD_DEFS.declareLocalField(MoneyWiseBasicResource.MONEYWISEDATA_MAP_UNDERLYING, MoneyWisePayeeDataMap::getUnderlyingMap);
922             FIELD_DEFS.declareLocalField(MoneyWiseBasicResource.MONEYWISEDATA_MAP_SINGULARMAP, MoneyWisePayeeDataMap::getPayeeMap);
923             FIELD_DEFS.declareLocalField(MoneyWiseBasicResource.MONEYWISEDATA_MAP_SINGULARCOUNTS, MoneyWisePayeeDataMap::getPayeeCountMap);
924         }
925 
926         /**
927          * The assetMap.
928          */
929         private final MoneyWiseAssetDataMap theUnderlyingMap;
930 
931         /**
932          * Map of category counts.
933          */
934         private final Map<Integer, Integer> thePayeeCountMap;
935 
936         /**
937          * Map of singular categories.
938          */
939         private final Map<Integer, MoneyWisePayee> thePayeeMap;
940 
941         /**
942          * Constructor.
943          */
944         public MoneyWisePayeeDataMap() {
945             /* Create underlying map */
946             theUnderlyingMap = new MoneyWiseAssetDataMap();
947 
948             /* Create the maps */
949             thePayeeCountMap = new HashMap<>();
950             thePayeeMap = new HashMap<>();
951         }
952 
953         @Override
954         public MetisFieldSet<MoneyWisePayeeDataMap> getDataFieldSet() {
955             return FIELD_DEFS;
956         }
957 
958         @Override
959         public String formatObject(final OceanusDataFormatter pFormatter) {
960             return FIELD_DEFS.getName();
961         }
962 
963         /**
964          * Obtain the underlying map.
965          *
966          * @return the underlying map
967          */
968         public MoneyWiseAssetDataMap getUnderlyingMap() {
969             return theUnderlyingMap;
970         }
971 
972         /**
973          * Obtain the underlying map.
974          *
975          * @return the underlying map
976          */
977         private Map<Integer, MoneyWisePayee> getPayeeMap() {
978             return thePayeeMap;
979         }
980 
981         /**
982          * Obtain the underlying map.
983          *
984          * @return the underlying map
985          */
986         private Map<Integer, Integer> getPayeeCountMap() {
987             return thePayeeCountMap;
988         }
989 
990         @Override
991         public void resetMap() {
992             theUnderlyingMap.resetMap();
993             thePayeeCountMap.clear();
994             thePayeeMap.clear();
995         }
996 
997         @Override
998         public void adjustForItem(final PrometheusDataItem pItem) {
999             /* Access item */
1000             final MoneyWisePayee myItem = (MoneyWisePayee) pItem;
1001 
1002             /* If the class is singular */
1003             final MoneyWisePayeeClass myClass = myItem.getCategoryClass();
1004             if (myClass.isSingular()) {
1005                 /* Adjust category count */
1006                 final Integer myId = myClass.getClassId();
1007                 final Integer myCount = thePayeeCountMap.get(myId);
1008                 if (myCount == null) {
1009                     thePayeeCountMap.put(myId, PrometheusDataInstanceMap.ONE);
1010                 } else {
1011                     thePayeeCountMap.put(myId, myCount + 1);
1012                 }
1013 
1014                 /* Adjust payee map */
1015                 thePayeeMap.put(myId, myItem);
1016             }
1017 
1018             /* Adjust name count */
1019             theUnderlyingMap.adjustForItem(pItem);
1020         }
1021 
1022         /**
1023          * find item by name.
1024          *
1025          * @param pName the name to look up
1026          * @return the matching item
1027          */
1028         public MoneyWisePayee findItemByName(final String pName) {
1029             final MoneyWiseAssetBase myAsset = theUnderlyingMap.findAssetByName(pName);
1030             return myAsset instanceof MoneyWisePayee myPayee
1031                     ? myPayee
1032                     : null;
1033         }
1034 
1035         /**
1036          * Check validity of name.
1037          *
1038          * @param pName the name to look up
1039          * @return true/false
1040          */
1041         public boolean validNameCount(final String pName) {
1042             return theUnderlyingMap.validKeyCount(pName);
1043         }
1044 
1045         /**
1046          * Check availability of name.
1047          *
1048          * @param pName the key to look up
1049          * @return true/false
1050          */
1051         public boolean availableName(final String pName) {
1052             return theUnderlyingMap.availableKey(pName);
1053         }
1054 
1055         /**
1056          * find singular item.
1057          *
1058          * @param pClass the class to look up
1059          * @return the matching item
1060          */
1061         public MoneyWisePayee findSingularItem(final MoneyWisePayeeClass pClass) {
1062             return thePayeeMap.get(pClass.getClassId());
1063         }
1064 
1065         /**
1066          * Check validity of singular count.
1067          *
1068          * @param pClass the class to look up
1069          * @return true/false
1070          */
1071         public boolean validSingularCount(final MoneyWisePayeeClass pClass) {
1072             final Integer myResult = thePayeeCountMap.get(pClass.getClassId());
1073             return PrometheusDataInstanceMap.ONE.equals(myResult);
1074         }
1075     }
1076 }