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.oceanus.date.OceanusDate;
21  import io.github.tonywasher.joceanus.oceanus.date.OceanusDateFormatter;
22  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusRate;
23  import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
24  import io.github.tonywasher.joceanus.metis.data.MetisDataDifference;
25  import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataFieldId;
26  import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataList;
27  import io.github.tonywasher.joceanus.metis.data.MetisDataResource;
28  import io.github.tonywasher.joceanus.metis.field.MetisFieldItem;
29  import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
30  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseDeposit.MoneyWiseDepositList;
31  import io.github.tonywasher.joceanus.moneywise.exc.MoneyWiseDataException;
32  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataInstanceMap;
33  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataItem;
34  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataMapItem;
35  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataValues;
36  import io.github.tonywasher.joceanus.prometheus.data.PrometheusEncryptedDataItem;
37  import io.github.tonywasher.joceanus.prometheus.data.PrometheusEncryptedFieldSet;
38  import io.github.tonywasher.joceanus.prometheus.data.PrometheusEncryptedPair;
39  import io.github.tonywasher.joceanus.prometheus.data.PrometheusEncryptedValues;
40  import io.github.tonywasher.joceanus.prometheus.views.PrometheusEditSet;
41  
42  import java.util.ArrayList;
43  import java.util.HashMap;
44  import java.util.Iterator;
45  import java.util.List;
46  import java.util.ListIterator;
47  import java.util.Map;
48  
49  /**
50   * DepositRate data type.
51   *
52   * @author Tony Washer
53   */
54  public class MoneyWiseDepositRate
55          extends PrometheusEncryptedDataItem {
56      /**
57       * Object name.
58       */
59      public static final String OBJECT_NAME = MoneyWiseBasicDataType.DEPOSITRATE.getItemName();
60  
61      /**
62       * List name.
63       */
64      public static final String LIST_NAME = MoneyWiseBasicDataType.DEPOSITRATE.getListName();
65  
66      /**
67       * Report fields.
68       */
69      private static final PrometheusEncryptedFieldSet<MoneyWiseDepositRate> FIELD_DEFS = PrometheusEncryptedFieldSet.newEncryptedFieldSet(MoneyWiseDepositRate.class);
70  
71      /*
72       * FieldIds.
73       */
74      static {
75          FIELD_DEFS.declareLinkField(MoneyWiseBasicDataType.DEPOSIT);
76          FIELD_DEFS.declareEncryptedRateField(MoneyWiseBasicResource.MONEYWISEDATA_FIELD_RATE);
77          FIELD_DEFS.declareEncryptedRateField(MoneyWiseBasicResource.DEPOSITRATE_BONUS);
78          FIELD_DEFS.declareDateField(MoneyWiseBasicResource.DEPOSITRATE_ENDDATE);
79      }
80  
81      /**
82       * Null Date Error.
83       */
84      public static final String ERROR_NULLDATE = MoneyWiseBasicResource.DEPOSITRATE_ERROR_NULLDATE.getValue();
85  
86      /**
87       * Copy Constructor.
88       *
89       * @param pList   the list
90       * @param pPeriod The Period to copy
91       */
92      protected MoneyWiseDepositRate(final MoneyWiseDepositRateList pList,
93                                     final MoneyWiseDepositRate pPeriod) {
94          /* Set standard values */
95          super(pList, pPeriod);
96      }
97  
98      /**
99       * Edit Constructor.
100      *
101      * @param pList the list
102      */
103     public MoneyWiseDepositRate(final MoneyWiseDepositRateList pList) {
104         super(pList, 0);
105     }
106 
107     /**
108      * Values constructor.
109      *
110      * @param pList   the List to add to
111      * @param pValues the values constructor
112      * @throws OceanusException on error
113      */
114     private MoneyWiseDepositRate(final MoneyWiseDepositRateList pList,
115                                  final PrometheusDataValues pValues) throws OceanusException {
116         /* Initialise the item */
117         super(pList, pValues);
118 
119         /* Access the formatter */
120         final OceanusDataFormatter myFormatter = getDataSet().getDataFormatter();
121 
122         /* Protect against exceptions */
123         try {
124             /* Store the Account */
125             Object myValue = pValues.getValue(MoneyWiseBasicDataType.DEPOSIT);
126             if (myValue instanceof Integer i) {
127                 setValueDeposit(i);
128             } else if (myValue instanceof String s) {
129                 setValueDeposit(s);
130             }
131 
132             /* Store the Rate */
133             myValue = pValues.getValue(MoneyWiseBasicResource.MONEYWISEDATA_FIELD_RATE);
134             if (myValue instanceof OceanusRate r) {
135                 setValueRate(r);
136             } else if (myValue instanceof byte[] ba) {
137                 setValueRate(ba);
138             } else if (myValue instanceof String myString) {
139                 setValueRate(myString);
140                 setValueRate(myFormatter.parseValue(myString, OceanusRate.class));
141             }
142 
143             /* Store the Bonus */
144             myValue = pValues.getValue(MoneyWiseBasicResource.DEPOSITRATE_BONUS);
145             if (myValue instanceof OceanusRate r) {
146                 setValueBonus(r);
147             } else if (myValue instanceof byte[] ba) {
148                 setValueBonus(ba);
149             } else if (myValue instanceof String myString) {
150                 setValueBonus(myString);
151                 setValueBonus(myFormatter.parseValue(myString, OceanusRate.class));
152             }
153 
154             /* Store the EndDate */
155             myValue = pValues.getValue(MoneyWiseBasicResource.DEPOSITRATE_ENDDATE);
156             if (myValue instanceof OceanusDate d) {
157                 setValueEndDate(d);
158             } else if (myValue instanceof String s) {
159                 final OceanusDateFormatter myParser = myFormatter.getDateFormatter();
160                 setValueEndDate(myParser.parseDate(s));
161             }
162 
163             /* Catch Exceptions */
164         } catch (IllegalArgumentException
165                  | OceanusException e) {
166             /* Pass on exception */
167             throw new MoneyWiseDataException(this, ERROR_CREATEITEM, e);
168         }
169     }
170 
171     @Override
172     public MetisFieldSetDef getDataFieldSet() {
173         return FIELD_DEFS;
174     }
175 
176     @Override
177     public boolean includeXmlField(final MetisDataFieldId pField) {
178         /* Determine whether fields should be included */
179         if (MoneyWiseBasicDataType.DEPOSIT.equals(pField)) {
180             return true;
181         }
182         if (MoneyWiseBasicResource.MONEYWISEDATA_FIELD_RATE.equals(pField)) {
183             return true;
184         }
185         if (MoneyWiseBasicResource.DEPOSITRATE_BONUS.equals(pField)) {
186             return getBonus() != null;
187         }
188         if (MoneyWiseBasicResource.DEPOSITRATE_ENDDATE.equals(pField)) {
189             return getEndDate() != null;
190         }
191 
192         /* Pass call on */
193         return super.includeXmlField(pField);
194     }
195 
196     @Override
197     public String formatObject(final OceanusDataFormatter pFormatter) {
198         return toString();
199     }
200 
201     @Override
202     public String toString() {
203         /* Access Key Values */
204         final PrometheusEncryptedValues myValues = getValues();
205         final Object myDeposit = myValues.getValue(MoneyWiseBasicDataType.DEPOSIT);
206         final Object myRate = myValues.getValue(MoneyWiseBasicResource.MONEYWISEDATA_FIELD_RATE);
207         final Object myEndDate = myValues.getValue(MoneyWiseBasicResource.DEPOSITRATE_ENDDATE);
208 
209         /* Access formatter */
210         final OceanusDataFormatter myFormatter = getDataSet().getDataFormatter();
211 
212         /* Create string builder */
213         final StringBuilder myBuilder = new StringBuilder();
214         myBuilder.append(myFormatter.formatObject(myDeposit));
215         myBuilder.append('@');
216         myBuilder.append(myFormatter.formatObject(myRate));
217         if (myEndDate != null) {
218             myBuilder.append("->");
219             myBuilder.append(myFormatter.formatObject(myEndDate));
220         }
221 
222         /* return it */
223         return myBuilder.toString();
224     }
225 
226     /**
227      * Obtain Rate.
228      *
229      * @return the rate
230      */
231     public OceanusRate getRate() {
232         return getValues().getValue(MoneyWiseBasicResource.MONEYWISEDATA_FIELD_RATE, OceanusRate.class);
233     }
234 
235     /**
236      * Obtain Encrypted rate.
237      *
238      * @return the Bytes
239      */
240     public byte[] getRateBytes() {
241         return getValues().getEncryptedBytes(MoneyWiseBasicResource.MONEYWISEDATA_FIELD_RATE);
242     }
243 
244     /**
245      * Obtain Encrypted Rate Field.
246      *
247      * @return the Field
248      */
249     private PrometheusEncryptedPair getRateField() {
250         return getValues().getEncryptedPair(MoneyWiseBasicResource.MONEYWISEDATA_FIELD_RATE);
251     }
252 
253     /**
254      * Obtain Bonus.
255      *
256      * @return the bonus rate
257      */
258     public OceanusRate getBonus() {
259         return getValues().getValue(MoneyWiseBasicResource.DEPOSITRATE_BONUS, OceanusRate.class);
260     }
261 
262     /**
263      * Obtain Encrypted bonus.
264      *
265      * @return the Bytes
266      */
267     public byte[] getBonusBytes() {
268         return getValues().getEncryptedBytes(MoneyWiseBasicResource.DEPOSITRATE_BONUS);
269     }
270 
271     /**
272      * Obtain Encrypted Rate Field.
273      *
274      * @return the Field
275      */
276     private PrometheusEncryptedPair getBonusField() {
277         return getValues().getEncryptedPair(MoneyWiseBasicResource.DEPOSITRATE_BONUS);
278     }
279 
280     /**
281      * Obtain date.
282      *
283      * @return the date
284      */
285     public OceanusDate getDate() {
286         return getEndDate();
287     }
288 
289     /**
290      * Obtain End Date.
291      *
292      * @return the End Date
293      */
294     public OceanusDate getEndDate() {
295         return getValues().getValue(MoneyWiseBasicResource.DEPOSITRATE_ENDDATE, OceanusDate.class);
296     }
297 
298     /**
299      * Obtain Deposit.
300      *
301      * @return the deposit
302      */
303     public MoneyWiseDeposit getDeposit() {
304         return getValues().getValue(MoneyWiseBasicDataType.DEPOSIT, MoneyWiseDeposit.class);
305     }
306 
307     /**
308      * Obtain DepositId.
309      *
310      * @return the depositId
311      */
312     public Integer getDepositId() {
313         final MoneyWiseDeposit myDeposit = getDeposit();
314         return myDeposit == null
315                 ? null
316                 : myDeposit.getIndexedId();
317     }
318 
319     /**
320      * Obtain DepositName.
321      *
322      * @return the depositName
323      */
324     public String getDepositName() {
325         final MoneyWiseDeposit myDeposit = getDeposit();
326         return myDeposit == null
327                 ? null
328                 : myDeposit.getName();
329     }
330 
331     /**
332      * Set the account.
333      *
334      * @param pValue the account
335      */
336     private void setValueDeposit(final MoneyWiseDeposit pValue) {
337         getValues().setUncheckedValue(MoneyWiseBasicDataType.DEPOSIT, pValue);
338     }
339 
340     /**
341      * Set the deposit id.
342      *
343      * @param pId the deposit id
344      */
345     private void setValueDeposit(final Integer pId) {
346         getValues().setUncheckedValue(MoneyWiseBasicDataType.DEPOSIT, pId);
347     }
348 
349     /**
350      * Set the deposit name.
351      *
352      * @param pName the deposit name
353      */
354     private void setValueDeposit(final String pName) {
355         getValues().setUncheckedValue(MoneyWiseBasicDataType.DEPOSIT, pName);
356     }
357 
358     /**
359      * Set the rate.
360      *
361      * @param pValue the rate
362      * @throws OceanusException on error
363      */
364     private void setValueRate(final OceanusRate pValue) throws OceanusException {
365         setEncryptedValue(MoneyWiseBasicResource.MONEYWISEDATA_FIELD_RATE, pValue);
366     }
367 
368     /**
369      * Set the rate.
370      *
371      * @param pBytes the encrypted rate
372      * @throws OceanusException on error
373      */
374     private void setValueRate(final byte[] pBytes) throws OceanusException {
375         setEncryptedValue(MoneyWiseBasicResource.MONEYWISEDATA_FIELD_RATE, pBytes, OceanusRate.class);
376     }
377 
378     /**
379      * Set the rate.
380      *
381      * @param pValue the rate
382      */
383     private void setValueRate(final PrometheusEncryptedPair pValue) {
384         getValues().setUncheckedValue(MoneyWiseBasicResource.MONEYWISEDATA_FIELD_RATE, pValue);
385     }
386 
387     /**
388      * Set the rate.
389      *
390      * @param pValue the rate
391      */
392     private void setValueRate(final String pValue) {
393         getValues().setUncheckedValue(MoneyWiseBasicResource.MONEYWISEDATA_FIELD_RATE, pValue);
394     }
395 
396     /**
397      * Set the bonus rate.
398      *
399      * @param pValue the bonus rate
400      * @throws OceanusException on error
401      */
402     private void setValueBonus(final OceanusRate pValue) throws OceanusException {
403         setEncryptedValue(MoneyWiseBasicResource.DEPOSITRATE_BONUS, pValue);
404     }
405 
406     /**
407      * Set the encrypted bonus.
408      *
409      * @param pBytes the encrypted bonus
410      * @throws OceanusException on error
411      */
412     private void setValueBonus(final byte[] pBytes) throws OceanusException {
413         setEncryptedValue(MoneyWiseBasicResource.DEPOSITRATE_BONUS, pBytes, OceanusRate.class);
414     }
415 
416     /**
417      * Set the bonus.
418      *
419      * @param pValue the bonus
420      */
421     private void setValueBonus(final PrometheusEncryptedPair pValue) {
422         getValues().setUncheckedValue(MoneyWiseBasicResource.DEPOSITRATE_BONUS, pValue);
423     }
424 
425     /**
426      * Set the bonus.
427      *
428      * @param pValue the bonus
429      */
430     private void setValueBonus(final String pValue) {
431         getValues().setUncheckedValue(MoneyWiseBasicResource.DEPOSITRATE_BONUS, pValue);
432     }
433 
434     /**
435      * Set the end date.
436      *
437      * @param pValue the date
438      */
439     private void setValueEndDate(final OceanusDate pValue) {
440         getValues().setUncheckedValue(MoneyWiseBasicResource.DEPOSITRATE_ENDDATE, pValue);
441     }
442 
443     @Override
444     public MoneyWiseDataSet getDataSet() {
445         return (MoneyWiseDataSet) super.getDataSet();
446     }
447 
448     @Override
449     public MoneyWiseDepositRate getBase() {
450         return (MoneyWiseDepositRate) super.getBase();
451     }
452 
453     @Override
454     public MoneyWiseDepositRateList getList() {
455         return (MoneyWiseDepositRateList) super.getList();
456     }
457 
458     /**
459      * Compare this rate to another to establish sort order.
460      *
461      * @param pThat The Rate to compare to
462      * @return (-1,0,1) depending of whether this object is before, equal, or after the passed
463      * object in the sort order
464      */
465     @Override
466     public int compareValues(final PrometheusDataItem pThat) {
467         /* Access as DepositRate */
468         final MoneyWiseDepositRate myThat = (MoneyWiseDepositRate) pThat;
469 
470         /* If header settings differ */
471         if (isHeader() != pThat.isHeader()) {
472             return isHeader()
473                     ? -1
474                     : 1;
475         }
476 
477         /* If the date differs */
478         final int iDiff = MetisDataDifference.compareObject(getDate(), myThat.getDate());
479         if (iDiff != 0) {
480             /* Sort in reverse date order !! */
481             return -iDiff;
482         }
483 
484         /* Compare the deposits */
485         return getDeposit().compareTo(myThat.getDeposit());
486     }
487 
488     @Override
489     public void resolveDataSetLinks() throws OceanusException {
490         /* Update the Encryption details */
491         super.resolveDataSetLinks();
492 
493         /* Resolve data links */
494         final MoneyWiseDataSet myData = getDataSet();
495         resolveDataLink(MoneyWiseBasicDataType.DEPOSIT, myData.getDeposits());
496     }
497 
498     /**
499      * Resolve links in an updateSet.
500      *
501      * @param pEditSet the edit Set
502      * @throws OceanusException on error
503      */
504     private void resolveEditSetLinks(final PrometheusEditSet pEditSet) throws OceanusException {
505         /* Resolve parent within list */
506         final MoneyWiseDepositList myDeposits = pEditSet.getDataList(MoneyWiseBasicDataType.DEPOSIT, MoneyWiseDepositList.class);
507         resolveDataLink(MoneyWiseBasicDataType.DEPOSIT, myDeposits);
508     }
509 
510     /**
511      * Set the deposit.
512      *
513      * @param pValue the deposit
514      */
515     public void setDeposit(final MoneyWiseDeposit pValue) {
516         setValueDeposit(pValue);
517     }
518 
519     /**
520      * Set a new rate.
521      *
522      * @param pRate the rate
523      * @throws OceanusException on error
524      */
525     public void setRate(final OceanusRate pRate) throws OceanusException {
526         setValueRate(pRate);
527     }
528 
529     /**
530      * Set a new bonus.
531      *
532      * @param pBonus the rate
533      * @throws OceanusException on error
534      */
535     public void setBonus(final OceanusRate pBonus) throws OceanusException {
536         setValueBonus(pBonus);
537     }
538 
539     /**
540      * Set a new date.
541      *
542      * @param pDate the new date
543      */
544     public void setEndDate(final OceanusDate pDate) {
545         setValueEndDate(pDate == null
546                 ? null
547                 : new OceanusDate(pDate));
548     }
549 
550     @Override
551     public void touchUnderlyingItems() {
552         /* touch the underlying deposit */
553         getDeposit().touchItem(this);
554     }
555 
556     @Override
557     public void touchOnUpdate() {
558         /* Touch deposit */
559         getDeposit().touchItem(this);
560     }
561 
562     /**
563      * Update Rate from a Rate extract.
564      *
565      * @param pRate the updated item
566      * @return whether changes have been made
567      */
568     @Override
569     public boolean applyChanges(final PrometheusDataItem pRate) {
570         /* Can only update from an DepositRate */
571         if (!(pRate instanceof MoneyWiseDepositRate)) {
572             return false;
573         }
574         final MoneyWiseDepositRate myRate = (MoneyWiseDepositRate) pRate;
575 
576         /* Store the current detail into history */
577         pushHistory();
578 
579         /* Update the rate if required */
580         if (!MetisDataDifference.isEqual(getRate(), myRate.getRate())) {
581             setValueRate(myRate.getRateField());
582         }
583 
584         /* Update the bonus if required */
585         if (!MetisDataDifference.isEqual(getBonus(), myRate.getBonus())) {
586             setValueBonus(myRate.getBonusField());
587         }
588 
589         /* Update the date if required */
590         if (!MetisDataDifference.isEqual(getEndDate(), myRate.getEndDate())) {
591             setValueEndDate(myRate.getEndDate());
592         }
593 
594         /* Check for changes */
595         return checkForHistory();
596     }
597 
598     @Override
599     public void adjustMapForItem() {
600         final MoneyWiseDepositRateList myList = getList();
601         final MoneyWiseDepositRateDataMap myMap = myList.getDataMap();
602         myMap.adjustForItem(this);
603     }
604 
605     /**
606      * List class.
607      */
608     public static class MoneyWiseDepositRateList
609             extends PrometheusEncryptedList<MoneyWiseDepositRate> {
610         /**
611          * Report fields.
612          */
613         private static final MetisFieldSet<MoneyWiseDepositRateList> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseDepositRateList.class);
614 
615         /**
616          * Construct an empty CORE rate list.
617          *
618          * @param pData the DataSet for the list
619          */
620         protected MoneyWiseDepositRateList(final MoneyWiseDataSet pData) {
621             super(MoneyWiseDepositRate.class, pData, MoneyWiseBasicDataType.DEPOSITRATE);
622         }
623 
624         /**
625          * Constructor for a cloned List.
626          *
627          * @param pSource the source List
628          */
629         private MoneyWiseDepositRateList(final MoneyWiseDepositRateList pSource) {
630             super(pSource);
631         }
632 
633         @Override
634         protected MoneyWiseDepositRateList getEmptyList(final PrometheusListStyle pStyle) {
635             final MoneyWiseDepositRateList myList = new MoneyWiseDepositRateList(this);
636             myList.setStyle(pStyle);
637             return myList;
638         }
639 
640         @Override
641         public MetisFieldSet<MoneyWiseDepositRateList> getDataFieldSet() {
642             return FIELD_DEFS;
643         }
644 
645         @Override
646         public MetisFieldSetDef getItemFields() {
647             return MoneyWiseDepositRate.FIELD_DEFS;
648         }
649 
650         @Override
651         public String listName() {
652             return LIST_NAME;
653         }
654 
655         @Override
656         public MoneyWiseDataSet getDataSet() {
657             return (MoneyWiseDataSet) super.getDataSet();
658         }
659 
660         @Override
661         public MoneyWiseDepositRateDataMap getDataMap() {
662             return (MoneyWiseDepositRateDataMap) super.getDataMap();
663         }
664 
665         /**
666          * Construct an edit extract of a Rate list.
667          *
668          * @param pEditSet the editSet
669          * @return the edit list
670          * @throws OceanusException on error
671          */
672         public MoneyWiseDepositRateList deriveEditList(final PrometheusEditSet pEditSet) throws OceanusException {
673             /* Build an empty List */
674             final MoneyWiseDepositRateList myList = getEmptyList(PrometheusListStyle.EDIT);
675             myList.ensureMap();
676             pEditSet.setEditEntryList(MoneyWiseBasicDataType.DEPOSITRATE, myList);
677 
678             /* Loop through the list */
679             final Iterator<MoneyWiseDepositRate> myIterator = iterator();
680             while (myIterator.hasNext()) {
681                 final MoneyWiseDepositRate myCurr = myIterator.next();
682 
683                 /* Copy the item */
684                 final MoneyWiseDepositRate myItem = new MoneyWiseDepositRate(myList, myCurr);
685                 myItem.resolveEditSetLinks(pEditSet);
686                 myList.add(myItem);
687 
688                 /* Adjust the map */
689                 myItem.adjustMapForItem();
690             }
691 
692             /* Return the List */
693             return myList;
694         }
695 
696         /**
697          * Add a new item to the core list.
698          *
699          * @param pRate item
700          * @return the newly added item
701          */
702         @Override
703         public MoneyWiseDepositRate addCopyItem(final PrometheusDataItem pRate) {
704             /* Can only clone a DepositRate */
705             if (!(pRate instanceof MoneyWiseDepositRate)) {
706                 throw new UnsupportedOperationException();
707             }
708 
709             final MoneyWiseDepositRate myRate = new MoneyWiseDepositRate(this, (MoneyWiseDepositRate) pRate);
710             add(myRate);
711             return myRate;
712         }
713 
714         /**
715          * Add a new item to the edit list.
716          *
717          * @return the new item
718          */
719         @Override
720         public MoneyWiseDepositRate addNewItem() {
721             final MoneyWiseDepositRate myRate = new MoneyWiseDepositRate(this);
722             add(myRate);
723             return myRate;
724         }
725 
726         @Override
727         public MoneyWiseDepositRate addValuesItem(final PrometheusDataValues pValues) throws OceanusException {
728             /* Create the rate */
729             final MoneyWiseDepositRate myRate = new MoneyWiseDepositRate(this, pValues);
730 
731             /* Check that this RateId has not been previously added */
732             if (!isIdUnique(myRate.getIndexedId())) {
733                 myRate.addError(ERROR_DUPLICATE, MetisDataResource.DATA_ID);
734                 throw new MoneyWiseDataException(myRate, ERROR_VALIDATION);
735             }
736 
737             /* Add to the list */
738             add(myRate);
739 
740             /* Return it */
741             return myRate;
742         }
743 
744         @Override
745         protected MoneyWiseDepositRateDataMap allocateDataMap() {
746             return new MoneyWiseDepositRateDataMap();
747         }
748     }
749 
750     /**
751      * The dataMap class.
752      */
753     public static class MoneyWiseDepositRateDataMap
754             implements PrometheusDataMapItem, MetisFieldItem {
755         /**
756          * Report fields.
757          */
758         private static final MetisFieldSet<MoneyWiseDepositRateDataMap> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseDepositRateDataMap.class);
759 
760         /*
761          * UnderlyingMap Field Id.
762          */
763         static {
764             FIELD_DEFS.declareLocalField(MoneyWiseBasicResource.MONEYWISEDATA_MAP_MAPOFMAPS, MoneyWiseDepositRateDataMap::getMapOfMaps);
765             FIELD_DEFS.declareLocalField(MoneyWiseBasicResource.DEPOSITRATE_MAP_MAPOFRATES, MoneyWiseDepositRateDataMap::getMapOfRates);
766         }
767 
768         /**
769          * Map of Maps.
770          */
771         private final Map<MoneyWiseDeposit, Map<OceanusDate, Integer>> theMapOfMaps;
772 
773         /**
774          * Map of Rates.
775          */
776         private final Map<MoneyWiseDeposit, MoneyWiseRateList> theMapOfRates;
777 
778         /**
779          * Constructor.
780          */
781         public MoneyWiseDepositRateDataMap() {
782             /* Create the maps */
783             theMapOfMaps = new HashMap<>();
784             theMapOfRates = new HashMap<>();
785         }
786 
787         @Override
788         public MetisFieldSet<MoneyWiseDepositRateDataMap> getDataFieldSet() {
789             return FIELD_DEFS;
790         }
791 
792         @Override
793         public String formatObject(final OceanusDataFormatter pFormatter) {
794             return FIELD_DEFS.getName();
795         }
796 
797         /**
798          * Obtain mapOfMaps.
799          *
800          * @return the map
801          */
802         private Map<MoneyWiseDeposit, Map<OceanusDate, Integer>> getMapOfMaps() {
803             return theMapOfMaps;
804         }
805 
806         /**
807          * Obtain mapOfRates.
808          *
809          * @return the map
810          */
811         private Map<MoneyWiseDeposit, MoneyWiseRateList> getMapOfRates() {
812             return theMapOfRates;
813         }
814 
815         @Override
816         public void resetMap() {
817             theMapOfMaps.clear();
818             theMapOfRates.clear();
819         }
820 
821         @Override
822         public void adjustForItem(final PrometheusDataItem pItem) {
823             /* Access the Deposit Id */
824             final MoneyWiseDepositRate myItem = (MoneyWiseDepositRate) pItem;
825             final MoneyWiseDeposit myDeposit = myItem.getDeposit();
826             if (myDeposit == null) {
827                 return;
828             }
829 
830             /* Access the map */
831             final Map<OceanusDate, Integer> myMap = theMapOfMaps.computeIfAbsent(myDeposit, m -> new HashMap<>());
832 
833             /* Adjust rate count */
834             final OceanusDate myDate = myItem.getEndDate();
835             final Integer myCount = myMap.get(myDate);
836             if (myCount == null) {
837                 myMap.put(myDate, PrometheusDataInstanceMap.ONE);
838             } else {
839                 myMap.put(myDate, myCount + 1);
840             }
841 
842             /* Access the list */
843             final MoneyWiseRateList myList = theMapOfRates.computeIfAbsent(myDeposit, MoneyWiseRateList::new);
844 
845             /* Add element to the list */
846             myList.add(myItem);
847         }
848 
849         /**
850          * Check validity of Rate.
851          *
852          * @param pItem the rate
853          * @return true/false
854          */
855         public boolean validRateCount(final MoneyWiseDepositRate pItem) {
856             /* Access the Details */
857             final MoneyWiseDeposit myDeposit = pItem.getDeposit();
858             final OceanusDate myDate = pItem.getEndDate();
859 
860             /* Access the map */
861             final Map<OceanusDate, Integer> myMap = theMapOfMaps.get(myDeposit);
862             if (myMap != null) {
863                 final Integer myResult = myMap.get(myDate);
864                 return PrometheusDataInstanceMap.ONE.equals(myResult);
865             }
866             return false;
867         }
868 
869         /**
870          * Check availability of date for a deposit.
871          *
872          * @param pDeposit the deposit
873          * @param pDate    the key to look up
874          * @return true/false
875          */
876         public boolean availableDate(final MoneyWiseDeposit pDeposit,
877                                      final OceanusDate pDate) {
878             /* Access the map */
879             final Map<OceanusDate, Integer> myMap = theMapOfMaps.get(pDeposit);
880             return myMap == null
881                     || myMap.get(pDate) == null;
882         }
883 
884         /**
885          * Obtain rate for date.
886          *
887          * @param pDeposit the deposit
888          * @param pDate    the date
889          * @return the latest rate for the date.
890          */
891         public MoneyWiseDepositRate getRateForDate(final MoneyWiseDeposit pDeposit,
892                                                    final OceanusDate pDate) {
893             /* Access list for deposit */
894             final MoneyWiseRateList myList = theMapOfRates.get(pDeposit);
895             if (myList != null) {
896                 /* Loop through the rates */
897                 final ListIterator<MoneyWiseDepositRate> myIterator = myList.listIterator(myList.size());
898                 while (myIterator.hasPrevious()) {
899                     final MoneyWiseDepositRate myCurr = myIterator.previous();
900 
901                     /* Access the date */
902                     final OceanusDate myDate = myCurr.getDate();
903 
904                     /* break loop if we have the correct record */
905                     if (myDate == null
906                             || myDate.compareTo(pDate) >= 0) {
907                         return myCurr;
908                     }
909                 }
910             }
911 
912             /* return null */
913             return null;
914         }
915 
916         /**
917          * Rate List class.
918          */
919         private static final class MoneyWiseRateList
920                 implements MetisFieldItem, MetisDataList<MoneyWiseDepositRate> {
921             /**
922              * Report fields.
923              */
924             private static final MetisFieldSet<MoneyWiseRateList> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseRateList.class);
925 
926             /*
927              * UnderlyingMap Field Id.
928              */
929             static {
930                 FIELD_DEFS.declareLocalField(MetisDataResource.LIST_SIZE, MoneyWiseRateList::size);
931             }
932 
933             /**
934              * The list.
935              */
936             private final List<MoneyWiseDepositRate> theList;
937 
938             /**
939              * The deposit.
940              */
941             private final MoneyWiseDeposit theDeposit;
942 
943             /**
944              * Constructor.
945              *
946              * @param pDeposit the deposit
947              */
948             private MoneyWiseRateList(final MoneyWiseDeposit pDeposit) {
949                 theDeposit = pDeposit;
950                 theList = new ArrayList<>();
951             }
952 
953             @Override
954             public MetisFieldSet<MoneyWiseRateList> getDataFieldSet() {
955                 return FIELD_DEFS;
956             }
957 
958             @Override
959             public String formatObject(final OceanusDataFormatter pFormatter) {
960                 return theDeposit.formatObject(pFormatter)
961                         + "("
962                         + size()
963                         + ")";
964             }
965 
966             @Override
967             public String toString() {
968                 return theDeposit.toString()
969                         + "("
970                         + size()
971                         + ")";
972             }
973 
974             @Override
975             public List<MoneyWiseDepositRate> getUnderlyingList() {
976                 return theList;
977             }
978         }
979     }
980 }