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.MetisDataResource;
21  import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
22  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseTransCategory.MoneyWiseTransCategoryList;
23  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseAccountInfoClass;
24  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseAccountInfoType;
25  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseAccountInfoType.MoneyWiseAccountInfoTypeList;
26  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseStaticDataType;
27  import io.github.tonywasher.joceanus.moneywise.exc.MoneyWiseDataException;
28  import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
29  import io.github.tonywasher.joceanus.prometheus.data.PrometheusData.PrometheusDataSetCtl;
30  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataInfoClass;
31  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataInfoItem;
32  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataInfoSet;
33  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataItem;
34  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataList;
35  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataResource;
36  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataSet;
37  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataValues;
38  import io.github.tonywasher.joceanus.prometheus.data.PrometheusEncrypted.PrometheusDataInfoSetItemCtl;
39  import io.github.tonywasher.joceanus.prometheus.data.PrometheusListStyle;
40  import io.github.tonywasher.joceanus.prometheus.data.PrometheusStaticDataItem;
41  import io.github.tonywasher.joceanus.prometheus.views.PrometheusEditSet;
42  
43  import java.util.Iterator;
44  
45  /**
46   * Representation of an information extension of a cash account.
47   *
48   * @author Tony Washer
49   */
50  public class MoneyWiseCashInfo
51          extends PrometheusDataInfoItem {
52      /**
53       * Object name.
54       */
55      public static final String OBJECT_NAME = MoneyWiseBasicDataType.CASHINFO.getItemName();
56  
57      /**
58       * List name.
59       */
60      public static final String LIST_NAME = MoneyWiseBasicDataType.CASHINFO.getListName();
61  
62      /**
63       * Report fields.
64       */
65      private static final MetisFieldSet<MoneyWiseCashInfo> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseCashInfo.class);
66  
67      /**
68       * Copy Constructor.
69       *
70       * @param pList the list
71       * @param pInfo The Info to copy
72       */
73      protected MoneyWiseCashInfo(final MoneyWiseCashInfoList pList,
74                                  final MoneyWiseCashInfo pInfo) {
75          /* Set standard values */
76          super(pList, pInfo);
77      }
78  
79      /**
80       * Edit Constructor.
81       *
82       * @param pList the list
83       * @param pCash the cash
84       * @param pType the type
85       */
86      private MoneyWiseCashInfo(final MoneyWiseCashInfoList pList,
87                                final PrometheusDataItem pCash,
88                                final MoneyWiseAccountInfoType pType) {
89          /* Initialise the item */
90          super(pList);
91          setNextDataKeySet();
92  
93          /* Record the Detail */
94          setValueInfoType(pType);
95          setValueOwner(pCash);
96      }
97  
98      /**
99       * Values constructor.
100      *
101      * @param pList   the List to add to
102      * @param pValues the values constructor
103      * @throws OceanusException on error
104      */
105     private MoneyWiseCashInfo(final MoneyWiseCashInfoList pList,
106                               final PrometheusDataValues pValues) throws OceanusException {
107         /* Initialise the item */
108         super(pList, pValues);
109 
110         /* Protect against exceptions */
111         try {
112             /* Resolve links */
113             resolveDataLink(PrometheusDataResource.DATAINFO_TYPE, MoneyWiseStaticDataType.ACCOUNTINFOTYPE);
114             resolveDataLink(PrometheusDataResource.DATAINFO_OWNER, MoneyWiseBasicDataType.CASH);
115 
116             /* Set the value */
117             setValue(pValues.getValue(PrometheusDataResource.DATAINFO_VALUE));
118 
119             /* Resolve any link value */
120             resolveLink(null);
121 
122             /* Access the CashInfoSet and register this data */
123             getInfoSet().registerInfo(this);
124 
125         } catch (OceanusException e) {
126             /* Pass on exception */
127             throw new MoneyWiseDataException(this, ERROR_CREATEITEM, e);
128         }
129     }
130 
131     @Override
132     public MetisFieldSetDef getDataFieldSet() {
133         return FIELD_DEFS;
134     }
135 
136     @Override
137     public MoneyWiseAccountInfoType getInfoType() {
138         return getValues().getValue(PrometheusDataResource.DATAINFO_TYPE, MoneyWiseAccountInfoType.class);
139     }
140 
141     @Override
142     public MoneyWiseAccountInfoClass getInfoClass() {
143         return getInfoType().getInfoClass();
144     }
145 
146     @Override
147     public PrometheusDataItem getOwner() {
148         return getValues().getValue(PrometheusDataResource.DATAINFO_OWNER, PrometheusDataItem.class);
149     }
150 
151     /**
152      * Obtain Payee.
153      *
154      * @return the Payee
155      */
156     public MoneyWisePayee getPayee() {
157         return getValues().getValue(PrometheusDataResource.DATAINFO_LINK, MoneyWisePayee.class);
158     }
159 
160     /**
161      * Obtain EventCategory.
162      *
163      * @return the EventCategory
164      */
165     public MoneyWiseTransCategory getEventCategory() {
166         return getValues().getValue(PrometheusDataResource.DATAINFO_LINK, MoneyWiseTransCategory.class);
167     }
168 
169     @Override
170     public String getLinkName() {
171         final PrometheusDataItem myItem = getLink();
172         if (myItem instanceof MoneyWisePayee myPayee) {
173             return myPayee.getName();
174         }
175         if (myItem instanceof MoneyWiseTransCategory myCat) {
176             return myCat.getName();
177         }
178         return null;
179     }
180 
181     @Override
182     public MoneyWiseCashInfo getBase() {
183         return (MoneyWiseCashInfo) super.getBase();
184     }
185 
186     @Override
187     public MoneyWiseCashInfoList getList() {
188         return (MoneyWiseCashInfoList) super.getList();
189     }
190 
191     /**
192      * Obtain the InfoSet.
193      *
194      * @return the infoSet
195      */
196     @SuppressWarnings("unchecked")
197     private PrometheusDataInfoSet<MoneyWiseCashInfo> getInfoSet() {
198         return (PrometheusDataInfoSet<MoneyWiseCashInfo>) ((PrometheusDataInfoSetItemCtl<MoneyWiseCashInfo>) getOwner()).getInfoSet();
199     }
200 
201     @Override
202     public void deRegister() {
203         /* Access the CashInfoSet and register this value */
204         getInfoSet().deRegisterInfo(this);
205     }
206 
207     @Override
208     public void resolveDataSetLinks() throws OceanusException {
209         /* Update the Encryption details */
210         super.resolveDataSetLinks();
211 
212         /* Resolve data links */
213         resolveDataLink(PrometheusDataResource.DATAINFO_TYPE, MoneyWiseStaticDataType.ACCOUNTINFOTYPE);
214         resolveDataLink(PrometheusDataResource.DATAINFO_OWNER, MoneyWiseBasicDataType.CASH);
215 
216         /* Resolve any link value */
217         resolveLink(null);
218 
219         /* Access the CashInfoSet and register this data */
220         getInfoSet().registerInfo(this);
221     }
222 
223     /**
224      * resolve editSet links.
225      *
226      * @param pEditSet the edit set
227      * @throws OceanusException on error
228      */
229     public void resolveEditSetLinks(final PrometheusEditSet pEditSet) throws OceanusException {
230         /* Resolve data links */
231         resolveDataLink(PrometheusDataResource.DATAINFO_TYPE, pEditSet.getDataList(MoneyWiseStaticDataType.ACCOUNTINFOTYPE, MoneyWiseAccountInfoTypeList.class));
232         resolveDataLink(PrometheusDataResource.DATAINFO_OWNER, pEditSet.getDataList(MoneyWiseBasicDataType.CASH, PrometheusDataList.class));
233 
234         /* Resolve any link value */
235         resolveLink(pEditSet);
236     }
237 
238     /**
239      * Resolve link reference.
240      *
241      * @param pEditSet the edit set
242      * @throws OceanusException on error
243      */
244     private void resolveLink(final PrometheusEditSet pEditSet) throws OceanusException {
245         /* If we have a link */
246         final MoneyWiseAccountInfoType myType = getInfoType();
247         if (myType.isLink()) {
248             /* Access data */
249             final PrometheusDataSetCtl myData = getDataSet();
250             final Object myLinkId = getValues().getValue(PrometheusDataResource.DATAINFO_VALUE);
251 
252             /* Switch on link type */
253             switch (myType.getInfoClass()) {
254                 case AUTOPAYEE:
255                     resolveDataLink(PrometheusDataResource.DATAINFO_LINK, pEditSet == null
256                             ? myData.getDataList(MoneyWiseBasicDataType.PAYEE, PrometheusDataList.class)
257                             : pEditSet.getDataList(MoneyWiseBasicDataType.PAYEE, PrometheusDataList.class));
258                     if (myLinkId == null) {
259                         setValueValue(getPayee().getIndexedId());
260                     }
261                     break;
262                 case AUTOEXPENSE:
263                     resolveDataLink(PrometheusDataResource.DATAINFO_LINK, pEditSet == null
264                             ? myData.getDataList(MoneyWiseBasicDataType.TRANSCATEGORY, MoneyWiseTransCategoryList.class)
265                             : pEditSet.getDataList(MoneyWiseBasicDataType.TRANSCATEGORY, MoneyWiseTransCategoryList.class));
266                     if (myLinkId == null) {
267                         setValueValue(getEventCategory().getIndexedId());
268                     }
269                     break;
270                 default:
271                     break;
272             }
273         }
274     }
275 
276     /**
277      * Update loanInfo from a loanInfo extract.
278      *
279      * @param pInfo the changed loanInfo
280      * @return whether changes have been made
281      */
282     @Override
283     public boolean applyChanges(final PrometheusDataItem pInfo) {
284         /* Can only update from CashInfo */
285         if (!(pInfo instanceof MoneyWiseCashInfo myInfo)) {
286             return false;
287         }
288 
289         /* Store the current detail into history */
290         pushHistory();
291 
292         /* Update the value if required */
293         if (!MetisDataDifference.isEqual(getField(), myInfo.getField())) {
294             setValueValue(myInfo.getField());
295             if (getInfoType().isLink()) {
296                 setValueLink(myInfo.getLink());
297             }
298         }
299 
300         /* Check for changes */
301         return checkForHistory();
302     }
303 
304     @Override
305     public void touchUnderlyingItems() {
306         /* touch info class */
307         super.touchUnderlyingItems();
308 
309         /* Switch on info class */
310         switch (getInfoClass()) {
311             case AUTOPAYEE:
312                 getPayee().touchItem(this);
313                 break;
314             case AUTOEXPENSE:
315                 getEventCategory().touchItem(this);
316                 break;
317             default:
318                 break;
319         }
320     }
321 
322     @Override
323     public void touchOnUpdate() {
324         /* Switch on info class */
325         switch (getInfoClass()) {
326             case AUTOPAYEE:
327                 getPayee().touchItem(this);
328                 break;
329             default:
330                 break;
331         }
332     }
333 
334     /**
335      * CashInfoList.
336      */
337     public static class MoneyWiseCashInfoList
338             extends PrometheusDataInfoList<MoneyWiseCashInfo> {
339         /**
340          * Report fields.
341          */
342         private static final MetisFieldSet<MoneyWiseCashInfoList> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseCashInfoList.class);
343 
344         /**
345          * Construct an empty CORE account list.
346          *
347          * @param pData the DataSet for the list
348          */
349         protected MoneyWiseCashInfoList(final PrometheusDataSet pData) {
350             super(MoneyWiseCashInfo.class, pData, MoneyWiseBasicDataType.CASHINFO, PrometheusListStyle.CORE);
351         }
352 
353         /**
354          * Constructor for a cloned List.
355          *
356          * @param pSource the source List
357          */
358         private MoneyWiseCashInfoList(final MoneyWiseCashInfoList pSource) {
359             super(pSource);
360         }
361 
362         @Override
363         public MetisFieldSet<MoneyWiseCashInfoList> getDataFieldSet() {
364             return FIELD_DEFS;
365         }
366 
367         @Override
368         public String listName() {
369             return LIST_NAME;
370         }
371 
372         @Override
373         public MetisFieldSetDef getItemFields() {
374             return MoneyWiseCashInfo.FIELD_DEFS;
375         }
376 
377         /**
378          * Set base list for Edit InfoList.
379          *
380          * @param pBase the base list
381          */
382         protected void setBase(final MoneyWiseCashInfoList pBase) {
383             /* Set the style and base */
384             setStyle(PrometheusListStyle.EDIT);
385             super.setBase(pBase);
386         }
387 
388         @Override
389         protected MoneyWiseCashInfoList getEmptyList(final PrometheusListStyle pStyle) {
390             final MoneyWiseCashInfoList myList = new MoneyWiseCashInfoList(this);
391             myList.setStyle(pStyle);
392             return myList;
393         }
394 
395         @Override
396         public MoneyWiseCashInfo addCopyItem(final PrometheusDataItem pItem) {
397             /* Can only clone a CashInfo */
398             if (!(pItem instanceof MoneyWiseCashInfo)) {
399                 throw new UnsupportedOperationException();
400             }
401 
402             final MoneyWiseCashInfo myInfo = new MoneyWiseCashInfo(this, (MoneyWiseCashInfo) pItem);
403             add(myInfo);
404             return myInfo;
405         }
406 
407         @Override
408         public MoneyWiseCashInfo addNewItem() {
409             throw new UnsupportedOperationException();
410         }
411 
412         @Override
413         protected MoneyWiseCashInfo addNewItem(final PrometheusDataItem pOwner,
414                                                final PrometheusStaticDataItem pInfoType) {
415             /* Allocate the new entry and add to list */
416             final MoneyWiseCashInfo myInfo = new MoneyWiseCashInfo(this, pOwner, (MoneyWiseAccountInfoType) pInfoType);
417             add(myInfo);
418 
419             /* return it */
420             return myInfo;
421         }
422 
423         @Override
424         public void addInfoItem(final Integer pId,
425                                 final PrometheusDataItem pCash,
426                                 final PrometheusDataInfoClass pInfoClass,
427                                 final Object pValue) throws OceanusException {
428             /* Ignore item if it is null */
429             if (pValue == null) {
430                 return;
431             }
432 
433             /* Access the accountInfoTypes */
434             final MoneyWiseAccountInfoTypeList myActInfos
435                     = getDataSet().getDataList(MoneyWiseStaticDataType.ACCOUNTINFOTYPE, MoneyWiseAccountInfoTypeList.class);
436 
437             /* Look up the Info Type */
438             final MoneyWiseAccountInfoType myInfoType = myActInfos.findItemByClass(pInfoClass);
439             if (myInfoType == null) {
440                 throw new MoneyWiseDataException(pCash, ERROR_BADINFOCLASS + " [" + pInfoClass + "]");
441             }
442 
443             /* Create the values */
444             final PrometheusDataValues myValues = new PrometheusDataValues(OBJECT_NAME);
445             myValues.addValue(MetisDataResource.DATA_ID, pId);
446             myValues.addValue(PrometheusDataResource.DATAINFO_TYPE, myInfoType);
447             myValues.addValue(PrometheusDataResource.DATAINFO_OWNER, pCash);
448             myValues.addValue(PrometheusDataResource.DATAINFO_VALUE, pValue);
449 
450             /* Create a new Cash Info */
451             final MoneyWiseCashInfo myInfo = new MoneyWiseCashInfo(this, myValues);
452 
453             /* Check that this InfoTypeId has not been previously added */
454             if (!isIdUnique(pId)) {
455                 myInfo.addError(ERROR_DUPLICATE, MetisDataResource.DATA_ID);
456                 throw new MoneyWiseDataException(myInfo, ERROR_VALIDATION);
457             }
458 
459             /* Add the Info to the list */
460             add(myInfo);
461         }
462 
463         @Override
464         public MoneyWiseCashInfo addValuesItem(final PrometheusDataValues pValues) throws OceanusException {
465             /* Create the info */
466             final MoneyWiseCashInfo myInfo = new MoneyWiseCashInfo(this, pValues);
467 
468             /* Check that this InfoId has not been previously added */
469             if (!isIdUnique(myInfo.getIndexedId())) {
470                 myInfo.addError(ERROR_DUPLICATE, MetisDataResource.DATA_ID);
471                 throw new MoneyWiseDataException(myInfo, ERROR_VALIDATION);
472             }
473 
474             /* Add to the list */
475             add(myInfo);
476 
477             /* Return it */
478             return myInfo;
479         }
480 
481         /**
482          * Resolve ValueLinks.
483          *
484          * @throws OceanusException on error
485          */
486         public void resolveValueLinks() throws OceanusException {
487             /* Loop through the Info items */
488             final Iterator<MoneyWiseCashInfo> myIterator = iterator();
489             while (myIterator.hasNext()) {
490                 final MoneyWiseCashInfo myCurr = myIterator.next();
491 
492                 /* If this is an infoItem */
493                 if (myCurr.getInfoType().isLink()) {
494                     /* Resolve the link */
495                     myCurr.resolveLink(null);
496                 }
497             }
498         }
499 
500         @Override
501         public void postProcessOnLoad() throws OceanusException {
502             /* Validate the CashInfo */
503             validateOnLoad();
504 
505             /* Map and Validate the Cash */
506             final PrometheusDataList<?> myCash
507                     = getDataSet().getDataList(MoneyWiseBasicDataType.CASH, PrometheusDataList.class);
508             myCash.mapData();
509             myCash.validateOnLoad();
510         }
511     }
512 }