MoneyWiseExchangeRate.java
/*
* MoneyWise: Finance Application
* Copyright 2012-2026. Tony Washer
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package io.github.tonywasher.joceanus.moneywise.data.basic;
import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
import io.github.tonywasher.joceanus.oceanus.date.OceanusDate;
import io.github.tonywasher.joceanus.oceanus.date.OceanusDateFormatter;
import io.github.tonywasher.joceanus.oceanus.date.OceanusDateRange;
import io.github.tonywasher.joceanus.oceanus.decimal.OceanusMoney;
import io.github.tonywasher.joceanus.oceanus.decimal.OceanusRatio;
import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
import io.github.tonywasher.joceanus.metis.data.MetisDataDifference;
import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataFieldId;
import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataList;
import io.github.tonywasher.joceanus.metis.data.MetisDataResource;
import io.github.tonywasher.joceanus.metis.field.MetisFieldItem;
import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
import io.github.tonywasher.joceanus.metis.field.MetisFieldVersionedSet;
import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseCurrency;
import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseCurrency.MoneyWiseCurrencyList;
import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseStaticResource;
import io.github.tonywasher.joceanus.moneywise.exc.MoneyWiseDataException;
import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataInstanceMap;
import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataItem;
import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataList;
import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataMapItem;
import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataValues;
import java.util.ArrayList;
import java.util.Currency;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
/**
* ExchangeRate class.
*/
public class MoneyWiseExchangeRate
extends PrometheusDataItem {
/**
* Object name.
*/
public static final String OBJECT_NAME = MoneyWiseBasicDataType.EXCHANGERATE.getItemName();
/**
* List name.
*/
public static final String LIST_NAME = MoneyWiseBasicDataType.EXCHANGERATE.getListName();
/**
* Local Report fields.
*/
private static final MetisFieldVersionedSet<MoneyWiseExchangeRate> FIELD_DEFS = MetisFieldVersionedSet.newVersionedFieldSet(MoneyWiseExchangeRate.class);
/*
* FieldIds.
*/
static {
FIELD_DEFS.declareDateField(MoneyWiseBasicResource.MONEYWISEDATA_FIELD_DATE);
FIELD_DEFS.declareLinkField(MoneyWiseBasicResource.XCHGRATE_FROM);
FIELD_DEFS.declareLinkField(MoneyWiseBasicResource.XCHGRATE_TO);
FIELD_DEFS.declareRatioField(MoneyWiseBasicResource.XCHGRATE_RATE);
}
/**
* Circular Rate Error.
*/
public static final String ERROR_CIRCLE = MoneyWiseBasicResource.XCHGRATE_ERROR_CIRCLE.getValue();
/**
* Default Rate Error.
*/
public static final String ERROR_DEF = MoneyWiseBasicResource.XCHGRATE_ERROR_DEFAULT.getValue();
/**
* Copy Constructor.
*
* @param pList the list
* @param pRate The Rate to copy
*/
protected MoneyWiseExchangeRate(final MoneyWiseExchangeRateBaseList<? extends MoneyWiseExchangeRate> pList,
final MoneyWiseExchangeRate pRate) {
/* Set standard values */
super(pList, pRate);
}
/**
* Edit Constructor.
*
* @param pList the list
*/
public MoneyWiseExchangeRate(final MoneyWiseExchangeRateBaseList<? extends MoneyWiseExchangeRate> pList) {
super(pList, 0);
}
/**
* Values constructor.
*
* @param pList the List to add to
* @param pValues the values constructor
* @throws OceanusException on error
*/
private MoneyWiseExchangeRate(final MoneyWiseExchangeRateList pList,
final PrometheusDataValues pValues) throws OceanusException {
/* Initialise the item */
super(pList, pValues);
/* Access formatter */
final OceanusDataFormatter myFormatter = getDataSet().getDataFormatter();
/* Protect against exceptions */
try {
/* Store the Date */
Object myValue = pValues.getValue(MoneyWiseBasicResource.MONEYWISEDATA_FIELD_DATE);
if (myValue instanceof OceanusDate d) {
setValueDate(d);
} else if (myValue instanceof String s) {
final OceanusDateFormatter myParser = myFormatter.getDateFormatter();
setValueDate(myParser.parseDate(s));
}
/* Store the From currency */
myValue = pValues.getValue(MoneyWiseBasicResource.XCHGRATE_FROM);
if (myValue instanceof Integer i) {
setValueFromCurrency(i);
} else if (myValue instanceof String s) {
setValueFromCurrency(s);
}
/* Store the To currency */
myValue = pValues.getValue(MoneyWiseBasicResource.XCHGRATE_TO);
if (myValue instanceof Integer i) {
setValueToCurrency(i);
} else if (myValue instanceof String s) {
setValueToCurrency(s);
}
/* Store the Rate */
myValue = pValues.getValue(MoneyWiseBasicResource.XCHGRATE_RATE);
if (myValue instanceof OceanusRatio r) {
setValueExchangeRate(r);
} else if (myValue instanceof String myString) {
setValueExchangeRate(myString);
setValueExchangeRate(myFormatter.parseValue(myString, OceanusRatio.class));
}
/* Catch Exceptions */
} catch (IllegalArgumentException e) {
/* Pass on exception */
throw new MoneyWiseDataException(this, ERROR_CREATEITEM, e);
}
}
/**
* Edit Constructor.
*
* @param pList the list
*/
public MoneyWiseExchangeRate(final MoneyWiseExchangeRateList pList) {
super(pList, 0);
}
@Override
public MetisFieldSetDef getDataFieldSet() {
return FIELD_DEFS;
}
@Override
public String formatObject(final OceanusDataFormatter pFormatter) {
return toString();
}
@Override
public String toString() {
/* Access formatter */
final OceanusDataFormatter myFormatter = getDataSet().getDataFormatter();
/* Create string builder */
final StringBuilder myBuilder = new StringBuilder();
myBuilder.append(myFormatter.formatObject(getDate()));
myBuilder.append(" ");
myBuilder.append(myFormatter.formatObject(getFromCurrency().getCurrency().getCurrencyCode()));
myBuilder.append(": ");
myBuilder.append(myFormatter.formatObject(getToCurrency().getCurrency().getCurrencyCode()));
myBuilder.append('=');
myBuilder.append(myFormatter.formatObject(getExchangeRate()));
return myBuilder.toString();
}
@Override
public boolean includeXmlField(final MetisDataFieldId pField) {
/* Determine whether fields should be included */
if (MoneyWiseBasicResource.MONEYWISEDATA_FIELD_DATE.equals(pField)) {
return true;
}
if (MoneyWiseBasicResource.XCHGRATE_FROM.equals(pField)) {
return true;
}
if (MoneyWiseBasicResource.XCHGRATE_TO.equals(pField)) {
return true;
}
if (MoneyWiseBasicResource.XCHGRATE_RATE.equals(pField)) {
return true;
}
/* Pass call on */
return super.includeXmlField(pField);
}
/**
* Obtain Date.
*
* @return the name
*/
public OceanusDate getDate() {
return getValues().getValue(MoneyWiseBasicResource.MONEYWISEDATA_FIELD_DATE, OceanusDate.class);
}
/**
* Obtain From currency.
*
* @return the currency
*/
public MoneyWiseCurrency getFromCurrency() {
return getValues().getValue(MoneyWiseBasicResource.XCHGRATE_FROM, MoneyWiseCurrency.class);
}
/**
* Obtain fromCurrencyId.
*
* @return the fromCurrencyId
*/
public Integer getFromCurrencyId() {
final MoneyWiseCurrency myCurr = getFromCurrency();
return myCurr == null
? null
: myCurr.getIndexedId();
}
/**
* Obtain FromCurrencyName.
*
* @return the fromCurrencyName
*/
public String getFromCurrencyName() {
final MoneyWiseCurrency myCurr = getFromCurrency();
return myCurr == null
? null
: myCurr.getName();
}
/**
* Obtain To currency.
*
* @return the currency
*/
public MoneyWiseCurrency getToCurrency() {
return getValues().getValue(MoneyWiseBasicResource.XCHGRATE_TO, MoneyWiseCurrency.class);
}
/**
* Obtain toCurrencyId.
*
* @return the toCurrencyId
*/
public Integer getToCurrencyId() {
final MoneyWiseCurrency myCurr = getToCurrency();
return myCurr == null
? null
: myCurr.getIndexedId();
}
/**
* Obtain ToCurrencyName.
*
* @return the toCurrencyName
*/
public String getToCurrencyName() {
final MoneyWiseCurrency myCurr = getToCurrency();
return myCurr == null
? null
: myCurr.getName();
}
/**
* Obtain ExchangeRate.
*
* @return the rate
*/
public OceanusRatio getExchangeRate() {
return getValues().getValue(MoneyWiseBasicResource.XCHGRATE_RATE, OceanusRatio.class);
}
/**
* Obtain InverseRate.
*
* @return the inverse rate
*/
public OceanusRatio getInverseRate() {
final OceanusRatio myRate = getExchangeRate();
return myRate == null
? null
: myRate.getInverseRatio();
}
/**
* Set date value.
*
* @param pValue the value
*/
private void setValueDate(final OceanusDate pValue) {
getValues().setUncheckedValue(MoneyWiseBasicResource.MONEYWISEDATA_FIELD_DATE, pValue);
}
/**
* Set from currency value.
*
* @param pValue the value
*/
private void setValueFromCurrency(final MoneyWiseCurrency pValue) {
getValues().setUncheckedValue(MoneyWiseBasicResource.XCHGRATE_FROM, pValue);
}
/**
* Set from currency value.
*
* @param pValue the value
*/
private void setValueFromCurrency(final Integer pValue) {
getValues().setUncheckedValue(MoneyWiseBasicResource.XCHGRATE_FROM, pValue);
}
/**
* Set from currency value.
*
* @param pValue the value
*/
private void setValueFromCurrency(final String pValue) {
getValues().setUncheckedValue(MoneyWiseBasicResource.XCHGRATE_FROM, pValue);
}
/**
* Set to currency value.
*
* @param pValue the value
*/
private void setValueToCurrency(final MoneyWiseCurrency pValue) {
getValues().setUncheckedValue(MoneyWiseBasicResource.XCHGRATE_TO, pValue);
}
/**
* Set to currency value.
*
* @param pValue the value
*/
private void setValueToCurrency(final Integer pValue) {
getValues().setUncheckedValue(MoneyWiseBasicResource.XCHGRATE_TO, pValue);
}
/**
* Set to currency value.
*
* @param pValue the value
*/
private void setValueToCurrency(final String pValue) {
getValues().setUncheckedValue(MoneyWiseBasicResource.XCHGRATE_TO, pValue);
}
/**
* Set exchange rate value.
*
* @param pValue the value
*/
protected void setValueExchangeRate(final OceanusRatio pValue) {
getValues().setUncheckedValue(MoneyWiseBasicResource.XCHGRATE_RATE, pValue);
}
/**
* Set exchange rate value.
*
* @param pValue the value
*/
private void setValueExchangeRate(final String pValue) {
getValues().setUncheckedValue(MoneyWiseBasicResource.XCHGRATE_RATE, pValue);
}
@Override
public MoneyWiseDataSet getDataSet() {
return (MoneyWiseDataSet) super.getDataSet();
}
@Override
public MoneyWiseExchangeRate getBase() {
return (MoneyWiseExchangeRate) super.getBase();
}
@Override
@SuppressWarnings("unchecked")
public MoneyWiseExchangeRateBaseList<? extends MoneyWiseExchangeRate> getList() {
return (MoneyWiseExchangeRateBaseList<? extends MoneyWiseExchangeRate>) super.getList();
}
@Override
public int compareValues(final PrometheusDataItem pThat) {
/* Access as ExchangeRate */
final MoneyWiseExchangeRate myThat = (MoneyWiseExchangeRate) pThat;
/* If the date differs */
int iDiff = MetisDataDifference.compareObject(getDate(), myThat.getDate());
if (iDiff != 0) {
/* Sort in reverse date order !! */
return -iDiff;
}
/* Compare From Currency */
iDiff = MetisDataDifference.compareObject(getFromCurrency(), myThat.getFromCurrency());
if (iDiff != 0) {
return iDiff;
}
/* Compare the toCurrency */
return getToCurrency().compareTo(myThat.getToCurrency());
}
@Override
public void resolveDataSetLinks() throws OceanusException {
/* Update the Encryption details */
super.resolveDataSetLinks();
/* Resolve currencies */
final MoneyWiseDataSet myData = getDataSet();
final MoneyWiseCurrencyList myCurrencies = myData.getAccountCurrencies();
resolveDataLink(MoneyWiseBasicResource.XCHGRATE_FROM, myCurrencies);
resolveDataLink(MoneyWiseBasicResource.XCHGRATE_TO, myCurrencies);
}
/**
* Set a new date.
*
* @param pDate the new date
*/
public void setDate(final OceanusDate pDate) {
setValueDate(pDate);
}
/**
* Set a new from currency.
*
* @param pCurrency the new from currency
*/
public void setFromCurrency(final MoneyWiseCurrency pCurrency) {
setValueFromCurrency(pCurrency);
}
/**
* Set a new to currency.
*
* @param pCurrency the new to currency
*/
public void setToCurrency(final MoneyWiseCurrency pCurrency) {
setValueToCurrency(pCurrency);
}
/**
* Set a new exchange rate.
*
* @param pRate the new rate
*/
public void setExchangeRate(final OceanusRatio pRate) {
setValueExchangeRate(pRate);
}
@Override
public void touchUnderlyingItems() {
/* touch the currencies referred to */
getFromCurrency().touchItem(this);
getToCurrency().touchItem(this);
}
/**
* Update base rate from an edited rate.
*
* @param pRate the edited rate
* @return whether changes have been made
*/
@Override
public boolean applyChanges(final PrometheusDataItem pRate) {
/* Can only update from an event exchange rate */
if (!(pRate instanceof MoneyWiseExchangeRate)) {
return false;
}
final MoneyWiseExchangeRate myRate = (MoneyWiseExchangeRate) pRate;
/* Store the current detail into history */
pushHistory();
/* Update the Date if required */
if (!MetisDataDifference.isEqual(getDate(), myRate.getDate())) {
setValueDate(myRate.getDate());
}
/* Update the from currency if required */
if (!MetisDataDifference.isEqual(getFromCurrency(), myRate.getFromCurrency())) {
setValueFromCurrency(myRate.getFromCurrency());
}
/* Update the to currency if required */
if (!MetisDataDifference.isEqual(getToCurrency(), myRate.getToCurrency())) {
setValueToCurrency(myRate.getToCurrency());
}
/* Update the rate if required */
if (!MetisDataDifference.isEqual(getExchangeRate(), myRate.getExchangeRate())) {
setValueExchangeRate(myRate.getExchangeRate());
}
/* Check for changes */
return checkForHistory();
}
@Override
public void adjustMapForItem() {
final MoneyWiseExchangeRateBaseList<? extends MoneyWiseExchangeRate> myList = getList();
final MoneyWiseExchangeRateDataMap myMap = myList.getDataMap();
myMap.adjustForItem(this);
}
/**
* Price List.
*
* @param <T> the data type
*/
public abstract static class MoneyWiseExchangeRateBaseList<T extends MoneyWiseExchangeRate>
extends PrometheusDataList<T> {
/*
* Report fields.
*/
static {
MetisFieldSet.newFieldSet(MoneyWiseExchangeRateBaseList.class);
}
/**
* Construct an empty CORE Price list.
*
* @param pData the DataSet for the list
* @param pClass the class of the item
* @param pItemType the item type
*/
protected MoneyWiseExchangeRateBaseList(final MoneyWiseDataSet pData,
final Class<T> pClass,
final MoneyWiseBasicDataType pItemType) {
/* Call super-constructor */
super(pClass, pData, pItemType, PrometheusListStyle.CORE);
}
/**
* Constructor for a cloned List.
*
* @param pSource the source List
*/
protected MoneyWiseExchangeRateBaseList(final MoneyWiseExchangeRateBaseList<T> pSource) {
/* Call super-constructor */
super(pSource);
}
@Override
public MoneyWiseExchangeRateDataMap getDataMap() {
return (MoneyWiseExchangeRateDataMap) super.getDataMap();
}
@Override
protected MoneyWiseExchangeRateDataMap allocateDataMap() {
return new MoneyWiseExchangeRateDataMap();
}
}
/**
* The ExchangeRate List class.
*/
public static class MoneyWiseExchangeRateList
extends MoneyWiseExchangeRateBaseList<MoneyWiseExchangeRate> {
/**
* Report fields.
*/
private static final MetisFieldSet<MoneyWiseExchangeRateList> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseExchangeRateList.class);
/*
* Declare Fields.
*/
static {
FIELD_DEFS.declareLocalField(MoneyWiseStaticResource.CURRENCY_REPORTING, MoneyWiseExchangeRateList::getReportingCurrency);
}
/**
* The reporting currency.
*/
private MoneyWiseCurrency theReporting;
/**
* Construct an empty CORE ExchangeRate list.
*
* @param pData the DataSet for the list
*/
protected MoneyWiseExchangeRateList(final MoneyWiseDataSet pData) {
super(pData, MoneyWiseExchangeRate.class, MoneyWiseBasicDataType.EXCHANGERATE);
}
/**
* Constructor for a cloned List.
*
* @param pSource the source List
*/
protected MoneyWiseExchangeRateList(final MoneyWiseExchangeRateList pSource) {
super(pSource);
}
@Override
public MetisFieldSet<MoneyWiseExchangeRateList> getDataFieldSet() {
return FIELD_DEFS;
}
/**
* Obtain reporting currency.
*
* @return the reporting currency
*/
public MoneyWiseCurrency getReportingCurrency() {
return theReporting;
}
@Override
public String listName() {
return LIST_NAME;
}
@Override
public MetisFieldSetDef getItemFields() {
return MoneyWiseExchangeRate.FIELD_DEFS;
}
@Override
public MoneyWiseDataSet getDataSet() {
return (MoneyWiseDataSet) super.getDataSet();
}
@Override
protected MoneyWiseExchangeRateList getEmptyList(final PrometheusListStyle pStyle) {
final MoneyWiseExchangeRateList myList = new MoneyWiseExchangeRateList(this);
myList.setStyle(pStyle);
return myList;
}
/**
* Add a new item to the core list.
*
* @param pRate item
* @return the newly added item
*/
@Override
public MoneyWiseExchangeRate addCopyItem(final PrometheusDataItem pRate) {
/* Can only clone an ExchangeRate */
if (!(pRate instanceof MoneyWiseExchangeRate)) {
throw new UnsupportedOperationException();
}
final MoneyWiseExchangeRate myRate = new MoneyWiseExchangeRate(this, (MoneyWiseExchangeRate) pRate);
add(myRate);
return myRate;
}
/**
* Add a new item to the edit list.
*
* @return the new item
*/
@Override
public MoneyWiseExchangeRate addNewItem() {
final MoneyWiseExchangeRate myRate = new MoneyWiseExchangeRate(this);
add(myRate);
return myRate;
}
@Override
public MoneyWiseExchangeRate addValuesItem(final PrometheusDataValues pValues)
throws OceanusException {
/* Create the rate */
final MoneyWiseExchangeRate myRate = new MoneyWiseExchangeRate(this, pValues);
/* Check that this RateId has not been previously added */
if (!isIdUnique(myRate.getIndexedId())) {
myRate.addError(ERROR_DUPLICATE, MetisDataResource.DATA_ID);
throw new MoneyWiseDataException(myRate, ERROR_VALIDATION);
}
/* Add to the list */
add(myRate);
/* Return it */
return myRate;
}
/**
* Convert a monetary value to the currency.
*
* @param pValue the value to convert
* @param pCurrency the required currency
* @param pDate the date of the conversion
* @return the converted value
*/
public OceanusMoney convertCurrency(final OceanusMoney pValue,
final MoneyWiseCurrency pCurrency,
final OceanusDate pDate) {
/* Obtain the existing currency */
OceanusMoney myValue = pValue;
final MoneyWiseCurrencyList myCurrencies = getDataSet().getAccountCurrencies();
final Currency myCurrent = pValue.getCurrency();
final Currency myReporting = theReporting.getCurrency();
final Currency myTarget = pCurrency.getCurrency();
/* Handle no conversion required */
if (myCurrent.equals(myTarget)) {
return pValue;
}
/* If the value is not already the reporting currency */
if (!myCurrent.equals(myReporting)) {
/* Find the required exchange rate */
final OceanusRatio myRate = findRate(myCurrencies.findCurrency(myCurrent), pDate);
/* Convert the currency */
myValue = myValue.convertCurrency(myReporting, myRate);
}
/* If we need to convert to a non-default currency */
if (!myReporting.equals(myTarget)) {
/* Find the required exchange rate */
final OceanusRatio myRate = findRate(pCurrency, pDate);
/* Convert the currency */
myValue = myValue.convertCurrency(myTarget, myRate);
}
/* Return the converted currency */
return myValue;
}
/**
* Find the exchange rate.
*
* @param pCurrency the currency to find
* @param pDate the date to find the exchange rate for
* @return the exchange rate
*/
private OceanusRatio findRate(final MoneyWiseCurrency pCurrency,
final OceanusDate pDate) {
/* pass call to data map */
return getDataMap().getRateForDate(pCurrency, pDate);
}
/**
* Set the default currency.
*
* @param pCurrency the new default currency
*/
public void setReportingCurrency(final MoneyWiseCurrency pCurrency) {
/* Access the iterator */
final Iterator<MoneyWiseExchangeRate> myIterator = iterator();
OceanusRatio myCurrRate = null;
OceanusDate myCurrDate = null;
/* Loop through the items to find the entry */
while (myIterator.hasNext()) {
final MoneyWiseExchangeRate myCurr = myIterator.next();
/* Access details */
final OceanusDate myDate = myCurr.getDate();
final MoneyWiseCurrency myTo = myCurr.getToCurrency();
final OceanusRatio myRatio = myCurr.getExchangeRate();
/* If this is a new date */
if (myCurrDate == null || !myDate.equals(myCurrDate)) {
/* Access the current rate for the new default currency */
/*
* TODO This must exist on the same date or else the currency cannot be set as
* default
*/
myCurrRate = findRate(pCurrency, myDate);
myCurrDate = myDate;
}
/* Update the item */
myCurr.pushHistory();
/* If this is a conversion to the new default */
if (myTo.equals(pCurrency)) {
/* Switch the direction of the currencies */
myCurr.setToCurrency(myCurr.getFromCurrency());
/* Invert the ratio */
myCurr.setExchangeRate(myRatio.getInverseRatio());
/* Else does not currently involve the new currency */
} else {
/* Need to combine the rates */
myCurr.setExchangeRate(new OceanusRatio(myRatio, myCurrRate));
}
/* Set from currency */
myCurr.setFromCurrency(pCurrency);
}
/* Set the new reporting currency */
theReporting = pCurrency;
}
}
/**
* The dataMap class.
*/
public static class MoneyWiseExchangeRateDataMap
implements PrometheusDataMapItem, MetisFieldItem {
/**
* Report fields.
*/
@SuppressWarnings("rawtypes")
private static final MetisFieldSet<MoneyWiseExchangeRateDataMap> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseExchangeRateDataMap.class);
/*
* UnderlyingMap Field Id.
*/
static {
FIELD_DEFS.declareLocalField(MoneyWiseBasicResource.MONEYWISEDATA_MAP_MAPOFMAPS, MoneyWiseExchangeRateDataMap::getMapOfMaps);
FIELD_DEFS.declareLocalField(MoneyWiseBasicResource.XCHGRATE_MAP_MAPOFRATES, MoneyWiseExchangeRateDataMap::getMapOfRates);
}
/**
* Map of Maps.
*/
private final Map<MoneyWiseCurrency, Map<OceanusDate, Integer>> theMapOfMaps;
/**
* Map of Rates.
*/
private final Map<MoneyWiseCurrency, MoneyWiseRateList> theMapOfRates;
/**
* Constructor.
*/
public MoneyWiseExchangeRateDataMap() {
/* Create the maps */
theMapOfMaps = new HashMap<>();
theMapOfRates = new HashMap<>();
}
@SuppressWarnings("rawtypes")
@Override
public MetisFieldSet<MoneyWiseExchangeRateDataMap> getDataFieldSet() {
return FIELD_DEFS;
}
@Override
public String formatObject(final OceanusDataFormatter pFormatter) {
return FIELD_DEFS.getName();
}
/**
* Obtain mapOfMaps.
*
* @return the map
*/
private Map<MoneyWiseCurrency, Map<OceanusDate, Integer>> getMapOfMaps() {
return theMapOfMaps;
}
/**
* Obtain mapOfRates.
*
* @return the map
*/
private Map<MoneyWiseCurrency, MoneyWiseRateList> getMapOfRates() {
return theMapOfRates;
}
@Override
public void resetMap() {
theMapOfMaps.clear();
theMapOfRates.clear();
}
@Override
public void adjustForItem(final PrometheusDataItem pItem) {
/* Access the Currency Id */
final MoneyWiseExchangeRate myItem = (MoneyWiseExchangeRate) pItem;
final MoneyWiseCurrency myCurrency = myItem.getToCurrency();
if (myCurrency == null) {
return;
}
/* Access the map */
final Map<OceanusDate, Integer> myMap = theMapOfMaps.computeIfAbsent(myCurrency, c -> new HashMap<>());
/* Adjust rate count */
final OceanusDate myDate = myItem.getDate();
final Integer myCount = myMap.get(myDate);
if (myCount == null) {
myMap.put(myDate, PrometheusDataInstanceMap.ONE);
} else {
myMap.put(myDate, myCount + 1);
}
/* Access the list */
final MoneyWiseRateList myList = theMapOfRates.computeIfAbsent(myCurrency, MoneyWiseRateList::new);
/* Add element to the list */
myList.add(myItem);
}
/**
* Check validity of Rate.
*
* @param pItem the rate
* @return true/false
*/
public boolean validRateCount(final MoneyWiseExchangeRate pItem) {
/* Access the Details */
final MoneyWiseCurrency myCurrency = pItem.getToCurrency();
final OceanusDate myDate = pItem.getDate();
/* Access the map */
final Map<OceanusDate, Integer> myMap = theMapOfMaps.get(myCurrency);
if (myMap != null) {
final Integer myResult = myMap.get(myDate);
return PrometheusDataInstanceMap.ONE.equals(myResult);
}
return false;
}
/**
* Check availability of date for a currency.
*
* @param pCurrency the currency
* @param pDate the key to look up
* @return true/false
*/
public boolean availableDate(final MoneyWiseCurrency pCurrency,
final OceanusDate pDate) {
/* Access the map */
final Map<OceanusDate, Integer> myMap = theMapOfMaps.get(pCurrency);
return myMap == null
|| myMap.get(pDate) == null;
}
/**
* Obtain rate for date.
*
* @param pCurrency the currency
* @param pDate the date
* @return the latest rate for the date.
*/
public OceanusRatio getRateForDate(final MoneyWiseCurrency pCurrency,
final OceanusDate pDate) {
/* Access list for currency */
final MoneyWiseRateList myList = theMapOfRates.get(pCurrency);
if (myList != null) {
/* Loop through the rates */
final Iterator<MoneyWiseExchangeRate> myIterator = myList.iterator();
while (myIterator.hasNext()) {
final MoneyWiseExchangeRate myCurr = myIterator.next();
/* Access the date */
final OceanusDate myDate = myCurr.getDate();
/* break loop if we have the correct record */
if (myDate.compareTo(pDate) >= 0) {
return myCurr.getExchangeRate();
}
}
}
/* return null */
return null;
}
/**
* Obtain rates for range.
*
* @param pCurrency the currency
* @param pRange the date range
* @return the two deep array of rates for the range.
*/
public OceanusRatio[] getRatesForRange(final MoneyWiseCurrency pCurrency,
final OceanusDateRange pRange) {
/* Set rate */
OceanusRatio myFirst = OceanusRatio.ONE;
OceanusRatio myLatest = OceanusRatio.ONE;
final OceanusDate myStart = pRange.getStart();
/* Access list for security */
final MoneyWiseRateList myList = theMapOfRates.get(pCurrency);
if (myList != null) {
/* Loop through the rates */
final ListIterator<MoneyWiseExchangeRate> myIterator = myList.listIterator(myList.size());
while (myIterator.hasPrevious()) {
final MoneyWiseExchangeRate myCurr = myIterator.previous();
/* Check for the range of the date */
final OceanusDate myDate = myCurr.getDate();
final int iComp = pRange.compareToDate(myDate);
/* If this is later than the range we are finished */
if (iComp < 0) {
break;
}
/* Record as best rate */
myLatest = myCurr.getExchangeRate();
/* Adjust first rate */
if (iComp > 0
|| myDate.compareTo(myStart) == 0) {
myFirst = myLatest;
}
}
}
/* Return the rates */
return new OceanusRatio[]
{myFirst, myLatest};
}
/**
* Obtain rateList cursor.
*
* @param pCurrency the currency
* @return the latest rate for the date.
*/
public ListIterator<MoneyWiseExchangeRate> rateIterator(final MoneyWiseCurrency pCurrency) {
/* Access list for currency */
final MoneyWiseRateList myList = theMapOfRates.get(pCurrency);
return myList != null
? myList.listIterator(myList.size())
: null;
}
/**
* Rate List class.
*/
private static final class MoneyWiseRateList
implements MetisFieldItem, MetisDataList<MoneyWiseExchangeRate> {
/**
* Report fields.
*/
private static final MetisFieldSet<MoneyWiseRateList> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseRateList.class);
/*
* UnderlyingMap Field Id.
*/
static {
FIELD_DEFS.declareLocalField(MetisDataResource.LIST_SIZE, MoneyWiseRateList::size);
}
/**
* The list.
*/
private final List<MoneyWiseExchangeRate> theList;
/**
* The currency.
*/
private final MoneyWiseCurrency theCurrency;
/**
* Constructor.
*
* @param pCurrency the currency
*/
private MoneyWiseRateList(final MoneyWiseCurrency pCurrency) {
theCurrency = pCurrency;
theList = new ArrayList<>();
}
@Override
public MetisFieldSet<MoneyWiseRateList> getDataFieldSet() {
return FIELD_DEFS;
}
@Override
public String formatObject(final OceanusDataFormatter pFormatter) {
return theCurrency.formatObject(pFormatter)
+ "("
+ size()
+ ")";
}
@Override
public String toString() {
return theCurrency.toString()
+ "("
+ size()
+ ")";
}
@Override
public List<MoneyWiseExchangeRate> getUnderlyingList() {
return theList;
}
}
}
}