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