package org.openlca.core.database.references;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.openlca.core.database.IDatabase;
import org.openlca.core.database.ParameterDao;
import org.openlca.core.model.Category;
import org.openlca.core.model.Parameter;
import org.openlca.core.model.ParameterScope;
import org.openlca.core.model.descriptors.ParameterDescriptor;
import org.openlca.util.Formula;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ParameterReferenceSearch extends BaseReferenceSearch<ParameterDescriptor> {
private final static Logger log = LoggerFactory.getLogger(ParameterReferenceSearch.class);
private final static Ref[] references = {
new Ref(Category.class, "category", "f_category", true)
};
public ParameterReferenceSearch(IDatabase database, boolean includeOptional) {
super(database, Parameter.class, includeOptional);
}
@Override
public List<Reference> findReferences(Set<Long> ids) {
List<Reference> results = new ArrayList<>();
results.addAll(findReferences("tbl_parameters", "id", ids, references));
results.addAll(findParameterReferences(ids));
return results;
}
private List<Reference> findParameterReferences(Set<Long> ids) {
List<String> formulaQueries = Search.createQueries("SELECT id, lower(formula) FROM tbl_parameters"
, "WHERE id IN", ids);
Map<Long, Set<String>> variables = getVariablesUsedInFormulas(formulaQueries);
Set<String> names = new HashSet<>();
for (Set<String> n : variables.values())
names.addAll(n);
List<Reference> results = new ArrayList<>();
List<ParameterDescriptor> descriptors = new ParameterDao(database)
.getDescriptors(names.toArray(new String[names.size()]),
ParameterScope.GLOBAL);
results.addAll(toReferences(descriptors, false, variables, null));
Set<String> found = new HashSet<>();
for (ParameterDescriptor d : descriptors)
found.add(d.getName());
for (String name : names)
if (!found.contains(name)) {
Reference ref = createMissingReference(name, variables);
if (ref != null)
results.add(ref);
}
return results;
}
private Reference createMissingReference(String name,
Map<Long, Set<String>> ownerToNames) {
for (long ownerId : ownerToNames.keySet())
if (ownerToNames.get(ownerId).contains(name))
return new Reference("", Parameter.class, 0, Parameter.class, ownerId);
return null;
}
protected Map<Long, Set<String>> getVariablesUsedInFormulas(List<String> formulaQueries) {
Map<Long, Set<String>> variables = new HashMap<>();
for (String formulaQuery : formulaQueries)
Search.on(database, null).query(formulaQuery, (result) -> {
long ownerId = result.getLong(1);
Set<String> set = variables.get(ownerId);
if (set == null)
variables.put(ownerId, set = new HashSet<>());
try {
set.addAll(Formula.getVariables(result.getString(2)));
} catch (Throwable e) {
log.warn("Failed parsing formula of parameter in model " + ownerId, e);
}
});
return variables;
}
}