package io.konik.csv.mapper;
import com.google.common.base.Function;
import com.neovisionaries.i18n.CountryCode;
import com.neovisionaries.i18n.CurrencyCode;
import io.konik.csv.processor.DateProcessor;
import io.konik.csv.processor.ReferenceProcessor;
import io.konik.csv.processor.UnitOfMeasurementProcessor;
import io.konik.zugferd.unece.codes.Reference;
import io.konik.zugferd.unece.codes.UnitOfMeasurement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.supercsv.cellprocessor.ift.CellProcessor;
import javax.annotation.Nullable;
import java.math.BigDecimal;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static io.konik.csv.mapper.CsvMapperBuilder.Column;
import static io.konik.csv.mapper.CsvMapperBuilder.column;
final class CsvMapperHeaderColumnsConfigurer implements ColumnsConfigurer {
private static final Logger log = LoggerFactory.getLogger(CsvMapperHeaderColumnsConfigurer.class);
private static final ConcurrentMap<Pattern, Function<String, Column.Builder>> config = new ConcurrentHashMap<Pattern, Function<String, Column.Builder>>();
static {
config.put(Pattern.compile("^file\\.input"), defaultColumn());
config.put(Pattern.compile("^file\\.output"), defaultColumn());
config.put(Pattern.compile("^header\\.invoiceNumber$"), defaultColumn());
config.put(Pattern.compile("^header\\.type$"), defaultColumn());
config.put(Pattern.compile("^header\\.issued$"), typeColumn(Date.class, new DateProcessor()));
config.put(Pattern.compile("^header\\.dueDate$"), typeColumn(Date.class, new DateProcessor()));
config.put(Pattern.compile("^header\\.reference$"), defaultColumn());
config.put(Pattern.compile("^header\\.customerNumber$"), defaultColumn());
config.put(Pattern.compile("^header\\.currency$"), typeColumn(CurrencyCode.class));
config.put(Pattern.compile("^header\\.note$"), defaultColumn());
config.put(Pattern.compile("^recipient\\.name$"), defaultColumn());
config.put(Pattern.compile("^recipient\\.contactName$"), defaultColumn());
config.put(Pattern.compile("^recipient\\.addressLine1$"), defaultColumn());
config.put(Pattern.compile("^recipient\\.addressLine2$"), defaultColumn());
config.put(Pattern.compile("^recipient\\.city$"), defaultColumn());
config.put(Pattern.compile("^recipient\\.postcode$"), defaultColumn());
config.put(Pattern.compile("^recipient\\.countryCode$"), typeColumn(CountryCode.class));
config.put(Pattern.compile("^recipient\\.postcode$"), defaultColumn());
config.put(Pattern.compile("^recipient\\.email$"), defaultColumn());
config.put(Pattern.compile("^recipient\\.taxes\\[\\d\\].number$"), defaultColumn());
config.put(Pattern.compile("^recipient\\.taxes\\[\\d\\].type$"), typeColumn(Reference.class, new ReferenceProcessor()));
config.put(Pattern.compile("^recipient\\.bankInfo.bankName$"), defaultColumn());
config.put(Pattern.compile("^recipient\\.bankInfo.bic$"), defaultColumn());
config.put(Pattern.compile("^recipient\\.bankInfo.iban$"), defaultColumn());
config.put(Pattern.compile("^issuer\\.name$"), defaultColumn());
config.put(Pattern.compile("^issuer\\.contactName$"), defaultColumn());
config.put(Pattern.compile("^issuer\\.addressLine1$"), defaultColumn());
config.put(Pattern.compile("^issuer\\.addressLine2$"), defaultColumn());
config.put(Pattern.compile("^issuer\\.city$"), defaultColumn());
config.put(Pattern.compile("^issuer\\.postcode$"), defaultColumn());
config.put(Pattern.compile("^issuer\\.countryCode$"), typeColumn(CountryCode.class));
config.put(Pattern.compile("^issuer\\.postcode$"), defaultColumn());
config.put(Pattern.compile("^issuer\\.email$"), defaultColumn());
config.put(Pattern.compile("^issuer\\.taxes\\[\\d\\].number$"), defaultColumn());
config.put(Pattern.compile("^issuer\\.taxes\\[\\d\\].type$"), typeColumn(Reference.class, new ReferenceProcessor()));
config.put(Pattern.compile("^issuer\\.bankInfo.bankName$"), defaultColumn());
config.put(Pattern.compile("^issuer\\.bankInfo.bic$"), defaultColumn());
config.put(Pattern.compile("^issuer\\.bankInfo.iban$"), defaultColumn());
config.put(Pattern.compile("^items\\[\\d\\]\\.name$"), defaultColumn());
config.put(Pattern.compile("^items\\[\\d\\]\\.quantity$"), typeColumn(BigDecimal.class));
config.put(Pattern.compile("^items\\[\\d\\]\\.unit$"), typeColumn(UnitOfMeasurement.class, new UnitOfMeasurementProcessor()));
config.put(Pattern.compile("^items\\[\\d\\]\\.unitPrice$"), typeColumn(BigDecimal.class));
config.put(Pattern.compile("^items\\[\\d\\]\\.taxPercent$"), typeColumn(BigDecimal.class));
}
private static Function<String, Column.Builder> defaultColumn() {
return new Function<String, Column.Builder>() {
@Nullable
@Override
public Column.Builder apply(String input) {
log.debug("Creating default column for {}", input);
return column(input);
}
};
}
private static Function<String, Column.Builder> typeColumn(final Class<?> type, final CellProcessor processor) {
return new Function<String, Column.Builder>() {
@Nullable
@Override
public Column.Builder apply(@Nullable String input) {
Column.Builder builder = column(input).type(type);
if (processor != null) {
builder.processor(processor);
}
return builder;
}
};
}
private static Function<String, Column.Builder> typeColumn(final Class<?> type) {
return typeColumn(type, null);
}
@Override
public Column getColumnDefinitionForHeader(String header) {
for (Pattern pattern : config.keySet()) {
Matcher matcher = pattern.matcher(header);
while (matcher.find()) {
String value = matcher.group();
Column.Builder builder = config.get(pattern).apply(value);
if (builder != null) {
return builder.build();
}
}
}
return null;
}
}