package org.molgenis.data.mapper.service.impl;
import org.molgenis.data.DataService;
import org.molgenis.data.meta.model.Attribute;
import org.molgenis.data.semanticsearch.explain.bean.ExplainedAttribute;
import org.molgenis.data.support.QueryImpl;
import org.molgenis.js.magma.JsMagmaScriptRunner;
import org.molgenis.script.Script;
import org.molgenis.script.ScriptParameter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import static java.util.Objects.requireNonNull;
import static org.molgenis.script.ScriptMetaData.SCRIPT;
import static org.molgenis.script.ScriptMetaData.TYPE;
@Service
public class AlgorithmTemplateServiceImpl implements AlgorithmTemplateService
{
private final DataService dataService;
@Autowired
public AlgorithmTemplateServiceImpl(DataService dataService)
{
this.dataService = requireNonNull(dataService);
}
@Override
public Stream<AlgorithmTemplate> find(Map<Attribute, ExplainedAttribute> attrMatches)
{
// get all algorithm templates
Stream<Script> jsScripts = dataService
.findAll(SCRIPT, new QueryImpl<Script>().eq(TYPE, JsMagmaScriptRunner.NAME), Script.class);
// select all algorithm templates that can be used with target and sources
return jsScripts.flatMap(script -> toAlgorithmTemplate(script, attrMatches));
}
private Stream<AlgorithmTemplate> toAlgorithmTemplate(Script script,
Map<Attribute, ExplainedAttribute> attrMatches)
{
// find attribute for each parameter
boolean paramMatch = true;
Map<String, String> model = new HashMap<>();
for (ScriptParameter param : script.getParameters())
{
Attribute attr = mapParamToAttribute(param, attrMatches);
if (attr != null)
{
model.put(param.getName(), attr.getName());
}
else
{
paramMatch = false;
break;
}
}
// create algorithm template if an attribute was found for all parameters
AlgorithmTemplate algorithmTemplate = new AlgorithmTemplate(script, model);
return paramMatch ? Stream.of(algorithmTemplate) : Stream.empty();
}
private Attribute mapParamToAttribute(ScriptParameter param,
Map<Attribute, ExplainedAttribute> attrMatches)
{
return attrMatches.entrySet().stream().filter(entry -> !entry.getValue().getExplainedQueryStrings().isEmpty())
.filter(entry -> StreamSupport.stream(entry.getValue().getExplainedQueryStrings().spliterator(), false)
.allMatch(explain -> explain.getTagName().equalsIgnoreCase(param.getName())))
.map(entry -> entry.getKey()).findFirst().orElse(null);
}
}