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.views;
18  
19  import io.github.tonywasher.joceanus.oceanus.date.OceanusDate;
20  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusRatio;
21  import io.github.tonywasher.joceanus.metis.data.MetisDataEditState;
22  import io.github.tonywasher.joceanus.metis.data.MetisDataState;
23  import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
24  import io.github.tonywasher.joceanus.metis.field.MetisFieldVersionValues;
25  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseBasicDataType;
26  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseBasicResource;
27  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseDataSet;
28  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseExchangeRate;
29  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseCurrency;
30  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseCurrency.MoneyWiseCurrencyList;
31  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseStaticDataType;
32  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataItem;
33  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataValues;
34  
35  import java.util.Iterator;
36  import java.util.ListIterator;
37  
38  /**
39   * Extension of ExchangeRate to cater for spot rates.
40   */
41  public final class MoneyWiseSpotExchangeRate
42          extends MoneyWiseExchangeRate {
43      /**
44       * Object name.
45       */
46      public static final String OBJECT_NAME = MoneyWiseSpotExchangeRate.class.getSimpleName();
47  
48      /**
49       * List name.
50       */
51      public static final String LIST_NAME = OBJECT_NAME + "s";
52  
53      /**
54       * Report fields.
55       */
56      @SuppressWarnings("rawtypes")
57      private static final MetisFieldSet<MoneyWiseSpotExchangeRate> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseSpotExchangeRate.class);
58  
59      /*
60       * The fields.
61       */
62      static {
63          FIELD_DEFS.declareLocalField(MoneyWiseViewResource.SPOTEVENT_PREVDATE, MoneyWiseSpotExchangeRate::getPrevDate);
64          FIELD_DEFS.declareLocalField(MoneyWiseViewResource.SPOTRATE_PREVRATE, MoneyWiseSpotExchangeRate::getPrevRate);
65      }
66  
67      /**
68       * the previous date.
69       */
70      private OceanusDate thePrevDate;
71  
72      /**
73       * the previous rate.
74       */
75      private OceanusRatio thePrevRate;
76  
77      /**
78       * Constructor for a new SpotRate where no rate data exists.
79       *
80       * @param pList     the Spot Rate List
81       * @param pCurrency the currency
82       */
83      private MoneyWiseSpotExchangeRate(final MoneyWiseSpotExchangeList pList,
84                                        final MoneyWiseCurrency pCurrency) {
85          super(pList);
86  
87          /* Store base values */
88          setDate(pList.theDate);
89          setFromCurrency(pList.getCurrency());
90          setToCurrency(pCurrency);
91      }
92  
93      @Override
94      public MetisFieldSetDef getDataFieldSet() {
95          return FIELD_DEFS;
96      }
97  
98      /**
99       * Obtain previous rate.
100      *
101      * @return the rate.
102      */
103     public OceanusRatio getPrevRate() {
104         return thePrevRate;
105     }
106 
107     /**
108      * Obtain previous date.
109      *
110      * @return the date.
111      */
112     public OceanusDate getPrevDate() {
113         return thePrevDate;
114     }
115 
116     /**
117      * Validate the line.
118      */
119     @Override
120     public void validate() {
121         setValidEdit();
122     }
123 
124     /* Is this row locked */
125     @Override
126     public boolean isLocked() {
127         return isDeleted();
128     }
129 
130     /**
131      * Note that this item has been validated.
132      */
133     @Override
134     public void setValidEdit() {
135         setEditState(hasHistory()
136                 ? MetisDataEditState.VALID
137                 : MetisDataEditState.CLEAN);
138     }
139 
140     @Override
141     public OceanusRatio getExchangeRate() {
142         /* Switch on state */
143         switch (getState()) {
144             case NEW:
145             case CHANGED:
146             case RECOVERED:
147             case CLEAN:
148                 return super.getExchangeRate();
149             default:
150                 return null;
151         }
152     }
153 
154     @Override
155     public MetisDataState getState() {
156         final MetisFieldVersionValues myCurr = getValues();
157         final MetisFieldVersionValues myBase = getOriginalValues();
158 
159         /* If we have no changes we are CLEAN */
160         if (myCurr.getVersion() == 0) {
161             return MetisDataState.CLEAN;
162         }
163 
164         /* If the original rate is Null */
165         if (myBase.getValue(MoneyWiseBasicResource.XCHGRATE_RATE) == null) {
166             /* Return status */
167             return myCurr.getValue(MoneyWiseBasicResource.XCHGRATE_RATE) == null
168                     ? MetisDataState.DELNEW
169                     : MetisDataState.NEW;
170         }
171 
172         /* If we are deleted return so */
173         return myCurr.getValue(MoneyWiseBasicResource.XCHGRATE_RATE) == null
174                 ? MetisDataState.DELETED
175                 : MetisDataState.CHANGED;
176     }
177 
178     /**
179      * The Spot Rates List class.
180      */
181     public static class MoneyWiseSpotExchangeList
182             extends MoneyWiseExchangeRateBaseList<MoneyWiseSpotExchangeRate> {
183         /**
184          * Report fields.
185          */
186         @SuppressWarnings("rawtypes")
187         private static final MetisFieldSet<MoneyWiseSpotExchangeList> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseSpotExchangeList.class);
188 
189         /*
190          * The currency field Id.
191          */
192         static {
193             FIELD_DEFS.declareLocalField(MoneyWiseStaticDataType.CURRENCY, MoneyWiseSpotExchangeList::getCurrency);
194             FIELD_DEFS.declareLocalField(MoneyWiseBasicResource.MONEYWISEDATA_FIELD_DATE, MoneyWiseSpotExchangeList::getDate);
195             FIELD_DEFS.declareLocalField(MoneyWiseViewResource.SPOTEVENT_NEXTDATE, MoneyWiseSpotExchangeList::getNext);
196             FIELD_DEFS.declareLocalField(MoneyWiseViewResource.SPOTEVENT_PREVDATE, MoneyWiseSpotExchangeList::getPrev);
197         }
198 
199         /**
200          * The date.
201          */
202         private final OceanusDate theDate;
203 
204         /**
205          * The view.
206          */
207         private final MoneyWiseView theView;
208 
209         /**
210          * The currency.
211          */
212         private final MoneyWiseCurrency theCurrency;
213 
214         /**
215          * The next date.
216          */
217         private OceanusDate theNext;
218 
219         /**
220          * The previous date.
221          */
222         private OceanusDate thePrev;
223 
224         /**
225          * Constructor.
226          *
227          * @param pView the view
228          * @param pDate the date
229          */
230         public MoneyWiseSpotExchangeList(final MoneyWiseView pView,
231                                          final OceanusDate pDate) {
232             /* Build initial list */
233             super(pView.getData(), MoneyWiseSpotExchangeRate.class, MoneyWiseBasicDataType.SECURITYPRICE);
234             setStyle(PrometheusListStyle.EDIT);
235             ensureMap();
236 
237             /* Store parameters */
238             theDate = pDate;
239             theView = pView;
240 
241             /* Obtain the portfolio bucket */
242             final MoneyWiseDataSet myData = theView.getData();
243             theCurrency = myData.getReportingCurrency();
244             final MoneyWiseCurrencyList myCurrencies = myData.getAccountCurrencies();
245 
246             /* Loop through the Currencies */
247             final OceanusDate myDate = new OceanusDate(theDate);
248             final Iterator<MoneyWiseCurrency> myCurIterator = myCurrencies.iterator();
249             while (myCurIterator.hasNext()) {
250                 final MoneyWiseCurrency myCurrency = myCurIterator.next();
251 
252                 /* Ignore deleted/disabled and default currency */
253                 boolean bIgnore = myCurrency.isDeleted() || myCurrency.isDisabled();
254                 bIgnore |= myCurrency.equals(theCurrency);
255                 if (bIgnore) {
256                     continue;
257                 }
258 
259                 /* Create a SpotRate entry */
260                 final MoneyWiseSpotExchangeRate mySpot = new MoneyWiseSpotExchangeRate(this, myCurrency);
261                 mySpot.setIndexedId(myCurrency.getIndexedId());
262                 mySpot.setDate(myDate);
263                 add(mySpot);
264             }
265 
266             /* Set the base for this list */
267             final MoneyWiseExchangeRateList myRates = myData.getExchangeRates();
268             setBase(myRates);
269 
270             /* Loop through the rates */
271             final ListIterator<MoneyWiseExchangeRate> myIterator = myRates.listIterator(myRates.size());
272             while (myIterator.hasPrevious()) {
273                 final MoneyWiseExchangeRate myRate = myIterator.previous();
274 
275                 /* Ignore deleted rates */
276                 if (myRate.isDeleted()) {
277                     continue;
278                 }
279 
280                 /* Test the Date */
281                 final int iDiff = theDate.compareTo(myRate.getDate());
282 
283                 /* If we are past the date */
284                 if (iDiff < 0) {
285                     /* Record the next date and break the loop */
286                     theNext = myRate.getDate();
287                     break;
288                 }
289 
290                 /* Access the Spot Rate and ignore if not relevant */
291                 final MoneyWiseCurrency myCurrency = myRate.getToCurrency();
292                 final MoneyWiseSpotExchangeRate mySpot = findItemById(myCurrency.getIndexedId());
293                 if (mySpot == null) {
294                     continue;
295                 }
296 
297                 /* If we are exactly the date */
298                 if (iDiff == 0) {
299                     /* Set rate */
300                     mySpot.setValueExchangeRate(myRate.getExchangeRate());
301 
302                     /* Link to base and re-establish state */
303                     mySpot.setBase(myRate);
304 
305                     /* else we are a previous date */
306                 } else {
307                     /* Set previous date and value */
308                     mySpot.thePrevDate = myRate.getDate();
309                     mySpot.thePrevRate = myRate.getExchangeRate();
310 
311                     /* Record the latest previous date */
312                     thePrev = myRate.getDate();
313                 }
314             }
315         }
316 
317         @SuppressWarnings("rawtypes")
318         @Override
319         public MetisFieldSet<MoneyWiseSpotExchangeList> getDataFieldSet() {
320             return FIELD_DEFS;
321         }
322 
323         @Override
324         public String listName() {
325             return MoneyWiseSpotExchangeList.class.getSimpleName();
326         }
327 
328         @Override
329         public MetisFieldSetDef getItemFields() {
330             return MoneyWiseSpotExchangeRate.FIELD_DEFS;
331         }
332 
333         @Override
334         protected MoneyWiseSpotExchangeList getEmptyList(final PrometheusListStyle pStyle) {
335             throw new UnsupportedOperationException();
336         }
337 
338         @Override
339         public MoneyWiseDataSet getDataSet() {
340             return (MoneyWiseDataSet) super.getDataSet();
341         }
342 
343         /**
344          * Obtain the currency.
345          *
346          * @return the currency
347          */
348         private MoneyWiseCurrency getCurrency() {
349             return theCurrency;
350         }
351 
352         /**
353          * Obtain the date.
354          *
355          * @return the date
356          */
357         private OceanusDate getDate() {
358             return theDate;
359         }
360 
361         /**
362          * Obtain the next date.
363          *
364          * @return the date
365          */
366         public OceanusDate getNext() {
367             return theNext;
368         }
369 
370         /**
371          * Obtain the previous date.
372          *
373          * @return the date
374          */
375         public OceanusDate getPrev() {
376             return thePrev;
377         }
378 
379         /* Is this list locked */
380         @Override
381         public boolean isLocked() {
382             return false;
383         }
384 
385         /* Disable Add a new item */
386         @Override
387         public MoneyWiseSpotExchangeRate addCopyItem(final PrometheusDataItem pElement) {
388             throw new UnsupportedOperationException();
389         }
390 
391         @Override
392         public MoneyWiseSpotExchangeRate addNewItem() {
393             throw new UnsupportedOperationException();
394         }
395 
396         @Override
397         public MoneyWiseSpotExchangeRate addValuesItem(final PrometheusDataValues pValues) {
398             throw new UnsupportedOperationException();
399         }
400     }
401 }