package org.aksw.jena_sparql_api.views;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.aksw.jena_sparql_api.restriction.RestrictionSetImpl;
import org.apache.jena.sparql.core.Var;
import org.apache.jena.sparql.core.VarExprList;
import org.apache.jena.sparql.expr.Expr;
import org.apache.jena.sparql.expr.ExprVar;
import com.google.common.base.Function;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
/**
* A variable definition binds a set of SPARQL variables to a
* set of corresponding defining expressions
*
* A variable definition consists of a
* - a restricted expression that defines the variable
* - an optional set of restriction expressions that restricts the variables set of values //apply to the variable under this definition
*
* The expression can either be:
* - a constant NodeValue that directly associates the variable with a constant
* - an expression of type E_RdfTermCtor,
*
* - other expression types probably do not make sense here - at least I don't see use cases for them (yet).
*
* @author Claus Stader
*
*/
public class VarDefinition
// implements Cloneable
{
private Multimap<Var, RestrictedExpr> varToExprs;
public VarDefinition() {
this.varToExprs = HashMultimap.create();
}
public VarDefinition(Multimap<Var, RestrictedExpr> varToExprs) {
this.varToExprs = varToExprs;
}
public boolean isEmpty() {
return varToExprs.isEmpty();
}
public Multimap<Var, RestrictedExpr> getMap() {
return varToExprs;
}
//public Collection<RestrictedExpr<Expr>> get(Var q)
public Collection<RestrictedExpr> getDefinitions(Var viewVar) {
return varToExprs.get(viewVar);
}
/**
* In place expression transformation
*
* @param transform
*/
public void applyExprTransform(Function<Expr, Expr> transform) {
Multimap<Var, RestrictedExpr> newVarToExprs = HashMultimap.create();
for(Entry<Var, RestrictedExpr> entry : varToExprs.entries()) {
Var var = entry.getKey();
RestrictedExpr restExpr = entry.getValue();
Expr expr = restExpr.getExpr();
Expr ne = transform.apply(expr);
RestrictionSetImpl r = restExpr.getRestrictions();
RestrictedExpr nre = new RestrictedExpr(ne, r);
//entry.setValue(new );
newVarToExprs.put(var, nre);
}
varToExprs = newVarToExprs;
}
public VarDefinition copyProject(Collection<Var> viewVars) {
Multimap<Var, RestrictedExpr> map = HashMultimap.create();
for(Var var : viewVars) {
Collection<RestrictedExpr> restExprs = varToExprs.get(var);
map.putAll(var, restExprs);
}
VarDefinition result = new VarDefinition(map);
return result;
}
public VarDefinition copyExpandConstants() {
Multimap<Var, RestrictedExpr> resultMap = HashMultimap.create();
for(Entry<Var, RestrictedExpr> entry : varToExprs.entries()) {
Var var = entry.getKey();
RestrictedExpr restExpr = entry.getValue();
Expr expr = restExpr.getExpr();
//Expr expandedExpr = ConstantExpander.transform(expr);
Expr expandedExpr;
if(expr.isConstant()) {
expandedExpr = ConstantExpander._transform(expr.getConstant());
} else {
expandedExpr = expr;
}
RestrictedExpr finalExpr = new RestrictedExpr(expandedExpr, restExpr.getRestrictions());
resultMap.put(var, finalExpr);
}
VarDefinition result = new VarDefinition(resultMap);
return result;
}
public VarDefinition copyRenameVars(Map<Var, Var> oldToNew) {
Multimap<Var, RestrictedExpr> resultMap = HashMultimap.create();
for(Entry<Var, Collection<RestrictedExpr>> entry : varToExprs.asMap().entrySet()) {
Var var = entry.getKey();
Var renamedVar = oldToNew.get(var);
Var newVar = renamedVar == null ? var : renamedVar;
resultMap.putAll(newVar, entry.getValue());
}
VarDefinition result = new VarDefinition(resultMap);
return result;
}
// Some Ideas for compact syntax:
// Construct {?s rdfs:label ?name} With ?s = uri(@rdf, id) From table
// Omitting the With clause alltogether: Construct { uri(@rdf, id) rdfs:label ?name } From table --- name will become a typed literal of type string.
// FIXME This method should not be static but a real member
public static VarDefinition copyRename(VarDefinition varDef, Map<String, String> oldToNew) {
Map<Var, Expr> map = new HashMap<Var, Expr>();
for(Entry<String, String> entry : oldToNew.entrySet()) {
map.put(Var.alloc(entry.getKey()), new ExprVar(Var.alloc(entry.getValue())));
}
VarDefinition result = copySubstitute(varDef, map);
return result;
}
public VarDefinition copySubstitute(Map<Var, Expr> map) {
VarDefinition result = VarDefinition.copySubstitute(this, map);
return result;
}
public static VarDefinition copySubstitute(VarDefinition varDef, Map<Var, Expr> map) {
NodeExprSubstitutor substitutor = new NodeExprSubstitutor(map);
Multimap<Var, RestrictedExpr> newVarToExpr = HashMultimap.create();
for(Entry<Var, RestrictedExpr> entry : varDef.getMap().entries()) {
RestrictedExpr before = entry.getValue();
Expr newExpr = substitutor.transformMM(before.getExpr());
RestrictedExpr after = new RestrictedExpr(newExpr, before.getRestrictions());
newVarToExpr.put(entry.getKey(), after);
}
VarDefinition result = new VarDefinition(newVarToExpr);
return result;
}
//@Override
public VarDefinition extend(VarDefinition that) {
Multimap<Var, RestrictedExpr> map = HashMultimap.create(varToExprs);
map.putAll(that.varToExprs);
VarDefinition result = new VarDefinition(map);
return result;
}
public String toPrettyString() {
return toIndentedString(this);
}
public static String toIndentedString(VarDefinition varDef) {
Multimap<Var, RestrictedExpr> map = varDef.getMap();
String result = toIndentedString(map);
return result;
}
public List<String> getReferencedNames() {
Set<Var> tmp = getReferencedVars();
List<String> result = new ArrayList<String>(tmp.size());
for(Var var : tmp) {
String name = var.getName();
result.add(name);
}
return result;
}
public static <T extends Collection<String>> T copyVarNames(T target, Collection<Var> vars) {
for(Var var : vars) {
target.add(var.getName());
}
return target;
}
public Set<Var> getReferencedVars() {
Set<Var> result = new HashSet<Var>();
for(Entry<Var, RestrictedExpr> entry : varToExprs.entries()) {
Set<Var> tmp = entry.getValue().getExpr().getVarsMentioned();
result.addAll(tmp);
}
return result;
}
public Multimap<Var, Expr> withoutRestrictions() {
Multimap<Var, Expr> result = HashMultimap.create();
for(Entry<Var, RestrictedExpr> entry : this.varToExprs.entries()) {
result.put(entry.getKey(), entry.getValue().getExpr());
}
return result;
}
/**
* Return only the referenced vars for the given vars
*
* @param vars
* @return
*/
public Set<Var> getReferencedVars(Collection<Var> vars) {
//List<Var> result = new ArrayList<Var>();
Set<Var> result = new HashSet<Var>();
// Track all columns that contribute to the construction of SQL variables
for(Var var : vars) {
for(RestrictedExpr def : getDefinitions(var)) {
Collection<Var> tmps = def.getExpr().getVarsMentioned();
result.addAll(tmps);
//for(Var item : def.getExpr().getVarsMentioned()) {
//String itemName = item.getName();
//if(!result.contains(item)) {
//result.add(item);
//}
//}
}
}
return result;
}
public Set<String> getReferencedVarNames(Collection<Var> vars) {
Set<Var> tmp = getReferencedVars(vars);
Set<String> result = copyVarNames(new HashSet<String>(), tmp);
return result;
}
public <T extends Collection<String>> T getReferencedVarNames(T target, Collection<Var> vars) {
Set<Var> tmp = getReferencedVars(vars);
T result = copyVarNames(target, tmp);
return result;
}
public static String toIndentedString(Multimap<Var, RestrictedExpr> varToExprs) {
String result = "";
for(Entry<Var, Collection<RestrictedExpr>> entry : varToExprs.asMap().entrySet()) {
Var var = entry.getKey();
String varName = var.getName();
//int varLen = varName.length();
Collection<RestrictedExpr> restExprs = entry.getValue();
Iterator<RestrictedExpr> it = restExprs.iterator();
String firstLabel;
if(!it.hasNext()) {
firstLabel = "(empty definition set)";
} else {
RestrictedExpr restExpr = it.next();
firstLabel = varName + ": " + restExpr.getExpr() + " [" + restExpr.getRestrictions() + "]";
}
result += firstLabel + "\n";
while(it.hasNext()) {
RestrictedExpr restExpr = it.next();
//StringUtils.
// FIXME Make spaces for var length
result += " " + restExpr.getExpr() + " [" + restExpr.getRestrictions() + "]" + "\n";
}
}
return result;
}
@Override
public String toString() {
return toPrettyString();
//return "VarDefinition [varToExprs=" + varToExprs + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((varToExprs == null) ? 0 : varToExprs.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;
VarDefinition other = (VarDefinition) obj;
if (varToExprs == null) {
if (other.varToExprs != null)
return false;
} else if (!varToExprs.equals(other.varToExprs))
return false;
return true;
}
/*
public renameColumnReferences(Map<String, String> oldToNew) {
for(Entry<Var, VariableDefinition> mapExpr : varToMapExprs.entrySet()) {
if(mapExpr.)
}
}*/
public static VarDefinition create(VarExprList varExprs) {
Multimap<Var, RestrictedExpr> map = HashMultimap.create();
for(Entry<Var, Expr> entry : varExprs.getExprs().entrySet()) {
Var var = entry.getKey();
Expr expr = entry.getValue();
RestrictedExpr restExpr = new RestrictedExpr(expr);
map.put(var, restExpr);
}
VarDefinition result = new VarDefinition(map);
return result;
}
}