package name.abuchen.portfolio.ui.views.dataseries;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.inject.Inject;
import name.abuchen.portfolio.model.Account;
import name.abuchen.portfolio.model.Classification;
import name.abuchen.portfolio.model.Client;
import name.abuchen.portfolio.model.Portfolio;
import name.abuchen.portfolio.model.Security;
import name.abuchen.portfolio.money.CurrencyConverter;
import name.abuchen.portfolio.money.CurrencyConverterImpl;
import name.abuchen.portfolio.money.ExchangeRateProviderFactory;
import name.abuchen.portfolio.snapshot.PerformanceIndex;
import name.abuchen.portfolio.snapshot.ReportingPeriod;
import name.abuchen.portfolio.ui.PortfolioPlugin;
import name.abuchen.portfolio.ui.util.ClientFilterMenu;
/**
* Cache for calculation results of DataSeries.
*/
public class DataSeriesCache
{
private static class CacheKey
{
private final String uuid;
private final ReportingPeriod reportingPeriod;
CacheKey(String uuid, ReportingPeriod reportingPeriod)
{
this.uuid = Objects.requireNonNull(uuid);
this.reportingPeriod = Objects.requireNonNull(reportingPeriod);
}
@Override
public int hashCode()
{
return Objects.hash(uuid, reportingPeriod);
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CacheKey other = (CacheKey) obj;
if (!uuid.equals(other.uuid))
return false;
if (!reportingPeriod.equals(other.reportingPeriod))
return false;
return true;
}
}
private final Client client;
private final CurrencyConverter converter;
private final Map<CacheKey, PerformanceIndex> cache = new HashMap<>();
@Inject
public DataSeriesCache(Client client, ExchangeRateProviderFactory factory)
{
this.client = client;
this.converter = new CurrencyConverterImpl(factory, client.getBaseCurrency());
}
public void clear()
{
this.cache.clear();
}
public PerformanceIndex lookup(DataSeries series, ReportingPeriod reportingPeriod)
{
// Every data series is cached separately except the for the client. The
// client data series are created out of the same PerformanceIndex
// instance, e.g. accumulated and delta performance.
String uuid = series.getType() == DataSeries.Type.CLIENT ? "$client$" : series.getUUID(); //$NON-NLS-1$
CacheKey key = new CacheKey(uuid, reportingPeriod);
return cache.computeIfAbsent(key, k -> calculate(series, reportingPeriod));
}
private PerformanceIndex calculate(DataSeries series, ReportingPeriod reportingPeriod)
{
List<Exception> warnings = new ArrayList<>();
try
{
switch (series.getType())
{
case CLIENT:
return PerformanceIndex.forClient(client, converter, reportingPeriod, warnings);
case SECURITY:
return PerformanceIndex.forInvestment(client, converter, (Security) series.getInstance(),
reportingPeriod, warnings);
case SECURITY_BENCHMARK:
return PerformanceIndex.forSecurity(
lookup(new DataSeries(DataSeries.Type.CLIENT, null, null, null), reportingPeriod),
(Security) series.getInstance());
case PORTFOLIO:
return PerformanceIndex.forPortfolio(client, converter, (Portfolio) series.getInstance(),
reportingPeriod, warnings);
case PORTFOLIO_PLUS_ACCOUNT:
return PerformanceIndex.forPortfolioPlusAccount(client, converter, (Portfolio) series.getInstance(),
reportingPeriod, warnings);
case ACCOUNT:
Account account = (Account) series.getInstance();
return PerformanceIndex.forAccount(client, converter, account, reportingPeriod, warnings);
case CLASSIFICATION:
Classification classification = (Classification) series.getInstance();
return PerformanceIndex.forClassification(client, converter, classification, reportingPeriod,
warnings);
case CONSUMER_PRICE_INDEX:
return PerformanceIndex.forConsumerPriceIndex(
lookup(new DataSeries(DataSeries.Type.CLIENT, null, null, null), reportingPeriod));
case CLIENT_FILTER:
ClientFilterMenu.Item item = (ClientFilterMenu.Item) series.getInstance();
return PerformanceIndex.forClient(item.getFilter().filter(client), converter, reportingPeriod,
warnings);
default:
throw new IllegalArgumentException(series.getType().name());
}
}
finally
{
if (!warnings.isEmpty())
PortfolioPlugin.log(warnings);
}
}
}