/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2014, Geomatys
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotoolkit.data.memory;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.sis.feature.FeatureTypeExt;
import org.apache.sis.feature.ReprojectFeatureType;
import org.apache.sis.feature.TransformFeatureType;
import org.apache.sis.feature.ViewFeatureType;
import org.apache.sis.storage.DataStoreException;
import org.geotoolkit.data.AbstractFeatureCollection;
import org.geotoolkit.data.FeatureCollection;
import org.geotoolkit.data.FeatureReader;
import org.geotoolkit.data.FeatureStoreRuntimeException;
import org.geotoolkit.data.query.Query;
import org.geotoolkit.factory.Hints;
import org.geotoolkit.util.NamesExt;
import org.opengis.util.GenericName;
import org.geotoolkit.geometry.jts.transform.GeometryScaleTransformer;
import org.opengis.feature.FeatureType;
import org.opengis.feature.MismatchedFeatureException;
import org.opengis.filter.Filter;
import org.opengis.filter.sort.SortBy;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.util.FactoryException;
/**
*
* @author Johann Sorel (Geomatys)
*/
public class GenericQueryFeatureIterator {
public static FeatureReader wrap(FeatureReader reader, final Query remainingParameters) throws DataStoreException{
final Integer start = remainingParameters.getStartIndex();
final Integer max = remainingParameters.getMaxFeatures();
final Filter filter = remainingParameters.getFilter();
final String[] properties = remainingParameters.getPropertyNames();
final SortBy[] sorts = remainingParameters.getSortBy();
final double[] resampling = remainingParameters.getResolution();
final CoordinateReferenceSystem crs = remainingParameters.getCoordinateSystemReproject();
final Hints hints = remainingParameters.getHints();
//we should take care of wrapping the reader in a correct order to avoid
//unnecessary calculations. fast and reducing number wrapper should be placed first.
//but we must not take misunderstanding assumptions neither.
//exemple : filter is slow than startIndex and MaxFeature but must be placed before
// otherwise the result will be illogic.
//wrap sort by ---------------------------------------------------------
//This can be really expensive, and force the us to read the full iterator.
//that may cause out of memory errors.
if(sorts != null && sorts.length != 0){
reader = GenericSortByFeatureIterator.wrap(reader, sorts);
}
//wrap filter ----------------------------------------------------------
//we must keep the filter first since it impacts the start index and max feature
if(filter != null && filter != Filter.INCLUDE){
if(filter == Filter.EXCLUDE){
//filter that exclude everything, use optimzed reader
reader = GenericEmptyFeatureIterator.createReader(reader.getFeatureType());
//close original reader
reader.close();
}else{
reader = GenericFilterFeatureIterator.wrap(reader, filter);
}
}
//wrap start index -----------------------------------------------------
if(start != null && start > 0){
reader = GenericStartIndexFeatureIterator.wrap(reader, start);
}
//wrap max -------------------------------------------------------------
if(max != null){
if(max == 0){
//use an optimized reader
reader = GenericEmptyFeatureIterator.createReader(reader.getFeatureType());
//close original reader
reader.close();
}else{
reader = GenericMaxFeatureIterator.wrap(reader, max);
}
}
//wrap properties -----------------------------------------------------
final FeatureType original = reader.getFeatureType();
if(properties!=null && !FeatureTypeExt.isAllProperties(original, properties)) {
try {
reader = GenericDecoratedFeatureIterator.wrap(reader, new ViewFeatureType(original, properties),hints);
} catch (MismatchedFeatureException | IllegalStateException ex) {
throw new DataStoreException(ex);
}
}
//wrap resampling ------------------------------------------------------
if(resampling != null){
final GeometryScaleTransformer trs = new GeometryScaleTransformer(resampling[0], resampling[1]);
final TransformFeatureType ttype = new TransformFeatureType(reader.getFeatureType(), trs);
reader = GenericDecoratedFeatureIterator.wrap(reader, ttype, hints);
}
//wrap reprojection ----------------------------------------------------
if(crs != null){
try {
reader = GenericDecoratedFeatureIterator.wrap(reader, new ReprojectFeatureType(reader.getFeatureType(), crs), hints);
} catch (MismatchedFeatureException ex) {
throw new DataStoreException(ex);
}
}
return reader;
}
public static FeatureCollection wrap(final FeatureCollection col, final Query query){
return new AbstractFeatureCollection("wrap", col.getSource()) {
private FeatureType type = null;
@Override
public FeatureType getFeatureType() {
if(type==null){
try (FeatureReader ite = iterator(null)) {
type = ite.getFeatureType();
}
}
return type;
}
@Override
public FeatureReader iterator(Hints hints) throws FeatureStoreRuntimeException {
final FeatureReader ite = (FeatureReader) col.iterator();
try {
return wrap(ite, query);
} catch (DataStoreException ex) {
throw new FeatureStoreRuntimeException(ex);
}
}
@Override
public void update(Filter filter, Map values) throws DataStoreException {
throw new DataStoreException("Not supported.");
}
@Override
public void remove(Filter filter) throws DataStoreException {
throw new DataStoreException("Not supported.");
}
};
}
}