package org.aksw.sparqlify.sparqlview;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.aksw.commons.collections.multimaps.IBiSetMultimap;
import org.aksw.jena_sparql_api.views.SparqlView;
import org.aksw.jena_sparql_api.views.VarBinding;
import org.aksw.jena_sparql_api.views.VarsMentioned;
import org.aksw.jena_sparql_api.views.ViewInstance;
import org.aksw.sparqlify.database.GetVarsMentioned;
import org.apache.jena.atlas.io.IndentedWriter;
import org.apache.jena.graph.Node;
import org.apache.jena.sparql.algebra.Op;
import org.apache.jena.sparql.algebra.op.OpExt;
import org.apache.jena.sparql.algebra.op.OpExtend;
import org.apache.jena.sparql.algebra.op.OpJoin;
import org.apache.jena.sparql.core.Var;
import org.apache.jena.sparql.core.VarExprList;
import org.apache.jena.sparql.engine.ExecutionContext;
import org.apache.jena.sparql.engine.QueryIterator;
import org.apache.jena.sparql.expr.Expr;
import org.apache.jena.sparql.expr.ExprVar;
import org.apache.jena.sparql.expr.NodeValue;
import org.apache.jena.sparql.serializer.SerializationContext;
import org.apache.jena.sparql.util.NodeIsomorphismMap;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.SetMultimap;
public class OpSparqlViewPattern
extends OpExt
implements VarsMentioned
{
private ViewInstanceJoin<SparqlView> conjunction;
public OpSparqlViewPattern(ViewInstanceJoin<SparqlView> conjunction) {
super(OpSparqlViewPattern.class.getSimpleName());
this.conjunction = conjunction;
}
/*
public OpRdfViewPattern() {
super(OpRdfUnionViewPattern.class.getName());
this.conjunction = new ArrayList<RdfViewConjunction>();
}*/
public ViewInstanceJoin<SparqlView> getConjunction() {
return conjunction;
}
@Override
public Op effectiveOp() {
Op a = null;
Op b = null;
for(ViewInstance<SparqlView> instance : conjunction.getViewInstances()) {
b = instance.getViewDefinition().getOp();
//Map<Node, N>
//Map<Var, Collection<Var>> viewToQueryVar = conjunction.getCompleteBinding().getEquiMap().getEquivalences().getInverse().asMap();
//instance.getRenamer()
Map<Var, Var> renamer = new HashMap<Var, Var>();
// TODO I think we don't need constraints here???
Set<Expr> constraints = new HashSet<Expr>();
// The same view variable might server multiple query variables
SetMultimap<Var, Var> extraProjection = HashMultimap.create();
//Multimap<Var, Var> src = instance.getVarDefinition();
VarBinding varBinding = instance.getBinding();
//SetMultimap<Var, Var> src = instance.getQueryToParentBinding();
//SetMultimap<Var, Var> dest = HashMultimap.create();
IBiSetMultimap<Var, Var> dest = varBinding.getViewVarToQueryVars();
//Multimaps.invertFrom(src, dest);
for(Entry<Var, Collection<Var>> entry : dest.asMap().entrySet()) {
// Add equals constraint if multiple view variables map to the same query variable
Var x = null;
for(Var y : entry.getValue()) {
if(x == null) {
x = y;
continue;
}
//constraints.add(new E_Equals(new ExprVar(x), new ExprVar(y)));
extraProjection.put(x, y);
}
// Rename the view variable to the query variable
renamer.put(entry.getKey(), x);
}
SparqlView renamed = instance.getViewDefinition().copyRenameVars(renamer); //NodeTransformLib.transform(renamer, op);
b = renamed.getOp();
//Op
VarExprList veList = new VarExprList();
Map<Var, Node> keyToValue = varBinding.getQueryVarToConstant();
if(!extraProjection.isEmpty() || !keyToValue.isEmpty()) {
//b = OpFilter.filter(new ExprList(new ArrayList<Expr>(constraints)), b);
for(Entry<Var, Var> entry : extraProjection.entries()) {
//veList.add(entry.getKey(), new ExprVar(entry.getValue()));
veList.add(entry.getValue(), new ExprVar(entry.getKey()));
}
for(Entry<Var, Node> entry : keyToValue.entrySet()) {
/*
if(entry.getValue().equals(Quad.defaultGraphNodeGenerated)) {
System.out.println("[Hack] Discarding default graph URI constraint, although it might affect a SPARQL variable in non-graph position");
continue;
}*/
Node node = entry.getValue();
if(node != null) {
veList.add(entry.getKey(), NodeValue.makeNode(node));
}
//veList.add(entry.getKey(), NodeValue.makeNode(entry.getValue()));
}
if(!veList.isEmpty()) {
b = OpExtend.extend(b, veList);
}
}
//System.out.println(renamed);
if(a == null) {
a = b;
continue;
}
a = OpJoin.create(a, b);
}
return a;
}
@Override
public QueryIterator eval(QueryIterator input, ExecutionContext execCxt) {
// TODO Auto-generated method stub
return null;
}
@Override
public void outputArgs(IndentedWriter out, SerializationContext sCxt) {
/*
* out.print("'''") ; sqlNode.output(out) ; out.print("'''") ;
*/
out.print(conjunction.getViewNames() + " " + conjunction.getRestrictions() + " " + conjunction);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((conjunction == null) ? 0 : conjunction.hashCode());
return result;
}
@Override
public boolean equalTo(Op obj, NodeIsomorphismMap labelMap)
{
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
OpSparqlViewPattern other = (OpSparqlViewPattern) obj;
if (conjunction == null) {
if (other.conjunction != null)
return false;
} else if (!conjunction.equals(other.conjunction))
return false;
return true;
}
@Override
public Set<Var> varsMentioned() {
return GetVarsMentioned.getVarsMentioned(effectiveOp());
}
}