package org.aksw.jena_sparql_api.utils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.aksw.commons.collections.MapUtils;
import org.aksw.jena_sparql_api.backports.syntaxtransform.ElementTransform;
import org.aksw.jena_sparql_api.backports.syntaxtransform.ExprTransformNodeElement;
import org.apache.jena.graph.Node;
import org.apache.jena.graph.Triple;
import org.apache.jena.sparql.algebra.Op;
import org.apache.jena.sparql.algebra.OpVars;
import org.apache.jena.sparql.core.BasicPattern;
import org.apache.jena.sparql.core.TriplePath;
import org.apache.jena.sparql.core.Var;
import org.apache.jena.sparql.expr.Expr;
import org.apache.jena.sparql.expr.ExprTransform;
import org.apache.jena.sparql.graph.NodeTransform;
import org.apache.jena.sparql.syntax.Element;
import org.apache.jena.sparql.syntax.ElementFilter;
import org.apache.jena.sparql.syntax.ElementGroup;
import org.apache.jena.sparql.syntax.ElementPathBlock;
import org.apache.jena.sparql.syntax.ElementTriplesBlock;
import org.apache.jena.sparql.syntax.ElementUnion;
import org.apache.jena.sparql.syntax.PatternVars;
//import org.apache.jena.sparql.syntax.syntaxtransform.ElementTransform;
//import org.apache.jena.sparql.syntax.syntaxtransform.ElementTransformer;
//import org.apache.jena.sparql.syntax.syntaxtransform.ExprTransformNodeElement;
//import org.apache.jena.sparql.syntax.syntaxtransform.ElementTransform;
//import org.apache.jena.sparql.syntax.syntaxtransform.ElementTransformer;
//import org.apache.jena.sparql.syntax.syntaxtransform.ExprTransformNodeElement;
public class ElementUtils {
// public static Generator<Var> freshVars(Element element){
// Collection<Var> blacklistVars = PatternVars.vars(element);
//
// Generator<Var> gen = VarGeneratorImpl2.create("v");
// Generator<Var> result = new VarGeneratorBlacklist(gen, blacklistVars);
//
// return result;
// }
public static ElementTriplesBlock createElement(Triple triple) {
BasicPattern bgp = new BasicPattern();
bgp.add(triple);
ElementTriplesBlock result = new ElementTriplesBlock(bgp);
return result;
}
public static ElementPathBlock createElement(TriplePath triplePath) {
ElementPathBlock result = new ElementPathBlock();
result.addTriplePath(triplePath);
return result;
}
public static List<Triple> extractTriples(Element e) {
List<Triple> result = new ArrayList<Triple>();
extractTriples(e, result);
return result;
}
//public static Element join()
public static Triple extractTriple(Element e) {
//Node result = null;
Triple result = null;
if(e instanceof ElementFilter) {
ElementFilter x = (ElementFilter)e;
Expr expr = x.getExpr();
Set<Set<Expr>> cnf = CnfUtils.toSetCnf(expr);
Map<Var, Node> map = CnfUtils.getConstants(cnf);
//Node g = MapUtils.getOrElse(map, Vars.g, Node.ANY);
Node s = MapUtils.getOrElse(map, Vars.s, Node.ANY);
Node p = MapUtils.getOrElse(map, Vars.p, Node.ANY);
Node o = MapUtils.getOrElse(map, Vars.o, Node.ANY);
result = new Triple(s, p, o);
} else {
List<Triple> triples = extractTriples(e);
if(triples.size() == 1) {
result = triples.get(0);
//Triple t = triples.get(0);
//result = t.getPredicate();
}
}
return result;
}
public static void extractTriples(Element e, List<Triple> result) {
if(e instanceof ElementGroup) {
ElementGroup g = (ElementGroup)e;
for(Element item : g.getElements()) {
extractTriples(item, result);
}
} else if(e instanceof ElementTriplesBlock) {
ElementTriplesBlock b = (ElementTriplesBlock)e;
List<Triple> triples = b.getPattern().getList();
result.addAll(triples);
}
}
public static Map<Node, Var> createMapFixVarNames(Element element) {
Collection<Var> vars = PatternVars.vars(element);
Map<Node, Var> result = createMapFixVarNames(vars);
return result;
}
public static Map<Node, Var> createMapFixVarNames(Collection<Var> vars) {
//Set<Var> vars = NodeUtils.getVarsMentioned(nodes);
//Set<Node> bnodes = NodeUtils.getBnodesMentioned(vars);
Generator<Var> gen = VarGeneratorBlacklist.create("v", vars);
Map<Node, Var> result = new HashMap<Node, Var>();
// for(Node node : bnodes) {
// result.put(node, gen.next());
// }
for(Var var : vars) {
if(var.getName().startsWith("?") || var.getName().startsWith("/")) {
result.put(var, gen.next());
}
//System.out.println(var);
}
return result;
}
public static Element fixVarNames(Element element) {
Map<Node, Var> nodeMap = createMapFixVarNames(element);
NodeTransform nodeTransform = new NodeTransformRenameMap(nodeMap);
Element result = ElementUtils.applyNodeTransform(element, nodeTransform);
return result;
}
public static Element toElement(Collection<Element> elements) {
Element result;
if(elements.size() == 1) {
result = elements.iterator().next();
} else {
ElementGroup e = new ElementGroup();
for(Element element : elements) {
e.addElement(element);
}
result = e;
}
return result;
}
public static Element union(Collection<Element> elements) {
Element result;
if(elements.size() == 1) {
result = elements.iterator().next();
} else {
ElementUnion e= new ElementUnion();
for(Element element : elements) {
e.addElement(element);
}
result = e;
}
return result;
}
public static Element groupIfNeeded(Iterable<Element> members) {
ElementGroup tmp = new ElementGroup();
for(Element member : members) {
if(member != null) {
tmp.addElement(member);
}
}
Element result = flatten(tmp);
return result;
}
public static Element groupIfNeeded(Element ... members) {
Element result = groupIfNeeded(Arrays.asList(members));
return result;
}
public static ElementGroup createElementGroup(Iterable<Element> members) {
ElementGroup result = new ElementGroup();
for(Element member : members) {
result.addElement(member);
}
return result;
}
public static ElementGroup createElementGroup(Element ... members) {
ElementGroup result = new ElementGroup();
for(Element member : members) {
result.addElement(member);
}
return result;
}
public static Element createRenamedElement(Element element, Map<? extends Node, ? extends Node> nodeMap) {
NodeTransform nodeTransform = new NodeTransformRenameMap(nodeMap);
Element result = applyNodeTransform(element, nodeTransform);
return result;
}
@Deprecated // Use TransformElementLib.transform instead
public static Element applyNodeTransform(Element element, NodeTransform nodeTransform) {
org.apache.jena.sparql.syntax.syntaxtransform.ElementTransform elementTransform = new ElementTransformSubst2(nodeTransform);//new ElementTransformSubst2(nodeTransform);
ExprTransform exprTransform = new org.apache.jena.sparql.syntax.syntaxtransform.ExprTransformNodeElement(nodeTransform, elementTransform);
//Element result = ElementTransformer.transform(element, elementTransform, exprTransform);
Element result = org.apache.jena.sparql.syntax.syntaxtransform.ElementTransformer.transform(element, elementTransform, exprTransform);
return result;
}
public static void copyElements(ElementGroup target, Element source) {
if(source instanceof ElementGroup) {
ElementGroup es = (ElementGroup)source;
for(Element e : es.getElements()) {
target.addElement(e);
}
} else {
target.addElement(source);
}
}
public static void mergeElements(ElementGroup target, ElementTriplesBlock etb, Element source) {
if(source instanceof ElementTriplesBlock) {
ElementTriplesBlock e = (ElementTriplesBlock)source;
for(Triple t : e.getPattern()) {
etb.addTriple(t);
}
} else if(source instanceof ElementGroup) {
ElementGroup es = (ElementGroup)source;
for(Element e : es.getElements()) {
mergeElements(target, etb, e);
//target.addElement(e);
}
} else {
target.addElement(source);
}
}
/**
* Creates a new ElementGroup that contains the elements of the given arguments.
* Argument ElementGroups are flattened. ElementTriplesBlocks however are not combined.
*
* @param first
* @param second
* @return
*/
public static Element mergeElements(Element first, Element second) {
ElementGroup tmp = new ElementGroup();
ElementTriplesBlock etb = new ElementTriplesBlock();
tmp.addElement(etb);
mergeElements(tmp, etb, first);
mergeElements(tmp, etb, second);
// Remove empty element triple blocks
ElementGroup result = new ElementGroup();
for(Element e : tmp.getElements()) {
if((e instanceof ElementTriplesBlock) && ((ElementTriplesBlock)e).isEmpty()) {
// Skip
} else {
result.addElement(e);
}
}
return result;
}
public static Element unionElements(Element first, Element second) {
ElementUnion result = new ElementUnion();
addUnionElements(result, first);
addUnionElements(result, second);
return result;
}
public static void addUnionElements(ElementUnion out, Element e) {
if(e instanceof ElementUnion) {
ElementUnion u = (ElementUnion)e;
for(Element m : u.getElements()) {
out.addElement(m);
}
}
else if(e instanceof ElementGroup && ((ElementGroup)e).isEmpty()) {
// nothing todo
} else {
out.addElement(e);
}
}
public static List<Element> toElementList(Element element) {
List<Element> result;
if(element instanceof ElementGroup) {
result = ((ElementGroup)element).getElements();
} else {
result = Arrays.asList(element);
}
// This method always returns a copy of the elements
result = new ArrayList<Element>(result);
return result;
}
/**
* TODO This method should flatten elements recursively
*
* @param e
* @return
*/
public static Element flatten(Element e) {
Element result;
if(e instanceof ElementGroup) {
ElementGroup tmp = (ElementGroup)e;
List<Element> els = tmp.getElements();
result = els.size() == 1 ? els.get(0) : tmp;
} else {
result = e;
}
return result;
}
}