package org.basex.query.ft;
import static org.basex.query.QueryText.*;
import org.basex.data.FTMatch;
import org.basex.data.FTMatches;
import org.basex.query.QueryContext;
import org.basex.query.QueryException;
import org.basex.query.item.FTNode;
import org.basex.query.iter.FTIter;
import org.basex.query.util.IndexContext;
import org.basex.util.InputInfo;
import org.basex.util.ft.Scoring;
/**
* FTOr expression.
*
* @author BaseX Team 2005-12, BSD License
* @author Christian Gruen
* @author Sebastian Gath
*/
public final class FTOr extends FTExpr {
/**
* Constructor.
* @param ii input info
* @param e expression list
*/
public FTOr(final InputInfo ii, final FTExpr[] e) {
super(ii, e);
}
@Override
public FTExpr comp(final QueryContext ctx) throws QueryException {
super.comp(ctx);
boolean not = true;
for(final FTExpr e : expr) not &= e instanceof FTNot;
if(not) {
// convert (!A or !B or ...) to !(A and B and ...)
for(int e = 0; e < expr.length; ++e) expr[e] = expr[e].expr[0];
return new FTNot(input, new FTAnd(input, expr));
}
return this;
}
@Override
public FTNode item(final QueryContext ctx, final InputInfo ii)
throws QueryException {
final FTNode item = expr[0].item(ctx, input);
for(int e = 1; e < expr.length; ++e) {
or(item, expr[e].item(ctx, input));
}
return item;
}
@Override
public FTIter iter(final QueryContext ctx) throws QueryException {
// initialize iterators
final FTIter[] ir = new FTIter[expr.length];
final FTNode[] it = new FTNode[expr.length];
for(int e = 0; e < expr.length; ++e) {
ir[e] = expr[e].iter(ctx);
it[e] = ir[e].next();
}
return new FTIter() {
@Override
public FTNode next() throws QueryException {
// find item with smallest pre value
int p = -1;
for(int i = 0; i < it.length; ++i) {
if(it[i] != null && (p == -1 || it[p].pre > it[i].pre)) p = i;
}
// no items left - leave
if(p == -1) return null;
// merge all matches
final FTNode item = it[p];
for(int i = 0; i < it.length; ++i) {
if(it[i] != null && p != i && item.pre == it[i].pre) {
or(item, it[i]);
it[i] = ir[i].next();
}
}
it[p] = ir[p].next();
return item;
}
};
}
/**
* Merges two matches.
* @param i1 first item
* @param i2 second item
*/
static void or(final FTNode i1, final FTNode i2) {
final FTMatches all = new FTMatches(
(byte) Math.max(i1.all.sTokenNum, i2.all.sTokenNum));
for(final FTMatch m : i1.all) all.add(m);
for(final FTMatch m : i2.all) all.add(m);
i1.score(Scoring.or(i1.score(), i2.score()));
i1.all = all;
}
@Override
public boolean indexAccessible(final IndexContext ic) throws QueryException {
int is = 0;
for(final FTExpr e : expr) {
// no index access if negative operators is found
if(!e.indexAccessible(ic) || ic.not) return false;
ic.not = false;
is = Math.min(Integer.MIN_VALUE, is + ic.costs());
}
ic.costs(is);
return true;
}
@Override
public String toString() {
return PAR1 + toString(' ' + FTOR + ' ') + PAR2;
}
}