package org.openlca.io.olca;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.openlca.core.database.IDatabase;
import org.openlca.core.database.NativeSql;
import org.openlca.core.model.Flow;
import org.openlca.core.model.Process;
import org.openlca.core.model.ProcessLink;
import org.openlca.core.model.ProductSystem;
import org.openlca.core.model.Unit;
import org.openlca.util.RefIdMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import gnu.trove.map.hash.TLongDoubleHashMap;
/**
* Maps the process IDs and IDs of the product system links.
*/
class ProductSystemLinks {
private Logger log = LoggerFactory.getLogger(getClass());
private IDatabase sourceDb;
private IDatabase destDb;
private ProductSystem system;
private RefIdMap<Long, String> srcIdMap;
private RefIdMap<String, Long> destIdMap;
public static void map(IDatabase sourceDb, IDatabase destDb,
ProductSystem system) {
if (sourceDb == null || destDb == null || system == null)
return;
new ProductSystemLinks(sourceDb, destDb, system).map();
}
private ProductSystemLinks(IDatabase sourceDb, IDatabase destDb,
ProductSystem system) {
this.sourceDb = sourceDb;
this.destDb = destDb;
this.system = system;
srcIdMap = RefIdMap.internalToRef(sourceDb, Process.class, Flow.class,
Unit.class);
destIdMap = RefIdMap.refToInternal(destDb, Process.class, Flow.class,
Unit.class);
}
private long destId(Class<?> type, long sourceId) {
if (sourceId == 0)
return 0;
String refId = srcIdMap.get(type, sourceId);
if (refId == null)
return 0;
Long destId = destIdMap.get(type, refId);
return destId == null ? 0 : destId;
}
private void map() {
mapProcessIds();
for (ProcessLink link : system.getProcessLinks()) {
link.providerId = destId(Process.class, link.providerId);
link.processId = destId(Process.class, link.processId);
link.flowId = destId(Flow.class, link.flowId);
Ex ex = new Ex(link.exchangeId);
link.exchangeId = ex.map().id;
}
}
private void mapProcessIds() {
List<Long> destProcessIds = new ArrayList<>();
for (Long id : system.getProcesses()) {
destProcessIds.add(destId(Process.class, id));
}
system.getProcesses().clear();
system.getProcesses().addAll(destProcessIds);
}
private class Ex {
long id;
long processId;
long flowId;
long unitId;
int isInput;
double amount;
long providerId;
Ex(long id) {
init(id);
}
void init(long id) {
this.id = id;
String sql = "SELECT f_owner, f_flow, f_unit, is_input, "
+ "resulting_amount_value, f_default_provider "
+ "from tbl_exchanges where id=" + id;
try {
NativeSql.on(sourceDb).query(sql, r -> {
processId = r.getLong(1);
flowId = r.getLong(2);
unitId = r.getLong(3);
isInput = r.getBoolean(4) ? 1 : 0;
amount = r.getDouble(5);
providerId = r.getLong(6);
return false;
});
} catch (Exception e) {
log.error("failed to query exchange: " + sql, e);
}
}
Ex map() {
processId = destId(Process.class, processId);
flowId = destId(Flow.class, flowId);
unitId = destId(Unit.class, unitId);
providerId = destId(Process.class, providerId);
findMatch();
return this;
}
void findMatch() {
id = 0;
String sql = "select id, resulting_amount_value from tbl_exchanges "
+ "where f_owner=" + processId + " and f_flow=" + flowId
+ " and f_unit=" + unitId + " and f_default_provider="
+ providerId + " and is_input=" + isInput;
try {
id = queryId(sql);
} catch (Exception e) {
Logger log = LoggerFactory.getLogger(getClass());
log.error("failed to search exchange: " + sql, e);
id = -1;
}
}
long queryId(String sql) throws SQLException {
TLongDoubleHashMap vals = new TLongDoubleHashMap();
NativeSql.on(destDb).query(sql, r -> {
vals.put(r.getLong(1), r.getDouble(2));
return true;
});
long exchangeId = -1;
double delta = 0;
for (long id : vals.keys()) {
double dist = Math.abs(amount - vals.get(id));
if (exchangeId == -1 || dist < delta) {
exchangeId = id;
delta = dist;
}
}
return exchangeId;
}
}
}