/* (non-Javadoc)
   * @see org.geotools.data.DataStore#getFeatureWriter(java.lang.String, org.geotools.filter.Filter, org.geotools.data.Transaction)
   */
  public FeatureWriter<SimpleFeatureType, SimpleFeature> getFeatureWriter(
      String typeName, Filter filter, Transaction transaction) throws IOException {
    if (filter == null) {
      throw new NullPointerException(
          "getFeatureReader requires Filter: " + "did you mean Filter.INCLUDE?");
    }

    if (filter == Filter.EXCLUDE) {
      SimpleFeatureType featureType = getSchema(typeName);

      return new EmptyFeatureWriter(featureType);
    }

    if (transaction == null) {
      throw new NullPointerException(
          "getFeatureWriter requires Transaction: "
              + "did you mean to use Transaction.AUTO_COMMIT?");
    }

    FeatureWriter<SimpleFeatureType, SimpleFeature> writer;

    if (transaction == Transaction.AUTO_COMMIT) {
      try {
        writer = createFeatureWriter(typeName, transaction);
      } catch (UnsupportedOperationException e) {
        throw e;
      }
    } else {
      TransactionStateDiff state = state(transaction);
      if (state != null) {
        writer = state.writer(typeName, filter);
      } else {
        throw new UnsupportedOperationException("Subclass sould implement");
      }
    }

    if (lockingManager != null) {
      // subclass has not provided locking so we will
      // fake it with InProcess locks
      writer = lockingManager.checkedWriter(writer, transaction);
    }

    if (filter != Filter.INCLUDE) {
      writer = new FilteringFeatureWriter(writer, filter);
    }

    return writer;
  }
  // Jody - Recomend moving to the following
  // When we are ready for CoordinateSystem support
  public FeatureReader<SimpleFeatureType, SimpleFeature> getFeatureReader(
      Query query, Transaction transaction) throws IOException {
    Filter filter = query.getFilter();
    String typeName = query.getTypeName();
    String propertyNames[] = query.getPropertyNames();

    if (filter == null) {
      throw new NullPointerException(
          "getFeatureReader requires Filter: " + "did you mean Filter.INCLUDE?");
    }
    if (typeName == null) {
      throw new NullPointerException(
          "getFeatureReader requires typeName: "
              + "use getTypeNames() for a list of available types");
    }
    if (transaction == null) {
      throw new NullPointerException(
          "getFeatureReader requires Transaction: "
              + "did you mean to use Transaction.AUTO_COMMIT?");
    }
    SimpleFeatureType featureType = getSchema(query.getTypeName());

    if (propertyNames != null || query.getCoordinateSystem() != null) {
      try {
        featureType =
            DataUtilities.createSubType(featureType, propertyNames, query.getCoordinateSystem());
      } catch (SchemaException e) {
        LOGGER.log(Level.FINEST, e.getMessage(), e);
        throw new DataSourceException("Could not create Feature Type for query", e);
      }
    }
    if (filter == Filter.EXCLUDE || filter.equals(Filter.EXCLUDE)) {
      return new EmptyFeatureReader<SimpleFeatureType, SimpleFeature>(featureType);
    }
    // GR: allow subclases to implement as much filtering as they can,
    // by returning just it's unsupperted filter
    filter = getUnsupportedFilter(typeName, filter);
    if (filter == null) {
      throw new NullPointerException(
          "getUnsupportedFilter shouldn't return null. Do you mean Filter.INCLUDE?");
    }

    // There are cases where the readers have to lock.  Take shapefile for example.  Getting a
    // Reader causes
    // the file to be locked.  However on a commit TransactionStateDiff locks before a writer is
    // obtained.  In order to
    // prevent deadlocks either the diff has to obtained first or the reader has to be obtained
    // first.
    // Because shapefile writes to a buffer first the actual write lock is not flipped until the
    // transaction has most of the work
    // done.  As a result I suggest getting the diff first then getting the reader.
    // JE
    Diff diff = null;
    if (transaction != Transaction.AUTO_COMMIT) {
      TransactionStateDiff state = state(transaction);
      if (state != null) {
        diff = state.diff(typeName);
      }
    }

    // This calls our subclass "simple" implementation
    // All other functionality will be built as a reader around
    // this class
    //
    FeatureReader<SimpleFeatureType, SimpleFeature> reader = getFeatureReader(typeName, query);

    if (diff != null)
      reader =
          new DiffFeatureReader<SimpleFeatureType, SimpleFeature>(reader, diff, query.getFilter());

    if (!filter.equals(Filter.INCLUDE)) {
      reader = new FilteringFeatureReader<SimpleFeatureType, SimpleFeature>(reader, filter);
    }

    if (!featureType.equals(reader.getFeatureType())) {
      LOGGER.fine("Recasting feature type to subtype by using a ReTypeFeatureReader");
      reader = new ReTypeFeatureReader(reader, featureType, false);
    }

    if (query.getMaxFeatures() != Query.DEFAULT_MAX) {
      reader =
          new MaxFeatureReader<SimpleFeatureType, SimpleFeature>(reader, query.getMaxFeatures());
    }

    return reader;
  }