/*
 *    GeoTools - The Open Source Java GIS Toolkit
 *    http://geotools.org
 * 
 *    (C) 2003-2008, Open Source Geospatial Foundation (OSGeo)
 *    
 *    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.geotools.data;

import java.io.IOException;
import java.util.NoSuchElementException;

import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.filter.Filter;


/**
 * Filtering is performed on this hasNext() method.
 * 
 * <p>
 * This implementation writes out content furing the hasNext() method. This
 * allows the implementation to "peek" ahead.
 * </p>
 * 
 * <p>
 * This FeatureWriter does not support the addition of new content.
 * </p>
 *
 * @author Jody Garnett, Refractions Research
 *
 * @source $URL: http://svn.osgeo.org/geotools/branches/2.7.x/modules/library/main/src/main/java/org/geotools/data/FilteringFeatureWriter.java $
 */
public class FilteringFeatureWriter implements FeatureWriter<SimpleFeatureType, SimpleFeature> {
    FeatureWriter<SimpleFeatureType, SimpleFeature> writer;
    Filter filter;
    SimpleFeature next = null; // next feature as peeked by hasNext()
    SimpleFeature current = null; // holds current Feature returned to user

    public FilteringFeatureWriter(FeatureWriter<SimpleFeatureType, SimpleFeature> writer, Filter filter) {
        this.writer = writer;
        this.filter = filter;
    }

    public SimpleFeatureType getFeatureType() {
        return writer.getFeatureType();
    }

    public SimpleFeature next() throws IOException {
        if (hasNext()) {
            // use hasNext() to and peek ahead
            // 
            current = next;
            next = null;

            return current;
        }
            // FilteringFeatureWriter Does not support the creation
            // of new content
            throw new NoSuchElementException(
                "FeatureWriter does not have additional content");
    }

    public void remove() throws IOException {
        if (writer == null) {
            throw new IOException("FeatureWriter has been closed");
        }

        if (current == null) {
            // We do not have a current Feature
            // Either:
            // - we have not started yet
            // - hasNext() has already skipped current
            // - write() has already writen current
            // - remove() has already deleted current
            throw new IOException("No feature available to remove");
        }

        current = null;
        writer.remove();
    }

    public void write() throws IOException {
        if (writer == null) {
            throw new IOException("FeatureWriter has been closed");
        }

        if (current == null) {
            // We do not have a current Feature
            // Either:
            // - we have not started yet
            // - hasNext() has already skipped current
            // - write() has already writen current
            // - remove() has already deleted current
            throw new IOException("No feature available to write");
        }

        writer.write();
        current = null;
    }

    /**
     * Query if we have more content.
     *
     * @return true if writer has additional content
     *
     * @throws IOException If writer we are filtering encounters a problem
     */
    public boolean hasNext() throws IOException {
        if (next != null) {
            return true; // we found next already
        }

        if (writer == null) {
            return false; // writer is closed
        }

        if (current != null) {
            // we are skipping ahead, the user will lose
            // any changes to current
            current = null;
        }

        SimpleFeature peek;

        while (writer.hasNext()) {
            peek = writer.next();

            if (filter.evaluate(peek)) {
                next = peek;

                return true; // we have a match!
            }
        }

        return false;
    }

    public void close() throws IOException {
        if (writer != null) {
            writer.close();
            writer = null;
        }

        if (filter != null) {
            filter = null;
        }

        current = null;
        next = null;
    }
}
