package org.basex.query.up.expr;
import static org.basex.query.QueryText.*;
import static org.basex.query.util.Err.*;
import java.io.IOException;
import org.basex.data.MemData;
import org.basex.io.serial.Serializer;
import org.basex.query.QueryContext;
import org.basex.query.QueryException;
import org.basex.query.expr.Arr;
import org.basex.query.expr.Expr;
import org.basex.query.flwor.Let;
import org.basex.query.item.ANode;
import org.basex.query.item.DBNode;
import org.basex.query.item.Item;
import org.basex.query.item.Value;
import org.basex.query.iter.Iter;
import org.basex.query.iter.ValueIter;
import org.basex.query.up.ContextModifier;
import org.basex.query.up.TransformModifier;
import org.basex.query.util.DataBuilder;
import org.basex.query.util.Var;
import org.basex.util.InputInfo;
/**
* Transform expression.
*
* @author BaseX Team 2005-12, BSD License
* @author Lukas Kircher
*/
public final class Transform extends Arr {
/** Variable bindings created by copy clause. */
private final Let[] copies;
/**
* Constructor.
* @param ii input info
* @param c copy expressions
* @param m modify expression
* @param r return expression
*/
public Transform(final InputInfo ii, final Let[] c, final Expr m,
final Expr r) {
super(ii, m, r);
copies = c;
}
@Override
public Expr comp(final QueryContext ctx) throws QueryException {
final boolean u = ctx.updating;
ctx.updating = true;
final int s = ctx.vars.size();
for(final Let c : copies) {
c.expr = checkUp(c.expr, ctx).comp(ctx);
ctx.vars.add(c.var);
}
for(int e = 0; e != expr.length; ++e) expr[e] = expr[e].comp(ctx);
if(!expr[0].uses(Use.UPD) && !expr[0].isVacuous()) UPEXPECTT.thrw(input);
checkUp(expr[1], ctx);
ctx.vars.size(s);
ctx.updating = u;
return this;
}
@Override
public ValueIter iter(final QueryContext ctx) throws QueryException {
return value(ctx).iter();
}
@Override
public Value value(final QueryContext ctx) throws QueryException {
final int s = ctx.vars.size();
try {
final TransformModifier pu = new TransformModifier();
for(final Let fo : copies) {
final Iter ir = ctx.iter(fo.expr);
final Item i = ir.next();
if(i == null || !i.type.isNode() || ir.next() != null)
UPCOPYMULT.thrw(input);
// copy node to main memory data instance
final MemData md = new MemData(ctx.context.prop);
new DataBuilder(md).build((ANode) i);
// add resulting node to variable
ctx.vars.add(fo.var.bind(new DBNode(md, 0), ctx).copy());
pu.addData(md);
}
final ContextModifier tmp = ctx.updates.mod;
ctx.updates.mod = pu;
ctx.value(expr[0]);
ctx.updates.applyUpdates();
ctx.updates.mod = tmp;
return ctx.value(expr[1]);
} finally {
ctx.vars.size(s);
}
}
@Override
public boolean uses(final Use u) {
return u == Use.VAR || u != Use.UPD && super.uses(u);
}
@Override
public int count(final Var v) {
int c = 0;
for(final Let l : copies) c += l.count(v);
return c + super.count(v);
}
@Override
public boolean removable(final Var v) {
for(final Let c : copies) if(!c.removable(v)) return false;
return super.removable(v);
}
@Override
public Expr remove(final Var v) {
for(final Let c : copies) c.remove(v);
return super.remove(v);
}
@Override
public void plan(final Serializer ser) throws IOException {
ser.openElement(this);
for(final Expr c : copies) c.plan(ser);
for(final Expr e : expr) e.plan(ser);
ser.closeElement();
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder(COPY + ' ');
for(final Let t : copies)
sb.append(t.var + " " + ASSIGN + ' ' + t.expr + ' ');
return sb.append(MODIFY + ' ' + expr[0] + ' ' + RETURN + ' ' +
expr[1]).toString();
}
}