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.MetisDataItem.MetisDataFieldId;
21  import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
22  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseDataValidator.MoneyWiseDataValidatorAutoCorrect;
23  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseDataValidator.MoneyWiseDataValidatorDefaults;
24  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseTax.MoneyWiseTaxCredit;
25  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseTax.MoneyWiseTaxFactory;
26  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseAssetCategory;
27  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseCurrency;
28  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseStaticDataType;
29  import io.github.tonywasher.joceanus.moneywise.exc.MoneyWiseDataException;
30  import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
31  import io.github.tonywasher.joceanus.oceanus.date.OceanusDate;
32  import io.github.tonywasher.joceanus.oceanus.date.OceanusDateRange;
33  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusMoney;
34  import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
35  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataInstanceMap;
36  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataItem;
37  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataList;
38  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataResource;
39  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataSet;
40  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataValues;
41  import io.github.tonywasher.joceanus.prometheus.data.PrometheusEncryptedDataItem;
42  import io.github.tonywasher.joceanus.prometheus.data.PrometheusEncryptedFieldSet;
43  import io.github.tonywasher.joceanus.prometheus.data.PrometheusEncryptedPair;
44  import io.github.tonywasher.joceanus.prometheus.data.PrometheusEncryptedValues;
45  import io.github.tonywasher.joceanus.prometheus.data.PrometheusListStyle;
46  import io.github.tonywasher.joceanus.prometheus.views.PrometheusEditSet;
47  
48  import java.util.Currency;
49  import java.util.Iterator;
50  
51  /**
52   * Class representing an account that can be part of a transaction.
53   */
54  public abstract class MoneyWiseAssetBase
55          extends PrometheusEncryptedDataItem
56          implements MoneyWiseTransAsset {
57      /**
58       * Validator for accounts.
59       *
60       * @param <T> the item type
61       */
62      public interface MoneyWiseDataValidatorAccount<T extends MoneyWiseAssetBase>
63              extends MoneyWiseDataValidatorDefaults<T>, MoneyWiseDataValidatorAutoCorrect<T> {
64      }
65  
66      /**
67       * dataSet Control interface.
68       */
69      public interface MoneyWiseDataSetCtl {
70          /**
71           * Obtain default currency.
72           *
73           * @return the default currency
74           */
75          MoneyWiseCurrency getReportingCurrency();
76  
77          /**
78           * Obtain Date range.
79           *
80           * @return the Date Range
81           */
82          OceanusDateRange getDateRange();
83  
84          /**
85           * Obtain Tax Factory.
86           *
87           * @return the taxFactory
88           */
89          MoneyWiseTaxFactory getTaxFactory();
90      }
91  
92      /**
93       * Report fields.
94       */
95      private static final PrometheusEncryptedFieldSet<MoneyWiseAssetBase> FIELD_DEFS = PrometheusEncryptedFieldSet.newEncryptedFieldSet(MoneyWiseAssetBase.class);
96  
97      /*
98       * FieldIds.
99       */
100     static {
101         FIELD_DEFS.declareEncryptedStringField(PrometheusDataResource.DATAITEM_FIELD_NAME, NAMELEN);
102         FIELD_DEFS.declareEncryptedStringField(PrometheusDataResource.DATAITEM_FIELD_DESC, DESCLEN);
103         FIELD_DEFS.declareLinkField(MoneyWiseBasicResource.CATEGORY_NAME);
104         FIELD_DEFS.declareLinkField(MoneyWiseBasicResource.ASSET_PARENT);
105         FIELD_DEFS.declareLinkField(MoneyWiseStaticDataType.CURRENCY);
106         FIELD_DEFS.declareBooleanField(MoneyWiseBasicResource.ASSET_CLOSED);
107         FIELD_DEFS.declareLocalField(MoneyWiseBasicResource.ASSET_CLOSEDATE, MoneyWiseAssetBase::getCloseDate);
108         FIELD_DEFS.declareLocalField(MoneyWiseBasicResource.ASSET_FIRSTEVENT, MoneyWiseAssetBase::getEarliest);
109         FIELD_DEFS.declareLocalField(MoneyWiseBasicResource.ASSET_LASTEVENT, MoneyWiseAssetBase::getLatest);
110         FIELD_DEFS.declareLocalField(MoneyWiseBasicResource.ASSET_RELEVANT, MoneyWiseAssetBase::isRelevant);
111     }
112 
113     /**
114      * Bad InfoSet Error Text.
115      */
116     protected static final String ERROR_BADINFOSET = PrometheusDataResource.DATAINFOSET_ERROR_BADSET.getValue();
117 
118     /**
119      * Close Date.
120      */
121     private OceanusDate theCloseDate;
122 
123     /**
124      * Earliest Transaction.
125      */
126     private MoneyWiseAssetTouch theEarliest;
127 
128     /**
129      * Latest Transaction.
130      */
131     private MoneyWiseAssetTouch theLatest;
132 
133     /**
134      * Is this relevant?
135      */
136     private boolean isRelevant;
137 
138     /**
139      * Copy Constructor.
140      *
141      * @param pList  the list
142      * @param pAsset The Asset to copy
143      */
144     protected MoneyWiseAssetBase(final MoneyWiseAssetBaseList<?> pList,
145                                  final MoneyWiseAssetBase pAsset) {
146         /* Set standard values */
147         super(pList, pAsset);
148 
149         /* If we are creating an edit copy from core */
150         final PrometheusListStyle myBaseStyle = pAsset.getList().getStyle();
151         if (pList.getStyle() == PrometheusListStyle.EDIT
152                 && myBaseStyle == PrometheusListStyle.CORE) {
153             /* Update underlying flags */
154             theCloseDate = pAsset.getCloseDate();
155             theEarliest = pAsset.getEarliest();
156             theLatest = pAsset.getLatest();
157             isRelevant = pAsset.isRelevant();
158         }
159     }
160 
161     /**
162      * Values constructor.
163      *
164      * @param pList   the List to add to
165      * @param pValues the values constructor
166      * @throws OceanusException on error
167      */
168     protected MoneyWiseAssetBase(final MoneyWiseAssetBaseList<?> pList,
169                                  final PrometheusDataValues pValues) throws OceanusException {
170         /* Initialise the item */
171         super(pList, pValues);
172 
173         /* Access formatter */
174         final OceanusDataFormatter myFormatter = getDataSet().getDataFormatter();
175 
176         /* Protect against exceptions */
177         try {
178             /* Store the name */
179             Object myValue = pValues.getValue(PrometheusDataResource.DATAITEM_FIELD_NAME);
180             if (myValue instanceof String s) {
181                 setValueName(s);
182             } else if (myValue instanceof byte[] ba) {
183                 setValueName(ba);
184             }
185 
186             /* Store the Description */
187             myValue = pValues.getValue(PrometheusDataResource.DATAITEM_FIELD_DESC);
188             if (myValue instanceof String s) {
189                 setValueDesc(s);
190             } else if (myValue instanceof byte[] ba) {
191                 setValueDesc(ba);
192             }
193 
194             /* Store the Category */
195             myValue = pValues.getValue(MoneyWiseBasicResource.CATEGORY_NAME);
196             if (myValue instanceof Integer i) {
197                 setValueCategory(i);
198             } else if (myValue instanceof String s) {
199                 setValueCategory(s);
200             }
201 
202             /* Store the Parent */
203             myValue = pValues.getValue(MoneyWiseBasicResource.ASSET_PARENT);
204             if (myValue instanceof Integer i) {
205                 setValueParent(i);
206             } else if (myValue instanceof String s) {
207                 setValueParent(s);
208             }
209 
210             /* Store the Currency */
211             myValue = pValues.getValue(MoneyWiseStaticDataType.CURRENCY);
212             if (myValue instanceof Integer i) {
213                 setValueCurrency(i);
214             } else if (myValue instanceof String s) {
215                 setValueCurrency(s);
216             } else if (myValue instanceof MoneyWiseCurrency c) {
217                 setValueCurrency(c);
218             }
219 
220             /* Store the closed flag */
221             myValue = pValues.getValue(MoneyWiseBasicResource.ASSET_CLOSED);
222             if (myValue instanceof Boolean b) {
223                 setValueClosed(b);
224             } else if (myValue instanceof String s) {
225                 setValueClosed(myFormatter.parseValue(s, Boolean.class));
226             }
227 
228             /* Catch Exceptions */
229         } catch (OceanusException e) {
230             /* Pass on exception */
231             throw new MoneyWiseDataException(this, ERROR_CREATEITEM, e);
232         }
233     }
234 
235     /**
236      * Edit Constructor.
237      *
238      * @param pList the list
239      */
240     protected MoneyWiseAssetBase(final MoneyWiseAssetBaseList<?> pList) {
241         super(pList, 0);
242         setNextDataKeySet();
243     }
244 
245     @Override
246     public String formatObject(final OceanusDataFormatter pFormatter) {
247         return toString();
248     }
249 
250     @Override
251     public String toString() {
252         return getName();
253     }
254 
255     @Override
256     public boolean includeXmlField(final MetisDataFieldId pField) {
257         /* Determine whether fields should be included */
258         if (PrometheusDataResource.DATAITEM_FIELD_NAME.equals(pField)) {
259             return true;
260         }
261         if (PrometheusDataResource.DATAITEM_FIELD_DESC.equals(pField)) {
262             return getDesc() != null;
263         }
264         if (MoneyWiseBasicResource.ASSET_CLOSED.equals(pField)) {
265             return isClosed();
266         }
267 
268         /* Pass call on */
269         return super.includeXmlField(pField);
270     }
271 
272     /**
273      * Obtain Category.
274      *
275      * @return the category
276      */
277     public abstract MoneyWiseAssetCategory getCategory();
278 
279     @Override
280     public MoneyWiseAssetBase getParent() {
281         return getValues().getValue(MoneyWiseBasicResource.ASSET_PARENT, MoneyWiseAssetBase.class);
282     }
283 
284     /**
285      * Obtain ParentId.
286      *
287      * @return the parentId
288      */
289     public Integer getParentId() {
290         final MoneyWiseAssetBase myParent = getParent();
291         return myParent == null
292                 ? null
293                 : myParent.getIndexedId();
294     }
295 
296     /**
297      * Obtain ParentName.
298      *
299      * @return the parentName
300      */
301     public String getParentName() {
302         final MoneyWiseAssetBase myParent = getParent();
303         return myParent == null
304                 ? null
305                 : myParent.getName();
306     }
307 
308     @Override
309     public MoneyWiseCurrency getAssetCurrency() {
310         return getValues().getValue(MoneyWiseStaticDataType.CURRENCY, MoneyWiseCurrency.class);
311     }
312 
313     /**
314      * Obtain CurrencyId.
315      *
316      * @return the currencyId
317      */
318     public Integer getAssetCurrencyId() {
319         final MoneyWiseCurrency myCurrency = getAssetCurrency();
320         return myCurrency == null ? null : myCurrency.getIndexedId();
321     }
322 
323     /**
324      * Obtain CurrencyName.
325      *
326      * @return the currencyName
327      */
328     public String getAssetCurrencyName() {
329         final MoneyWiseCurrency myCurrency = getAssetCurrency();
330         return myCurrency == null ? null : myCurrency.getName();
331     }
332 
333     /**
334      * Get default Currency.
335      *
336      * @return the default currency.
337      */
338     public MoneyWiseCurrency getDefaultCurrency() {
339         return getDataSet() instanceof MoneyWiseDataSetCtl myReport
340                 ? myReport.getReportingCurrency() : null;
341     }
342 
343     @Override
344     public Currency getCurrency() {
345         MoneyWiseCurrency myCurrency = getAssetCurrency();
346         if (myCurrency == null) {
347             myCurrency = getDefaultCurrency();
348         }
349         return myCurrency == null ? null : myCurrency.getCurrency();
350     }
351 
352     /**
353      * Obtain Opening Balance.
354      *
355      * @return the Opening balance
356      */
357     public OceanusMoney getOpeningBalance() {
358         return null;
359     }
360 
361     @Override
362     public boolean isTaxFree() {
363         return false;
364     }
365 
366     @Override
367     public boolean isGross() {
368         return false;
369     }
370 
371     @Override
372     public boolean isForeign() {
373         return false;
374     }
375 
376     /**
377      * Get the close Date of the account.
378      *
379      * @return the closeDate
380      */
381     public OceanusDate getCloseDate() {
382         return theCloseDate;
383     }
384 
385     /**
386      * Obtain Earliest transaction.
387      *
388      * @return the event
389      */
390     public MoneyWiseAssetTouch getEarliest() {
391         return theEarliest;
392     }
393 
394     /**
395      * Obtain Latest Transaction.
396      *
397      * @return the event
398      */
399     public MoneyWiseAssetTouch getLatest() {
400         return theLatest;
401     }
402 
403     /**
404      * Is the account relevant (i.e. non-closeable)?
405      *
406      * @return true/false
407      */
408     public boolean isRelevant() {
409         return isRelevant;
410     }
411 
412     @Override
413     public boolean isAutoExpense() {
414         return false;
415     }
416 
417     @Override
418     public boolean isShares() {
419         return false;
420     }
421 
422     @Override
423     public boolean isCapital() {
424         return false;
425     }
426 
427     @Override
428     public boolean isHidden() {
429         return false;
430     }
431 
432     @Override
433     public MoneyWiseAssetType getAssetType() {
434         return switch ((MoneyWiseBasicDataType) getItemType()) {
435             case DEPOSIT -> MoneyWiseAssetType.DEPOSIT;
436             case CASH -> MoneyWiseAssetType.CASH;
437             case LOAN -> MoneyWiseAssetType.LOAN;
438             case PORTFOLIO -> MoneyWiseAssetType.PORTFOLIO;
439             case SECURITY -> MoneyWiseAssetType.SECURITY;
440             case PAYEE -> MoneyWiseAssetType.PAYEE;
441             default -> throw new IllegalStateException();
442         };
443     }
444 
445     @Override
446     public String getName() {
447         return getValues().getValue(PrometheusDataResource.DATAITEM_FIELD_NAME, String.class);
448     }
449 
450     /**
451      * Obtain Encrypted name.
452      *
453      * @return the bytes
454      */
455     public byte[] getNameBytes() {
456         return getValues().getEncryptedBytes(PrometheusDataResource.DATAITEM_FIELD_NAME);
457     }
458 
459     /**
460      * Obtain Encrypted Name Field.
461      *
462      * @return the Field
463      */
464     private PrometheusEncryptedPair getNameField() {
465         return getValues().getEncryptedPair(PrometheusDataResource.DATAITEM_FIELD_NAME);
466     }
467 
468     /**
469      * Obtain Description.
470      *
471      * @return the description
472      */
473     public String getDesc() {
474         return getValues().getValue(PrometheusDataResource.DATAITEM_FIELD_DESC, String.class);
475     }
476 
477     /**
478      * Obtain Encrypted description.
479      *
480      * @return the bytes
481      */
482     public byte[] getDescBytes() {
483         return getValues().getEncryptedBytes(PrometheusDataResource.DATAITEM_FIELD_DESC);
484     }
485 
486     /**
487      * Obtain Encrypted Description Field.
488      *
489      * @return the Field
490      */
491     private PrometheusEncryptedPair getDescField() {
492         return getValues().getEncryptedPair(PrometheusDataResource.DATAITEM_FIELD_DESC);
493     }
494 
495     @Override
496     public Boolean isClosed() {
497         return getValues().getValue(MoneyWiseBasicResource.ASSET_CLOSED, Boolean.class);
498     }
499 
500     @Override
501     public boolean isDisabled() {
502         return isClosed();
503     }
504 
505     /**
506      * Set name value.
507      *
508      * @param pValue the value
509      * @throws OceanusException on error
510      */
511     private void setValueName(final String pValue) throws OceanusException {
512         setEncryptedValue(PrometheusDataResource.DATAITEM_FIELD_NAME, pValue);
513     }
514 
515     /**
516      * Set name value.
517      *
518      * @param pBytes the value
519      * @throws OceanusException on error
520      */
521     private void setValueName(final byte[] pBytes) throws OceanusException {
522         setEncryptedValue(PrometheusDataResource.DATAITEM_FIELD_NAME, pBytes, String.class);
523     }
524 
525     /**
526      * Set name value.
527      *
528      * @param pValue the value
529      */
530     private void setValueName(final PrometheusEncryptedPair pValue) {
531         getValues().setUncheckedValue(PrometheusDataResource.DATAITEM_FIELD_NAME, pValue);
532     }
533 
534     /**
535      * Set description value.
536      *
537      * @param pValue the value
538      * @throws OceanusException on error
539      */
540     private void setValueDesc(final String pValue) throws OceanusException {
541         setEncryptedValue(PrometheusDataResource.DATAITEM_FIELD_DESC, pValue);
542     }
543 
544     /**
545      * Set description value.
546      *
547      * @param pBytes the value
548      * @throws OceanusException on error
549      */
550     private void setValueDesc(final byte[] pBytes) throws OceanusException {
551         setEncryptedValue(PrometheusDataResource.DATAITEM_FIELD_DESC, pBytes, String.class);
552     }
553 
554     /**
555      * Set description value.
556      *
557      * @param pValue the value
558      */
559     private void setValueDesc(final PrometheusEncryptedPair pValue) {
560         getValues().setUncheckedValue(PrometheusDataResource.DATAITEM_FIELD_DESC, pValue);
561     }
562 
563     /**
564      * Set category value.
565      *
566      * @param pValue the value
567      */
568     private void setValueCategory(final MoneyWiseAssetCategory pValue) {
569         getValues().setUncheckedValue(MoneyWiseBasicResource.CATEGORY_NAME, pValue);
570     }
571 
572     /**
573      * Set category id.
574      *
575      * @param pValue the value
576      */
577     private void setValueCategory(final Integer pValue) {
578         getValues().setUncheckedValue(MoneyWiseBasicResource.CATEGORY_NAME, pValue);
579     }
580 
581     /**
582      * Set category name.
583      *
584      * @param pValue the value
585      */
586     private void setValueCategory(final String pValue) {
587         getValues().setUncheckedValue(MoneyWiseBasicResource.CATEGORY_NAME, pValue);
588     }
589 
590     /**
591      * Set parent value.
592      *
593      * @param pValue the value
594      */
595     private void setValueParent(final MoneyWiseAssetBase pValue) {
596         getValues().setUncheckedValue(MoneyWiseBasicResource.ASSET_PARENT, pValue);
597     }
598 
599     /**
600      * Set parent id.
601      *
602      * @param pValue the value
603      */
604     private void setValueParent(final Integer pValue) {
605         getValues().setUncheckedValue(MoneyWiseBasicResource.ASSET_PARENT, pValue);
606     }
607 
608     /**
609      * Set parent name.
610      *
611      * @param pValue the value
612      */
613     private void setValueParent(final String pValue) {
614         getValues().setUncheckedValue(MoneyWiseBasicResource.ASSET_PARENT, pValue);
615     }
616 
617     /**
618      * Set currency value.
619      *
620      * @param pValue the value
621      */
622     private void setValueCurrency(final MoneyWiseCurrency pValue) {
623         getValues().setUncheckedValue(MoneyWiseStaticDataType.CURRENCY, pValue);
624     }
625 
626     /**
627      * Set currency id.
628      *
629      * @param pValue the value
630      */
631     private void setValueCurrency(final Integer pValue) {
632         getValues().setUncheckedValue(MoneyWiseStaticDataType.CURRENCY, pValue);
633     }
634 
635     /**
636      * Set currency name.
637      *
638      * @param pValue the value
639      */
640     private void setValueCurrency(final String pValue) {
641         getValues().setUncheckedValue(MoneyWiseStaticDataType.CURRENCY, pValue);
642     }
643 
644     /**
645      * Set closed indication.
646      *
647      * @param pValue the value
648      */
649     private void setValueClosed(final Boolean pValue) {
650         getValues().setUncheckedValue(MoneyWiseBasicResource.ASSET_CLOSED, pValue);
651     }
652 
653     @Override
654     public MoneyWiseAssetBaseList<?> getList() {
655         return (MoneyWiseAssetBaseList<?>) super.getList();
656     }
657 
658     @Override
659     public boolean isLocked() {
660         return isClosed();
661     }
662 
663     /**
664      * Set relevant.
665      */
666     public void setRelevant() {
667         isRelevant = true;
668     }
669 
670     /**
671      * Obtain detailed category.
672      *
673      * @param pCategory current category
674      * @param pYear     the taxYear
675      * @return detailed category
676      */
677     public MoneyWiseTransCategory getDetailedCategory(final MoneyWiseTransCategory pCategory,
678                                                       final MoneyWiseTaxCredit pYear) {
679         /* return the unchanged category */
680         return pCategory;
681     }
682 
683     /**
684      * Adjust closed date.
685      *
686      * @throws OceanusException on error
687      */
688     public void adjustClosed() throws OceanusException {
689         /* Access latest activity date */
690         theCloseDate = theLatest == null ? null : theLatest.getDate();
691     }
692 
693     @Override
694     public void clearActive() {
695         /* Reset flags */
696         theCloseDate = null;
697         theEarliest = null;
698         theLatest = null;
699         isRelevant = false;
700 
701         /* Pass call onwards */
702         super.clearActive();
703     }
704 
705     @Override
706     public void touchItem(final PrometheusDataItem pSource) {
707         /* If we are being touched by a transaction */
708         if (pSource instanceof MoneyWiseAssetTouch myTrans) {
709             /* Record the transaction */
710             if (theEarliest == null) {
711                 theEarliest = myTrans;
712             }
713             theLatest = myTrans;
714 
715             /* if this transaction is not reconciled */
716             if (Boolean.FALSE.equals(myTrans.isReconciled())) {
717                 /* Mark account as relevant */
718                 setRelevant();
719             }
720 
721             /* Touch parent if it exists */
722             final MoneyWiseAssetBase myParent = getParent();
723             if (myParent != null) {
724                 myParent.touchItem(pSource);
725             }
726         }
727 
728         /* If we are being touched by an asset */
729         if (pSource instanceof MoneyWiseAssetBase myAsset
730                 && Boolean.FALSE.equals(myAsset.isClosed())) {
731             setRelevant();
732         }
733 
734 
735         /* Pass call onwards */
736         super.touchItem(pSource);
737     }
738 
739     @Override
740     public void resolveDataSetLinks() throws OceanusException {
741         /* Update the Encryption details */
742         super.resolveDataSetLinks();
743 
744         /* Resolve data links */
745         final PrometheusEncryptedValues myValues = getValues();
746 
747         /* Adjust Closed */
748         final Object myClosed = myValues.getValue(MoneyWiseBasicResource.ASSET_CLOSED);
749         if (myClosed == null) {
750             setValueClosed(Boolean.FALSE);
751         }
752     }
753 
754     /**
755      * resolve EditSet links.
756      *
757      * @throws OceanusException on error
758      */
759     protected abstract void resolveEditSetLinks() throws OceanusException;
760 
761     /**
762      * Resolve late edit Set links.
763      */
764     public void resolveLateEditSetLinks() {
765         /* Access the editSet */
766         final PrometheusEditSet myEditSet = getList().getEditSet();
767 
768         /* Resolve First/LastEvent if required */
769         final PrometheusDataList<?> myTransList = myEditSet.getDataList(MoneyWiseBasicDataType.TRANSACTION, PrometheusDataList.class);
770         if (theEarliest != null) {
771             theEarliest = (MoneyWiseAssetTouch) myTransList.findItemById(theEarliest.getIndexedId());
772         }
773         if (theLatest != null) {
774             theLatest = (MoneyWiseAssetTouch) myTransList.findItemById(theLatest.getIndexedId());
775         }
776     }
777 
778     /**
779      * Set a new name.
780      *
781      * @param pName the new name
782      * @throws OceanusException on error
783      */
784     public void setName(final String pName) throws OceanusException {
785         setValueName(pName);
786     }
787 
788     /**
789      * Set a new description.
790      *
791      * @param pDesc the description
792      * @throws OceanusException on error
793      */
794     public void setDescription(final String pDesc) throws OceanusException {
795         setValueDesc(pDesc);
796     }
797 
798     /**
799      * Set a new category.
800      *
801      * @param pCategory the new category
802      */
803     public void setCategory(final MoneyWiseAssetCategory pCategory) {
804         setValueCategory(pCategory);
805     }
806 
807     /**
808      * Set a new currency.
809      *
810      * @param pCurrency the new currency
811      */
812     public void setAssetCurrency(final MoneyWiseCurrency pCurrency) {
813         setValueCurrency(pCurrency);
814     }
815 
816     /**
817      * Set a new parent.
818      *
819      * @param pParent the parent
820      */
821     public void setParent(final MoneyWiseAssetBase pParent) {
822         setValueParent(pParent);
823     }
824 
825     /**
826      * Set a new closed indication.
827      *
828      * @param isClosed the new closed indication
829      */
830     public void setClosed(final Boolean isClosed) {
831         setValueClosed(isClosed);
832     }
833 
834     /**
835      * Update base asset from an edited asset.
836      *
837      * @param pAsset the edited asset
838      */
839     protected void applyBasicChanges(final MoneyWiseAssetBase pAsset) {
840         /* Update the name if required */
841         if (!MetisDataDifference.isEqual(getName(), pAsset.getName())) {
842             setValueName(pAsset.getNameField());
843         }
844 
845         /* Update the description if required */
846         if (!MetisDataDifference.isEqual(getDesc(), pAsset.getDesc())) {
847             setValueDesc(pAsset.getDescField());
848         }
849 
850         /* Update the category if required */
851         if (!MetisDataDifference.isEqual(getCategory(), pAsset.getCategory())) {
852             setValueCategory(pAsset.getCategory());
853         }
854 
855         /* Update the parent if required */
856         if (!MetisDataDifference.isEqual(getParent(), pAsset.getParent())) {
857             setValueParent(pAsset.getParent());
858         }
859 
860         /* Update the currency if required */
861         if (!MetisDataDifference.isEqual(getAssetCurrency(), pAsset.getAssetCurrency())) {
862             setValueCurrency(pAsset.getAssetCurrency());
863         }
864 
865         /* Update the closed indication if required */
866         if (!MetisDataDifference.isEqual(isClosed(), pAsset.isClosed())) {
867             setValueClosed(pAsset.isClosed());
868         }
869     }
870 
871     /**
872      * The Asset List class.
873      *
874      * @param <T> the dataType
875      */
876     public abstract static class MoneyWiseAssetBaseList<T extends MoneyWiseAssetBase>
877             extends PrometheusEncryptedList<T> {
878         /*
879          * Report fields.
880          */
881         static {
882             MetisFieldSet.newFieldSet(MoneyWiseAssetBaseList.class);
883         }
884 
885         /**
886          * The EditSet.
887          */
888         private PrometheusEditSet theEditSet;
889 
890         /**
891          * Construct an empty CORE list.
892          *
893          * @param pData     the DataSet for the list
894          * @param pClass    the class of the item
895          * @param pItemType the item type
896          */
897         protected MoneyWiseAssetBaseList(final PrometheusDataSet pData,
898                                          final Class<T> pClass,
899                                          final MoneyWiseBasicDataType pItemType) {
900             super(pClass, pData, pItemType, PrometheusListStyle.CORE);
901         }
902 
903         /**
904          * Constructor for a cloned List.
905          *
906          * @param pSource the source List
907          */
908         protected MoneyWiseAssetBaseList(final MoneyWiseAssetBaseList<T> pSource) {
909             super(pSource);
910         }
911 
912         @Override
913         @SuppressWarnings("unchecked")
914         public MoneyWiseDataValidatorAccount<T> getValidator() {
915             return (MoneyWiseDataValidatorAccount<T>) super.getValidator();
916         }
917 
918         /**
919          * Obtain editSet.
920          *
921          * @return the editSet
922          */
923         public PrometheusEditSet getEditSet() {
924             return theEditSet;
925         }
926 
927         /**
928          * Set editSet.
929          *
930          * @param pEditSet the editSet
931          */
932         protected void setEditSet(final PrometheusEditSet pEditSet) {
933             theEditSet = pEditSet;
934         }
935 
936         @Override
937         public abstract T findItemByName(String pName);
938 
939         /**
940          * Check whether a name is available for use.
941          *
942          * @param pName Name of item
943          * @return true/false
944          */
945         public abstract boolean checkAvailableName(String pName);
946 
947         /**
948          * Check whether a name is validly used.
949          *
950          * @param pName Name of item
951          * @return true/false
952          */
953         public abstract boolean validNameCount(String pName);
954 
955         @Override
956         public void postProcessOnLoad() throws OceanusException {
957             /* Resolve links and sort the data */
958             super.resolveDataSetLinks();
959             reSort();
960 
961             /* Map the data */
962             mapData();
963         }
964 
965         /**
966          * Resolve late edit Set links.
967          *
968          * @throws OceanusException on error
969          */
970         public void resolveLateEditSetLinks() throws OceanusException {
971             final Iterator<T> myIterator = iterator();
972             while (myIterator.hasNext()) {
973                 final T myItem = myIterator.next();
974                 myItem.resolveLateEditSetLinks();
975             }
976         }
977     }
978 
979     /**
980      * The dataMap class.
981      */
982     protected static class MoneyWiseAssetDataMap
983             extends PrometheusDataInstanceMap<MoneyWiseAssetBase, String> {
984         @Override
985         public void adjustForItem(final PrometheusDataItem pItem) {
986             /* Access item */
987             final MoneyWiseAssetBase myItem = (MoneyWiseAssetBase) pItem;
988 
989             /* Adjust name count */
990             adjustForItem(myItem, myItem.getName());
991         }
992 
993         /**
994          * find item by name.
995          *
996          * @param pName the name to look up
997          * @return the matching item
998          */
999         public MoneyWiseAssetBase findAssetByName(final String pName) {
1000             return findItemByKey(pName);
1001         }
1002 
1003         /**
1004          * Check validity of name.
1005          *
1006          * @param pName the name to look up
1007          * @return true/false
1008          */
1009         public boolean validNameCount(final String pName) {
1010             return validKeyCount(pName);
1011         }
1012     }
1013 }