/* Copyright 2013 The jeo project. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.jeo.vector;
import io.jeo.filter.Filters;
import io.jeo.geom.Bounds;
import io.jeo.util.Pair;
import io.jeo.filter.Filter;
import io.jeo.util.Predicate;
import org.osgeo.proj4j.CoordinateReferenceSystem;
import com.vividsolutions.jts.geom.Envelope;
import java.util.Set;
/**
* Explains how a query is handled by a format driver.
* <p>
* This class is typically only used by format implementers. As a {@link VectorQuery} object is processed
* the query plan is updated at aspects of the query such as bounds, filtering, limit/offset, etc..
* are handled natively. Finally {@link #apply(FeatureCursor)} should be called to augment a cursor with
* wrappers that handle the parts of the query that could not be handled natively.
* </p>
* @author Justin Deoliveira, OpenGeo
*/
public class VectorQueryPlan {
VectorQuery q;
boolean bounded;
Filter<Feature> filter;
boolean offsetted;
boolean limited;
boolean reprojected;
boolean simplified;
boolean sorted;
boolean fieldsSelected;
public VectorQueryPlan(VectorQuery q) {
this.q = q;
filter = q.filter();
}
/**
* Whether {@link VectorQuery#bounds()} was handled natively.
*/
public boolean isBounded() {
return bounded;
}
/**
* Marks {@link VectorQuery#bounds()} as being handled natively.
*/
public void bounded() {
this.bounded = true;
}
/**
* Whether {@link VectorQuery#filter()} was handled natively.
*/
public boolean isFiltered() {
return Filters.isTrueOrNull(filter);
}
/**
* Marks {@link VectorQuery#filter()} as being handled natively.
*/
public void filtered() {
filter = Filters.all();
}
/**
* Marks {@link VectorQuery#filter()} as being handled natively with a left-over part of the filter that could not
* be handled.
*/
public void filtered(Filter left) {
filter = left;
}
/**
* Whether {@link VectorQuery#sort()} was handled natively.
*/
public boolean isSorted() {
return sorted;
}
/**
* Marks {@link VectorQuery#sort()} as being handled natively.
*/
public void sorted() {
sorted = true;
}
/**
* Whether {@link VectorQuery#offset()} was handled natively.
*/
public boolean isOffsetted() {
return offsetted;
}
/**
* Marks {@link VectorQuery#offset()} as being handled natively.
*/
public void offsetted() {
offsetted = true;
}
/**
* Whether {@link VectorQuery#limit()} was handled natively.
*/
public boolean isLimited() {
return limited;
}
/**
* Marks {@link VectorQuery#limit()} as being handled natively.
*/
public void limited() {
limited = true;
}
/**
* Whether {@link VectorQuery#reproject()} was handled natively.
*/
public boolean isReprojected() {
return reprojected;
}
/**
* Marks {@link VectorQuery#reproject()} as being handled natively.
*/
public void reprojected() {
reprojected = true;
}
/**
* Whether {@link VectorQuery#simplify()} was handled natively.
*/
public boolean isSimplified() {
return simplified;
}
/**
* Marks {@link VectorQuery#simplify()} as being handled natively.
*/
public void simplified() {
simplified = true;
}
/**
* Whether {@link VectorQuery#fields()} was handled natively.
*/
public boolean isFields() {
return fieldsSelected;
}
/**
* Marks {@link VectorQuery#fields()} as being handled natively.
*/
public void fields() {
this.fieldsSelected = true;
}
/**
* Augments the specified cursor with wrappers that handle the parts of the query that could
* not be processed natively.
* <p>
* For example, if a format is unable to process {@link VectorQuery#filter()} objects natively
* then {@link #isFiltered()} should return <tt>false</tt> and this method should transform the
* cursor with {@link FeatureCursor#filter(Predicate)}.
* </p>
* @param cursor Cursor to augment.
*
* @return The augmented cursor.
*/
public FeatureCursor apply(FeatureCursor cursor) {
Envelope bounds = q.bounds();
if (!isBounded() && !Bounds.isNull(bounds)) {
cursor = cursor.intersect(bounds, true);
}
if (!Filters.isTrueOrNull(filter)) {
cursor = cursor.filter(filter);
}
Integer offset = q.offset();
if (!isOffsetted() && offset != null) {
cursor = cursor.skip(offset);
}
Integer limit = q.limit();
if (!isLimited() && limit != null) {
cursor = cursor.limit(limit);
}
Pair<CoordinateReferenceSystem,CoordinateReferenceSystem> reproj = q.reproject();
if (!isReprojected() && reproj != null) {
cursor = cursor.reproject(reproj.first, reproj.second);
}
Set<String> fields = q.fields();
if (!isFields() && !fields.isEmpty()) {
cursor = cursor.select(fields);
}
//TODO: sorting
return cursor;
}
}