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