package org.aksw.jena_sparql_api.concepts;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import org.aksw.commons.collections.SetUtils;
import org.aksw.jena_sparql_api.stmt.SparqlElementParser;
import org.aksw.jena_sparql_api.stmt.SparqlElementParserImpl;
import org.aksw.jena_sparql_api.utils.ElementUtils;
import org.aksw.jena_sparql_api.utils.VarUtils;
import org.aksw.jena_sparql_api.utils.Vars;
import org.apache.jena.query.Syntax;
import org.apache.jena.sparql.core.TriplePath;
import org.apache.jena.sparql.core.Var;
import org.apache.jena.sparql.graph.NodeTransform;
import org.apache.jena.sparql.syntax.Element;
import org.apache.jena.sparql.syntax.ElementGroup;
import org.apache.jena.sparql.syntax.PatternVars;
/**
* This is a binary relation used to relate two concepts to each other
*
* @author raven
*
*/
public class Relation {
private Var sourceVar;
private Var targetVar;
private Element element;
public Relation(Element element, Var sourceVar, Var targetVar) {
this.element = element;
this.sourceVar = sourceVar;
this.targetVar = targetVar;
}
public Var getSourceVar() {
return sourceVar;
}
public Var getTargetVar() {
return targetVar;
}
public Element getElement() {
return element;
}
public Relation reverse()
{
Relation result = new Relation(element, targetVar, sourceVar);
return result;
}
public Concept getSourceConcept() {
Concept result = new Concept(element, sourceVar);
return result;
}
public Concept getTargetConcept() {
Concept result = new Concept(element, targetVar);
return result;
}
public static Relation create(String elementStr, String sourceVarName,
String targetVarName) {
SparqlElementParser parser = SparqlElementParserImpl.create(Syntax.syntaxARQ, null);
Relation result = create(elementStr, sourceVarName, targetVarName, parser);
return result;
}
public static Relation create(String elementStr, String sourceVarName,
String targetVarName, Function<String, ? extends Element> elementParser) {
Var sourceVar = Var.alloc(sourceVarName);
Var targetVar = Var.alloc(targetVarName);
String tmp = elementStr.trim();
boolean isEnclosed = tmp.startsWith("{") && tmp.endsWith("}");
if (!isEnclosed) {
tmp = "{" + tmp + "}";
}
Element element = elementParser.apply(tmp);//ParserSPARQL10.parseElement(tmp);
// TODO Find a generic flatten routine
if (element instanceof ElementGroup) {
ElementGroup group = (ElementGroup) element;
List<Element> elements = group.getElements();
if (elements.size() == 1) {
element = elements.get(0);
}
}
Relation result = new Relation(element, sourceVar, targetVar);
return result;
}
/**
* Return all vars that are neither source nor target
* @return
*/
public Set<Var> getInnerVars() {
Set<Var> result = SetUtils.asSet(PatternVars.vars(element));
result.remove(sourceVar);
result.remove(targetVar);
return result;
}
public Set<Var> getVarsMentioned() {
Set<Var> result = SetUtils.asSet(PatternVars.vars(element));
result.add(sourceVar);
result.add(targetVar);
return result;
}
public Relation applyNodeTransform(NodeTransform nodeTransform) {
Var s = VarUtils.applyNodeTransform(sourceVar, nodeTransform);
Var t = VarUtils.applyNodeTransform(targetVar, nodeTransform);
Element e = ElementUtils.applyNodeTransform(element, nodeTransform);
Relation result = new Relation(e, s, t);
return result;
}
public static Relation create(org.apache.jena.sparql.path.Path path) {
Relation result = new Relation(ElementUtils.createElement(new TriplePath(Vars.s, path, Vars.o)), Vars.s, Vars.o);
return result;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((element == null) ? 0 : element.hashCode());
result = prime * result
+ ((sourceVar == null) ? 0 : sourceVar.hashCode());
result = prime * result
+ ((targetVar == null) ? 0 : targetVar.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Relation other = (Relation) obj;
if (element == null) {
if (other.element != null)
return false;
} else if (!element.equals(other.element))
return false;
if (sourceVar == null) {
if (other.sourceVar != null)
return false;
} else if (!sourceVar.equals(other.sourceVar))
return false;
if (targetVar == null) {
if (other.targetVar != null)
return false;
} else if (!targetVar.equals(other.targetVar))
return false;
return true;
}
@Override
public String toString() {
String result = sourceVar + " " + targetVar + " | " + element;
return result;
/*
return "Relation [sourceVar=" + sourceVar + ", targetVar=" + targetVar
+ ", element=" + element + "]";
*/
}
/**
* An empty relation does is equivalent to a zero-length path, i.e.
* it navigates from a set of resources to the same set of resources.
*
* It is expressed as an empty graph pattern (ElementGroup), and
* equal variables in source and target;
*
* @return
*/
public static boolean isEmpty(Relation relation) {
boolean result;
Element e = relation.getElement();
if(e instanceof ElementGroup) {
ElementGroup g = (ElementGroup)e;
result = g.getElements().isEmpty();
//relation.getSourceVar().equals(relation.getTargetVar())
} else {
result = false;
}
return result;
}
public static Relation empty() {
return new Relation(new ElementGroup(), Vars.s, Vars.s);
}
public static Relation empty(Var var) {
return new Relation(new ElementGroup(), var, var);
}
}