package name.abuchen.portfolio.datatransfer.csv;
import java.io.IOException;
import java.text.MessageFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import name.abuchen.portfolio.Messages;
import name.abuchen.portfolio.datatransfer.SecurityCache;
import name.abuchen.portfolio.datatransfer.csv.CSVImporter.Column;
import name.abuchen.portfolio.datatransfer.csv.CSVImporter.Field;
import name.abuchen.portfolio.model.Client;
import name.abuchen.portfolio.model.Security;
import name.abuchen.portfolio.money.CurrencyUnit;
import name.abuchen.portfolio.money.Money;
/* package */ abstract class BaseCSVExtractor extends CSVExtractor
{
private Client client;
private SecurityCache securityCache;
private String label;
private List<Field> fields;
/* package */ BaseCSVExtractor(Client client, String label)
{
this.client = client;
this.label = label;
this.fields = new ArrayList<>();
}
@Override
public final String getLabel()
{
return label;
}
@Override
public final List<Field> getFields()
{
return fields;
}
@Override
public final String toString()
{
return label;
}
public Client getClient()
{
return client;
}
@Override
public List<Item> extract(int skipLines, List<String[]> rawValues, Map<String, Column> field2column,
List<Exception> errors)
{
// careful: the security cache makes the extractor stateful because
// securities extracted during a previous run will not be created again
securityCache = new SecurityCache(client);
List<Item> results = new ArrayList<>();
int lineNo = 1 + skipLines; // +1 because of end user
for (String[] strings : rawValues)
{
try
{
extract(results, strings, field2column);
}
catch (ParseException | UnsupportedOperationException | IllegalArgumentException e)
{
errors.add(new IOException(MessageFormat.format(Messages.CSVLineXwithMsgY, lineNo, e.getMessage()), e));
}
lineNo++;
}
results.addAll(securityCache.createMissingSecurityItems(results));
securityCache = null;
return results;
}
/* package */ abstract void extract(List<Item> items, String[] rawValues, Map<String, Column> field2column)
throws ParseException;
protected Security getSecurity(String[] rawValues, Map<String, Column> field2column,
Consumer<Security> onSecurityCreated)
{
Security security = null;
String isin = getText(Messages.CSVColumn_ISIN, rawValues, field2column);
String tickerSymbol = getText(Messages.CSVColumn_TickerSymbol, rawValues, field2column);
String wkn = getText(Messages.CSVColumn_WKN, rawValues, field2column);
String name = getText(Messages.CSVColumn_SecurityName, rawValues, field2column);
if (isin != null || tickerSymbol != null || wkn != null || name != null)
{
name = constructName(isin, tickerSymbol, wkn, name);
security = securityCache.lookup(isin, tickerSymbol, wkn, name, () -> {
Security s = new Security();
s.setCurrencyCode(client.getBaseCurrency());
onSecurityCreated.accept(s);
return s;
});
}
return security;
}
private String constructName(String isin, String tickerSymbol, String wkn, String name)
{
if (name != null && !name.isEmpty())
{
return name;
}
else
{
String key = isin != null ? isin : tickerSymbol != null ? tickerSymbol : wkn;
return MessageFormat.format(Messages.CSVImportedSecurityLabel, key);
}
}
protected String getCurrencyCode(String name, String[] rawValues, Map<String, Column> field2column)
{
String value = getText(name, rawValues, field2column);
if (value == null)
return client.getBaseCurrency();
CurrencyUnit unit = CurrencyUnit.getInstance(value.trim());
return unit == null ? client.getBaseCurrency() : unit.getCurrencyCode();
}
protected Money getMoney(String[] rawValues, Map<String, Column> field2column) throws ParseException
{
Long amount = getAmount(Messages.CSVColumn_Value, rawValues, field2column);
if (amount == null)
throw new ParseException(MessageFormat.format(Messages.CSVImportMissingField, Messages.CSVColumn_Value), 0);
String currencyCode = getCurrencyCode(Messages.CSVColumn_TransactionCurrency, rawValues, field2column);
return Money.of(currencyCode, amount);
}
}