package org.xenei.jdbc4sparql.sparql.parser.jsqlparser;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
import org.xenei.jdbc4sparql.iface.name.ColumnName;
import org.xenei.jdbc4sparql.iface.name.ItemName;
import org.xenei.jdbc4sparql.sparql.SparqlQueryBuilder;
import org.xenei.jdbc4sparql.sparql.items.QueryColumnInfo;
import com.hp.hpl.jena.sparql.core.Var;
import com.hp.hpl.jena.sparql.expr.Expr;
import com.hp.hpl.jena.sparql.expr.ExprAggregator;
import com.hp.hpl.jena.sparql.expr.ExprFunction;
import com.hp.hpl.jena.sparql.expr.ExprFunction0;
import com.hp.hpl.jena.sparql.expr.ExprFunction1;
import com.hp.hpl.jena.sparql.expr.ExprFunction2;
import com.hp.hpl.jena.sparql.expr.ExprFunction3;
import com.hp.hpl.jena.sparql.expr.ExprFunctionN;
import com.hp.hpl.jena.sparql.expr.ExprFunctionOp;
import com.hp.hpl.jena.sparql.expr.ExprList;
import com.hp.hpl.jena.sparql.expr.ExprVar;
import com.hp.hpl.jena.sparql.expr.ExprVisitor;
import com.hp.hpl.jena.sparql.expr.NodeValue;
import com.hp.hpl.jena.sparql.expr.aggregate.Aggregator;
public abstract class ExpRewriter implements ExprVisitor {
protected final Map<ItemName, ItemName> aliasMap = new HashMap<ItemName, ItemName>();
protected final SparqlQueryBuilder queryBuilder;
protected final Stack<Expr> stack = new Stack<Expr>();
public ExpRewriter(final SparqlQueryBuilder queryBuilder) {
this.queryBuilder = queryBuilder;
}
public void addMap(final ItemName from, final ItemName to) {
aliasMap.put(from, to);
}
private ExprList createExprList(final ExprFunction expr) {
pushArgs(expr);
final ExprList lst = new ExprList();
for (int i = 0; i < expr.numArgs(); i++) {
lst.add(stack.pop());
}
return lst;
}
@Override
public void finishVisit() {
}
public Expr getResult() {
return stack.pop();
}
public ColumnName isMapped(final QueryColumnInfo ci) {
for (final ItemName qi : aliasMap.keySet()) {
if (new ColumnName(qi).matches(ci.getName())) {
final ItemName mapTo = aliasMap.get(qi);
return new ColumnName(mapTo.getCatalog(), mapTo.getSchema(),
mapTo.getTable(), ci.getName().getColumn());
}
}
return null;
}
/**
* Push args in reverse order so we can pop them back in the proper order
*/
protected void pushArgs(final ExprFunction exp) {
for (int i = exp.numArgs(); i > 0; i--) {
exp.getArg(i).visit(this);
}
}
@Override
public void startVisit() {
}
@Override
public void visit(final ExprAggregator eAgg) {
final Aggregator agg = eAgg.getAggregator();
Expr exp = agg.getExpr();
if (exp != null) {
exp.visit(this);
exp = stack.pop();
}
stack.push(new ExprAggregator(eAgg.getVar(), agg.copy(exp)));
}
@Override
public void visit(final ExprFunction0 func) {
stack.push(func);
}
@Override
public void visit(final ExprFunction1 func) {
func.getArg().visit(this);
stack.push(func.copy(stack.pop()));
}
@Override
public void visit(final ExprFunction2 func) {
pushArgs(func);
stack.push(func.copy(stack.pop(), stack.pop()));
}
@Override
public void visit(final ExprFunction3 func) {
pushArgs(func);
stack.push(func.copy(stack.pop(), stack.pop(), stack.pop()));
}
@Override
public void visit(final ExprFunctionN func) {
try {
final Method m = ExprFunctionN.class.getMethod("copy",
ExprList.class);
m.setAccessible(true);
stack.push((Expr) m.invoke(func, createExprList(func)));
} catch (final NoSuchMethodException e) {
throw new IllegalStateException(String.format(
"%s copy(ExprList) method is required", func.getClass()), e);
} catch (final SecurityException e) {
throw new IllegalStateException(String.format(
"Could not make %s copy(ExprList) method visible",
func.getClass()), e);
} catch (final IllegalAccessException e) {
throw new IllegalStateException(String.format(
"Could not make %s copy(ExprList) method visible",
func.getClass()), e);
} catch (final InvocationTargetException e) {
throw new IllegalStateException(String.format(
"Could not invoke %s copy(ExprList) method",
func.getClass()), e);
}
}
@Override
public void visit(final ExprFunctionOp funcOp) {
stack.push(funcOp.copy(createExprList(funcOp), funcOp.getGraphPattern()));
}
@Override
public void visit(final ExprVar nv) {
final Var v = nv.asVar();
final QueryColumnInfo ci = queryBuilder.getColumn(v);
if (ci != null) {
for (final ItemName qi : aliasMap.keySet()) {
if (new ColumnName(qi).matches(ci.getName())) {
ItemName mapTo = aliasMap.get(qi);
mapTo = new ColumnName(mapTo.getCatalog(),
mapTo.getSchema(), mapTo.getTable(), ci.getName()
.getColumn());
stack.push(new ExprVar(mapTo.getSPARQLName()));
return;
}
}
}
stack.push(nv);
}
@Override
public void visit(final NodeValue nv) {
stack.push(nv);
}
}