package org.aksw.sparqlify.inverse;
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.aksw.jena_sparql_api.normal_form.Clause;
import org.aksw.jena_sparql_api.normal_form.NestedNormalForm;
import org.aksw.jena_sparql_api.restriction.RestrictionManagerImpl;
import org.aksw.jena_sparql_api.utils.ExprUtils;
import org.aksw.jena_sparql_api.utils.QuadUtils;
import org.aksw.jena_sparql_api.views.VarDefinition;
import org.aksw.jena_sparql_api.views.ViewQuad;
import org.aksw.sparqlify.algebra.sql.exprs2.S_ColumnRef;
import org.aksw.sparqlify.algebra.sql.exprs2.SqlExpr;
import org.aksw.sparqlify.algebra.sql.exprs2.SqlExprFunction;
import org.aksw.sparqlify.algebra.sql.nodes.SqlOp;
import org.aksw.sparqlify.algebra.sql.nodes.SqlOpTable;
import org.aksw.sparqlify.core.TypeToken;
import org.aksw.sparqlify.core.algorithms.CandidateViewSelectorSparqlify;
import org.aksw.sparqlify.core.algorithms.MappingOpsImpl;
import org.aksw.sparqlify.core.cast.SqlValue;
import org.aksw.sparqlify.core.domain.input.ViewDefinition;
import org.aksw.sparqlify.core.interfaces.SqlTranslator;
import org.apache.jena.graph.Node;
import org.apache.jena.sparql.core.Quad;
import org.apache.jena.sparql.core.Var;
import org.apache.jena.sparql.expr.E_Equals;
import org.apache.jena.sparql.expr.Expr;
import org.apache.jena.sparql.expr.ExprList;
import org.apache.jena.sparql.expr.ExprVar;
import org.apache.jena.sparql.expr.NodeValue;
public class SparqlSqlInverseMapperImpl
implements SparqlSqlInverseMapper
{
private CandidateViewSelectorSparqlify candidateViewSelector;
private SqlTranslator sqlTranslator;
public SparqlSqlInverseMapperImpl(CandidateViewSelectorSparqlify candidateViewSelector, SqlTranslator sqlTranslator) {
this.candidateViewSelector = candidateViewSelector;
this.sqlTranslator = sqlTranslator;
}
// public static List<Sq$lExpr> swapVarFirst(List<SqlExpr> sqlExpr) {
//
// }
@Override
public List<SparqlSqlInverseMap> map(Quad quad) {
Set<ViewQuad<ViewDefinition>> viewQuads = getCandidateViews(candidateViewSelector, quad);
List<SparqlSqlInverseMap> result = new ArrayList<SparqlSqlInverseMap>();
/*
* For each view-quad: Try to figure out, what values the
* underlying table needs no have in order to yield the quad.
*/
for(ViewQuad<ViewDefinition> viewQuad : viewQuads) {
ViewDefinition viewDef = viewQuad.getView();
VarDefinition varDef = viewDef.getMapping().getVarDefinition();
Map<String, TypeToken> typeMap = viewDef.getMapping().getSqlOp().getSchema().getTypeMap();
//ViewDefinitionNormalizer viewDefNormalizer = new ViewDefinitionNormalizer();
//ViewDefinition viewDef = viewDefNormalizer.normalize(tmpViewDef);
// Retrieve the view's table
SqlOp tmpTable = viewDef.getMapping().getSqlOp();
if(!(tmpTable instanceof SqlOpTable)) {
throw new RuntimeException("Not supported: " + tmpTable);
}
//SqlOpTable table = (SqlOpTable)tmpTable;
//table.g
Quad q = viewQuad.getQuad();
ExprList exprs = new ExprList();
for(int i = 0; i < 4; ++i) {
Node n = QuadUtils.getNode(q, i);
if(!n.isVariable()) {
continue;
}
Var v = (Var)n;
Node insertNode = QuadUtils.getNode(quad, i);
if(insertNode.isVariable() || insertNode.isBlank()) {
continue;
}
//exprs.add(new E_Equals(NodeValue.makeNode(quad.getSubject()), NodeValue.makeNode(insertQuad.getSubject())));
exprs.add(new E_Equals(new ExprVar(v), NodeValue.makeNode(insertNode)));
}
Expr condition = ExprUtils.andifyBalanced(exprs);
// System.out.println("Condition: " + condition);
// System.out.println("VarDef : " + varDef);
/*
*
*/
List<SqlExpr> sqlExprs = MappingOpsImpl.createSqlConditionItems(condition, varDef, typeMap, sqlTranslator);
Map<S_ColumnRef, SqlValue> columnToValue = new HashMap<S_ColumnRef, SqlValue>();
for(SqlExpr sqlExpr : sqlExprs) {
List<SqlExpr> args = sqlExpr.getArgs();
SqlExpr left = args.get(0);
SqlExpr right = args.get(1);
// Get rid of redundant expression items (such as conversion from string to string)
// TODO Move this to a generic optimization function
if(left.isFunction()) {
SqlExprFunction fn = left.asFunction();
if(fn.getName().equals("str@str")) {
left = fn.getArgs().get(0);
}
}
if(left.isConstant()) {
SqlExpr tmp = right;
right = left;
left = tmp;
}
if(!left.isVariable()) {
throw new RuntimeException("Variable expected, instead got: " + left);
}
if(!right.isConstant()) {
throw new RuntimeException("Variable expected, instead got: " + right);
}
S_ColumnRef columnRef = (S_ColumnRef)left.asVariable();
SqlValue sqlValue = right.asConstant().getValue();
//System.out.println(" " + left.getClass() + ", " + right.getClass());
columnToValue.put(columnRef, sqlValue);
}
SparqlSqlInverseMap inverseMap = new SparqlSqlInverseMap(quad, viewDef, viewQuad.getQuad(), columnToValue);
result.add(inverseMap);
}
return result;
}
/**
* Utility function that returns the set of candidate views for
* a variable-free quad.
*
* @param candidateSelector
* @param quad
* @return
*/
public static Set<ViewQuad<ViewDefinition>> getCandidateViews(CandidateViewSelectorSparqlify candidateSelector, Quad quad) {
Var g = Var.alloc("g");
Var s = Var.alloc("s");
Var p = Var.alloc("p");
Var o = Var.alloc("o");
Node gv = quad.getGraph();
Node sv = quad.getSubject();
Node pv = quad.getPredicate();
Node ov = quad.getObject();
Quad tmpQuad = new Quad(g, s, p, o);
RestrictionManagerImpl r = new RestrictionManagerImpl();
/*
ExprList exprs = new ExprList();
exprs.add(new E_Equals(new ExprVar(g), NodeValue.makeNode(gv)));
exprs.add(new E_Equals(new ExprVar(s), NodeValue.makeNode(sv)));
exprs.add(new E_Equals(new ExprVar(p), NodeValue.makeNode(pv)));
exprs.add(new E_Equals(new ExprVar(o), NodeValue.makeNode(ov)));
Clause clause = new Clause(new HashSet<Expr>(exprs.getList()));
*/
/*
* Create a conjunctive normal form (literals ORed, clauses ANDed),
* with one clause for constraint of {g, s, p, o}
*/
Set<Clause> clauses = new HashSet<Clause>();
Var[] vars = new Var[]{g, s, p, o};
Node[] nodes = new Node[]{gv, sv, pv, ov};
for(int i = 0; i < 4; ++i) {
Var v = vars[i];
Node n = nodes[i];
if(!n.isVariable() && !n.isBlank()) {
clauses.add(new Clause(new E_Equals(new ExprVar(v), NodeValue.makeNode(n))));
}
}
/*
clauses.add(new Clause(new E_Equals(new ExprVar(g), NodeValue.makeNode(gv))));
clauses.add(new Clause(new E_Equals(new ExprVar(s), NodeValue.makeNode(sv))));
clauses.add(new Clause(new E_Equals(new ExprVar(p), NodeValue.makeNode(pv))));
clauses.add(new Clause(new E_Equals(new ExprVar(o), NodeValue.makeNode(ov))));
*/
NestedNormalForm nnf = new NestedNormalForm(clauses);
r.stateCnf(nnf);
/*
* BUG: stating a Node does not change the CNF (should it do that?)
r.stateNode(g, gv);
r.stateNode(s, sv);
r.stateNode(p, pv);
r.stateNode(o, ov);
*/
// TODO The quad may only consist of variables....
Set<ViewQuad<ViewDefinition>> result = candidateSelector.findCandidates(tmpQuad, r);
return result;
}
}