package spimedb.query;
import jcog.tree.rtree.rect.RectDoubleND;
import org.apache.lucene.search.ScoreDoc;
import org.jetbrains.annotations.NotNull;
import spimedb.SpimeDB;
import spimedb.index.DObject;
import java.util.Arrays;
import java.util.function.BiPredicate;
import static spimedb.query.Query.BoundsCondition.Intersect;
/**
* General spatiotemporal x tag Query
*/
public class Query {
/**
* time the query was created
*/
public final long whenCreated;
long whenStarted, whenEnded;
public static final double[] ANY_SCALAR = {Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY};
// public static final RectDoubleND[] ANYWHERE_4 =
// new RectDoubleND[] ( ANY_SCALAR, ANY_SCALAR );
/**
* OR-d together, potentially executed in parallel
*/
public RectDoubleND[] bounds = null;
public BoundsCondition boundsCondition = Intersect;
/**
* tags within which to search; if null, searches all
*/
public String[] include = null;
public int limit = 128;
/**
*
* @param each if null, attempts to use this instance as the predicate (as it can be implemented in subclasses)
*/
public Query() {
this.whenCreated = System.currentTimeMillis();
}
public Query limit(int limit) {
this.limit = limit;
return this;
}
public enum BoundsCondition {
/**
* the query bound may intersect or contain a matched bound
*/
Intersect,
/**
* the query bound needs to fully contain a matched bound
*/
Contain
}
/**
* called by the db when the query begins executing
*/
public void onStart() {
this.whenStarted = System.currentTimeMillis();
}
public void onEnd() {
this.whenEnded = System.currentTimeMillis();
}
public Query in(String... tags) {
ensureNotStarted();
include = tags;
return this;
}
/** time-axis only */
public <Q extends Query> Q when(float start, float end) {
return (Q) bounds(new RectDoubleND(
new double[]{start, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY},
new double[]{end, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY}
));
}
/**
* specific lat x lon region, at any time
*/
public <Q extends Query> Q where(double[] lon, double[] lat) {
return (Q) bounds(new RectDoubleND(
new double[]{Double.NEGATIVE_INFINITY, lon[0], lat[0], Double.NEGATIVE_INFINITY},
new double[]{Double.POSITIVE_INFINITY, lon[1], lat[1], Double.POSITIVE_INFINITY}
));
}
@NotNull
public <Q extends Query> Q bounds(RectDoubleND... newBounds) {
ensureNotStarted();
if (bounds!=null)
throw new RuntimeException("bounds already specified");
bounds = newBounds;
return (Q) this;
}
private void ensureNotStarted() {
if (whenStarted != 0)
throw new RuntimeException("Query already executing");
}
@Override
public String toString() {
return getClass().getSimpleName() + "{" +
", whenCreated=" + whenCreated +
", whenStarted=" + whenStarted +
", whenEnded=" + whenEnded + "=(" + ((double)(whenEnded - whenStarted)) + "ms)" +
", bounds=" + Arrays.toString(bounds) +
", boundsCondition=" + boundsCondition +
", include=" + ((include == null || include.length == 0) ? "ALL" : Arrays.toString(include)) +
'}';
}
public void forEach(SpimeDB db, BiPredicate<DObject,ScoreDoc> each) {
db.get(this).forEach(each);
}
}