package org.basex.query.flwor;
import static org.basex.query.QueryText.*;
import static org.basex.util.Token.*;
import java.io.IOException;
import org.basex.io.serial.Serializer;
import org.basex.query.QueryContext;
import org.basex.query.QueryException;
import org.basex.query.expr.Expr;
import org.basex.query.item.Bln;
import org.basex.query.item.Dbl;
import org.basex.query.item.Item;
import org.basex.query.item.SeqType;
import org.basex.query.item.Value;
import org.basex.query.iter.Iter;
import org.basex.query.util.Var;
import org.basex.util.InputInfo;
import org.basex.util.ft.Scoring;
/**
* Let clause.
*
* @author BaseX Team 2005-12, BSD License
* @author Christian Gruen
*/
public final class Let extends ForLet {
/** Scoring flag. */
final boolean score;
/**
* Constructor.
* @param ii input info
* @param e variable input
* @param v variable
*/
public Let(final InputInfo ii, final Expr e, final Var v) {
this(ii, e, v, false);
}
/**
* Constructor.
* @param ii input info
* @param e variable input
* @param v variable
* @param s score flag
*/
public Let(final InputInfo ii, final Expr e, final Var v, final boolean s) {
super(ii, e, v);
score = s;
}
@Override
public Let comp(final QueryContext ctx) throws QueryException {
expr = checkUp(expr, ctx).comp(ctx);
type = SeqType.ITEM;
size = 1;
var.size = expr.size();
var.ret = score ? SeqType.DBL : expr.type();
ctx.vars.add(var);
return this;
}
@Override
public Iter iter(final QueryContext ctx) {
final Var vr = var.copy();
return new Iter() {
/** Variable stack size. */
private int vs;
/** Iterator flag. */
private boolean more;
@Override
public Item next() throws QueryException {
if(!more) {
vs = ctx.vars.size();
final Value v;
if(score) {
// assign average score value
double s = 0;
int c = 0;
final Iter ir = ctx.iter(expr);
for(Item it; (it = ir.next()) != null;) {
s += it.score();
++c;
}
v = Dbl.get(Scoring.let(s, c));
} else {
v = ctx.value(expr);
}
ctx.vars.add(vr.bind(v, ctx));
more = true;
return Bln.TRUE;
}
reset();
return null;
}
@Override
public long size() {
return 1;
}
@Override
public Item get(final long i) throws QueryException {
reset();
return next();
}
@Override
public boolean reset() {
if(more) {
ctx.vars.size(vs);
more = false;
}
return true;
}
};
}
@Override
boolean simple(final boolean one) {
return !score;
}
@Override
public void plan(final Serializer ser) throws IOException {
ser.openElement(this, score ? token(SCORE) : VAR, token(var.toString()));
expr.plan(ser);
ser.closeElement();
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder(LET).append(' ');
if(score) sb.append(SCORE).append(' ');
sb.append(var).append(' ').append(ASSIGN).append(' ').append(expr);
return sb.toString();
}
@Override
public boolean declares(final Var v) {
return var.is(v);
}
@Override
public Var[] vars() {
return new Var[]{ var };
}
}