package org.openlca.io.ecospold1.input;
import java.util.HashMap;
import java.util.Map;
import org.openlca.core.model.Category;
import org.openlca.core.model.Flow;
import org.openlca.core.model.FlowPropertyFactor;
import org.openlca.core.model.FlowType;
import org.openlca.core.model.ModelType;
import org.openlca.core.model.Unit;
import org.openlca.core.model.UnitGroup;
import org.openlca.ecospold.IExchange;
import org.openlca.ecospold.IReferenceFunction;
import org.openlca.ecospold.io.DataSet;
import org.openlca.util.KeyGen;
import org.openlca.io.UnitMapping;
import org.openlca.io.UnitMappingEntry;
import org.openlca.io.maps.FlowMap;
import org.openlca.io.maps.FlowMapEntry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Returns flows from the database or creates them using unit- and
* flow-mappings. Flows can be imported from EcoSpold 1 exchanges representing
* process inputs or outputs, exchanges representing impact assessment factors,
* or reference functions of processes.
*/
class FlowImport {
private Logger log = LoggerFactory.getLogger(getClass());
private DB db;
private UnitMapping unitMapping;
private FlowMap flowMap;
private Map<String, FlowBucket> cache = new HashMap<>();
public FlowImport(DB db, UnitMapping unitMapping, FlowMap flowMap) {
this.db = db;
this.unitMapping = unitMapping;
this.flowMap = flowMap;
}
/** Import a flow from a process import or export. */
public FlowBucket handleProcessExchange(IExchange exchange) {
String flowKey = ES1KeyGen.forFlow(exchange);
return handleExchange(flowKey, exchange);
}
/** Import a flow from an impact assessment factor. */
public FlowBucket handleImpactFactor(IExchange exchange) {
String flowKey = ES1KeyGen.forElementaryFlow(exchange);
return handleExchange(flowKey, exchange);
}
/** Import a flow from an exchange. */
private FlowBucket handleExchange(String flowKey, IExchange exchange) {
FlowBucket cached = getCachedOrMapped(flowKey);
if (cached != null)
return cached;
FlowBucket db = getDbFlow(flowKey, exchange);
if (db != null)
return cache(flowKey, db);
Flow flow = new Flow();
flow.setRefId(flowKey);
flow.setName(exchange.getName());
mapExchangeData(exchange, flow);
String unit = exchange.getUnit();
FlowBucket created = createFlow(flowKey, flow, unit);
return cache(flowKey, created);
}
/** Import a flow from a reference function. */
public FlowBucket handleProcessProduct(DataSet dataSet) {
if (dataSet == null || dataSet.getReferenceFunction() == null)
return null;
String flowKey = ES1KeyGen.forProduct(dataSet);
FlowBucket cached = getCachedOrMapped(flowKey);
if (cached != null)
return cached;
FlowBucket db = getDbFlow(flowKey, dataSet);
if (db != null)
return cache(flowKey, db);
IReferenceFunction refFun = dataSet.getReferenceFunction();
Flow flow = new Flow();
flow.setRefId(flowKey);
flow.setName(refFun.getName());
mapDataSetData(dataSet, flow);
String unit = refFun.getUnit();
FlowBucket created = createFlow(flowKey, flow, unit);
return cache(flowKey, created);
}
/** Get a cached or mapped flow: no unit info is required. */
private FlowBucket getCachedOrMapped(String flowKey) {
FlowBucket cached = cache.get(flowKey);
if (cached != null)
return cached;
FlowBucket mapped = getMappedFlow(flowKey);
if (mapped != null)
return cache(flowKey, mapped);
return null;
}
/** Cache the bucket for the generated key. */
private FlowBucket cache(String flowKey, FlowBucket bucket) {
if (bucket == null || !bucket.isValid()) {
log.warn("Could not create valid flow {}", flowKey);
return null;
}
cache.put(flowKey, bucket);
return bucket;
}
/** Try to find a flow from the mapping tables. */
private FlowBucket getMappedFlow(String genKey) {
FlowMapEntry entry = flowMap.getEntry(genKey);
if (entry == null)
return null;
Flow flow = db.get(Flow.class, entry.getOpenlcaFlowKey());
if (flow == null)
return null;
FlowBucket bucket = new FlowBucket();
bucket.conversionFactor = entry.getConversionFactor();
bucket.flow = flow;
bucket.flowProperty = flow.getReferenceFactor();
Unit unit = getReferenceUnit(bucket.flowProperty);
bucket.unit = unit;
if (!bucket.isValid()) {
log.warn("invalid flow mapping for {}", genKey);
return null;
}
return bucket;
}
private Unit getReferenceUnit(FlowPropertyFactor flowProperty) {
if (flowProperty == null || flowProperty.getFlowProperty() == null)
return null;
UnitGroup group = flowProperty.getFlowProperty().getUnitGroup();
if (group == null)
return null;
return group.getReferenceUnit();
}
private FlowBucket getDbFlow(String flowKey, IExchange inExchange) {
Flow flow = db.findFlow(inExchange, flowKey,
unitMapping.getEntry(inExchange.getUnit()));
if (flow == null)
return null;
return createBucket(flow, inExchange.getUnit());
}
private FlowBucket getDbFlow(String flowKey, DataSet dataSet) {
if (dataSet.getReferenceFunction() == null)
return null;
IReferenceFunction refFun = dataSet.getReferenceFunction();
Flow flow = db.findFlow(dataSet, flowKey,
unitMapping.getEntry(refFun.getUnit()));
if (flow == null)
return null;
return createBucket(flow, refFun.getUnit());
}
private void mapExchangeData(IExchange inExchange, Flow flow) {
flow.setCasNumber(inExchange.getCASNumber());
flow.setFormula(inExchange.getFormula());
if (inExchange.isInfrastructureProcess() != null)
flow.setInfrastructureFlow(inExchange.isInfrastructureProcess());
Category flowCategory = db.getPutCategory(ModelType.FLOW,
inExchange.getCategory(), inExchange.getSubCategory());
if (flowCategory != null)
flow.setCategory(flowCategory);
String locationCode = inExchange.getLocation();
if (locationCode != null) {
String locKey = KeyGen.get(locationCode);
flow.setLocation(db.findLocation(locationCode, locKey));
}
FlowType flowType = Mapper.getFlowType(inExchange);
flow.setFlowType(flowType);
}
private void mapDataSetData(DataSet dataset, Flow flow) {
IReferenceFunction refFun = dataset.getReferenceFunction();
flow.setCasNumber(refFun.getCASNumber());
flow.setFormula(refFun.getFormula());
Category flowCategory = db.getPutCategory(ModelType.FLOW,
refFun.getCategory(), refFun.getSubCategory());
if (flowCategory != null)
flow.setCategory(flowCategory);
if (dataset.getGeography() != null
&& dataset.getGeography().getLocation() != null) {
String code = dataset.getGeography().getLocation();
String locKey = KeyGen.get(code);
flow.setLocation(db.findLocation(code, locKey));
}
flow.setFlowType(FlowType.PRODUCT_FLOW);
}
/** Creates a new flow and inserts it in the database. */
private FlowBucket createFlow(String flowKey, Flow flow, String unit) {
UnitMappingEntry entry = unitMapping.getEntry(unit);
if (entry == null || !entry.isValid())
return null;
flow.setReferenceFlowProperty(entry.flowProperty);
FlowPropertyFactor factor = new FlowPropertyFactor();
factor.setFlowProperty(entry.flowProperty);
factor.setConversionFactor(1.0);
flow.getFlowPropertyFactors().add(factor);
db.put(flow, flowKey);
return createBucket(flow, unit);
}
/** Create the flow bucket for the given flow and unit. */
private FlowBucket createBucket(Flow flow, String unit) {
UnitMappingEntry mapEntry = unitMapping.getEntry(unit);
if (mapEntry == null || !mapEntry.isValid())
return null;
FlowPropertyFactor factor = flow.getFactor(mapEntry.flowProperty);
if (factor == null) {
log.error("The unit/property for flow {}/{} "
+ "changed in the database", flow, unit);
return null;
}
FlowBucket bucket = new FlowBucket();
bucket.conversionFactor = 1.0;
bucket.flow = flow;
bucket.flowProperty = factor;
bucket.unit = mapEntry.unit;
return bucket;
}
}