package org.openlca.io.xls.process.input;
import org.apache.poi.ss.usermodel.Sheet;
import org.openlca.core.model.AllocationFactor;
import org.openlca.core.model.AllocationMethod;
import org.openlca.core.model.Exchange;
import org.openlca.core.model.Flow;
import org.openlca.core.model.FlowType;
import org.openlca.core.model.Process;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
class AllocationSheet {
private Logger log = LoggerFactory.getLogger(getClass());
private final Config config;
private final Process process;
private final Sheet sheet;
private AllocationSheet(Config config) {
this.config = config;
this.process = config.process;
this.sheet = config.workbook.getSheet("Allocation");
}
public static void read(Config config) {
new AllocationSheet(config).read();
}
private void read() {
if (sheet == null || process == null)
return;
try {
List<Exchange> products = selectProducts();
if (products.size() <= 1) {
log.trace("process is not a multi-output process "
+ "-> no allocation factors imported");
return;
}
log.trace("read allocation factors");
readDefaultMethod();
readFactors(products);
readCausalFactors(products);
} catch (Exception e) {
log.error("failed to read allocation factors", e);
}
}
private void readDefaultMethod() {
String methodString = config.getString(sheet, 1, 1);
AllocationMethod method = getMethod(methodString);
process.setDefaultAllocationMethod(method);
}
private AllocationMethod getMethod(String string) {
if (string == null)
return AllocationMethod.NONE;
switch (string.trim().toLowerCase()) {
case "causal":
return AllocationMethod.CAUSAL;
case "economic":
return AllocationMethod.ECONOMIC;
case "physical":
return AllocationMethod.PHYSICAL;
default:
return AllocationMethod.NONE;
}
}
private void readFactors(List<Exchange> products) {
int row = 4;
while (true) {
AllocationFactor[] factors = readRowFactors(row, products);
if (factors == null)
break;
process.getAllocationFactors().add(factors[0]);
process.getAllocationFactors().add(factors[1]);
row++;
}
}
private AllocationFactor[] readRowFactors(int row, List<Exchange> products) {
String name = config.getString(sheet, row, 0);
Exchange product = getProduct(name, products);
if (product == null)
return null;
AllocationFactor[] factors = new AllocationFactor[2];
factors[0] = new AllocationFactor();
factors[0].setProductId(product.getFlow().getId());
factors[0].setValue(config.getDouble(sheet, row, 2));
factors[0].setAllocationType(AllocationMethod.PHYSICAL);
factors[1] = new AllocationFactor();
factors[1].setProductId(product.getFlow().getId());
factors[1].setValue(config.getDouble(sheet, row, 3));
factors[1].setAllocationType(AllocationMethod.ECONOMIC);
return factors;
}
private void readCausalFactors(List<Exchange> products) {
int causalStartRow = findCausalStartRow();
if (causalStartRow == -1)
return;
HashMap<Integer, Long> map = getProductColumnMap(causalStartRow,
products);
int row = causalStartRow + 2;
while (true) {
Exchange exchange = getFactorExchange(row);
if (exchange == null)
break;
createCausalFactors(row, exchange, map);
row++;
}
}
private void createCausalFactors(int row, Exchange exchange,
HashMap<Integer, Long> productColumnMap) {
for (Integer col : productColumnMap.keySet()) {
Long productId = productColumnMap.get(col);
if (col == null || productId == null)
continue;
AllocationFactor factor = new AllocationFactor();
factor.setAllocationType(AllocationMethod.CAUSAL);
factor.setProductId(productId);
factor.setValue(config.getDouble(sheet, row, col));
factor.setExchange(exchange);
process.getAllocationFactors().add(factor);
}
}
private Exchange getFactorExchange(int row) {
String name = config.getString(sheet, row, 0);
if (name == null)
return null;
String category = config.getString(sheet, row, 1);
Flow flow = config.refData.getFlow(name, category);
String direction = config.getString(sheet, row, 2);
if (flow == null || direction == null)
return null;
boolean input = direction.equalsIgnoreCase("Input");
for (Exchange exchange : process.getExchanges()) {
if (exchange.isInput() == input
&& Objects.equals(exchange.getFlow(), flow))
return exchange;
}
return null;
}
private int findCausalStartRow() {
int row = 5;
while (row < 500) {
String s = config.getString(sheet, row, 0);
if (s != null && s.equalsIgnoreCase("Causal allocation"))
return row;
row++;
}
return -1;
}
private HashMap<Integer, Long> getProductColumnMap(int causalStartRow,
List<Exchange> products) {
HashMap<Integer, Long> map = new HashMap<>();
int row = causalStartRow + 1;
int col = 4;
while (col < 500) {
String name = config.getString(sheet, row, col);
Exchange product = getProduct(name, products);
if (product == null)
break;
map.put(col, product.getFlow().getId());
col++;
}
return map;
}
private List<Exchange> selectProducts() {
List<Exchange> products = new ArrayList<>();
for (Exchange exchange : config.process.getExchanges()) {
if (exchange.isInput() || exchange.getFlow() == null)
continue;
if (exchange.getFlow().getFlowType() == FlowType.PRODUCT_FLOW)
products.add(exchange);
}
return products;
}
private Exchange getProduct(String name, List<Exchange> products) {
if (name == null)
return null;
for (Exchange exchange : products) {
String flowName = exchange.getFlow().getName();
if (flowName == null)
continue;
if (name.equalsIgnoreCase(flowName))
return exchange;
}
log.warn("no output product found for name {}", name);
return null;
}
}