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