/**
   * Creates a query that requests the features in sourceLayer as dictated by filter. Query only
   * requests the attributes that can be mapped from sourceLayer to targetLayer.
   *
   * @param queryAttributes populates with a mapping of attributeTypeNames from targetLayer to
   *     sourcelayer
   * @return
   */
  @SuppressWarnings("unchecked")
  private Query createQuery(
      ILayer sourceLayer, Filter filter, Layer targetLayer, Map<String, String> queryAttributes) {
    SimpleFeatureType sourceSchema = sourceLayer.getSchema();
    SimpleFeatureType targetSchema = targetLayer.getSchema();
    // Maps type names to type names since we are ignoring case

    queryAttributes.putAll(FeatureUtils.createAttributeMapping(sourceSchema, targetSchema));
    Set<String> properties = new HashSet(queryAttributes.values());
    return new DefaultQuery(
        sourceSchema.getName().getLocalPart(),
        filter,
        properties.toArray(new String[properties.size()]));
  }
  public void run(IProgressMonitor monitor) throws Exception {
    monitor.beginTask(Messages.AddFeaturesCommand_taskMessage, 10);
    monitor.worked(1);

    FeatureStore<SimpleFeatureType, SimpleFeature> store =
        layer.getResource(FeatureStore.class, new SubProgressMonitor(monitor, 2));
    String geomAttributeName = layer.getSchema().getGeometryDescriptor().getLocalName();
    String[] desiredProperties = new String[] {geomAttributeName};
    Query query = new DefaultQuery(layer.getSchema().getTypeName(), filter, desiredProperties);
    FeatureCollection<SimpleFeatureType, SimpleFeature> features = store.getFeatures(query);

    FeatureIterator<SimpleFeature> iter = features.features();
    try {
      commands = new ArrayList<UndoableMapCommand>();
      while (iter.hasNext()) {
        SimpleFeature feature = iter.next();
        commands.add(new SelectFeatureCommand(bb, feature));
      }

      float index = 0;
      float inc = (float) 7 / commands.size();
      for (UndoableMapCommand command : commands) {
        command.setMap(getMap());
        index += inc;
        SubProgressMonitor subProgressMonitor = new SubProgressMonitor(monitor, (int) index);
        command.run(subProgressMonitor);
        subProgressMonitor.done();
        if (index > 1) {
          index = 0;
        }
      }
    } finally {
      features.close(iter);
    }

    monitor.done();
  }
  /**
   * Creates A geometry filter for the given layer.
   *
   * @param boundingBox in the same crs as the viewport model.
   * @return a Geometry filter in the correct CRS or null if an exception occurs.
   */
  public Filter createBBoxFilter(
      ReferencedEnvelope boundingBox, ILayer layer, Class<? extends Filter> filterType) {
    FilterFactory2 factory = CommonFactoryFinder.getFilterFactory2(GeoTools.getDefaultHints());
    if (!layer.hasResource(FeatureSource.class)) return Filter.EXCLUDE;
    try {

      SimpleFeatureType schema = layer.getSchema();
      Name geom = getGeometryAttDescriptor(schema).getName();

      Filter bboxFilter = factory.bbox(factory.property(geom), boundingBox);

      return bboxFilter;
    } catch (Exception e) {
      ProjectPlugin.getPlugin().log(e);
      return Filter.EXCLUDE;
    }
  }
  private static void writeFeatureType(ILayer layer, BufferedWriter out) throws IOException {
    WFSDataStore wfs = (WFSDataStore) layer.getResource(WFSDataStore.class, null);
    SimpleFeatureType type = layer.getSchema();
    String typeName = type.getName().getLocalPart();

    int hidden = layer.isVisible() ? 1 : 0;
    ServiceInfo serviceInfo = wfs.getInfo();
    String title = serviceInfo.getTitle();
    String version = "1.0.0"; // only known entry at this time //$NON-NLS-1$
    URI source = serviceInfo.getSource();
    String get = source == null ? "" : source.toString();

    ResourceInfo resourceInfo = wfs.getFeatureSource(typeName).getInfo();
    append(4, out, "<SimpleFeatureType hidden=\"" + hidden + "\">"); // $NON-NLS-1$ //$NON-NLS-2$
    append(
        6,
        out,
        "<Server service=\"OGC:WFS\" title=\""
            + title
            + "\" version=\""
            + version
            + "\">"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    append(
        8,
        out,
        "<OnlineResource method=\"GET\" xlink:href=\""
            + get
            + "\" xlink:type=\"simple\"/>"); //$NON-NLS-1$ //$NON-NLS-2$
    append(6, out, "</Server>"); // $NON-NLS-1$
    append(6, out, "<Name>" + typeName + "</Name>"); // $NON-NLS-1$ //$NON-NLS-2$
    append(6, out, "<Title>" + resourceInfo.getTitle() + "</Title>"); // $NON-NLS-1$ //$NON-NLS-2$
    // if( !Double.isNaN( layer.getMinScaleDenominator() ))
    //        append( 6, out,
    // "<sld:MinScaleDenominator>"+layer.getMinScaleDenominator()+"</sld:MinScaleDenominator>");
    // if( !Double.isNaN( layer.getMaxScaleDenominator() ))
    //        append( 6, out,
    // "<sld:MinScaleDenominator>"+layer.getMaxScaleDenominator()+"</sld:MinScaleDenominator>");
    String SRS = "EPSG:4326";
    CoordinateReferenceSystem crs = resourceInfo.getCRS();
    // TODO: anyone knows how to get the urn for the crs object?
    append(6, out, "<SRS>" + SRS + "</SRS>"); // $NON-NLS-1$ //$NON-NLS-2$
    append(4, out, "</SimpleFeatureType>"); // $NON-NLS-1$
  }
  public UndoableMapCommand getCommand(EditToolHandler handler) {
    final PrimitiveShape currentShape = handler.getCurrentShape();
    final ILayer editLayer = handler.getEditLayer();

    // need to use map coordinates in order to avoid
    // possible inconsistencies between what the user
    // drawn and the projected result
    GeometryFactory gf = new GeometryFactory();
    CoordinateReferenceSystem layerCrs = LayerUtil.getCrs(editLayer);
    CoordinateReferenceSystem mapCrs = editLayer.getMap().getViewportModel().getCRS();
    Point p1 = gf.createPoint(currentShape.getCoord(0));
    Point p2 = gf.createPoint(currentShape.getCoord(1));
    Point p3 = gf.createPoint(currentShape.getCoord(2));

    try {
      p1 = (Point) GeoToolsUtils.reproject(p1, layerCrs, mapCrs);
      p2 = (Point) GeoToolsUtils.reproject(p2, layerCrs, mapCrs);
      p3 = (Point) GeoToolsUtils.reproject(p3, layerCrs, mapCrs);
    } catch (OperationNotFoundException onfe) {
      throw new IllegalStateException(
          "Could not reproject to map crs:" + onfe.getLocalizedMessage(), onfe);
    } catch (TransformException te) {
      throw new IllegalStateException(
          "Could not reproject to map crs:" + te.getLocalizedMessage(), te);
    }

    ArcBuilder builder = new ArcBuilder();
    builder.setPoints(p1.getX(), p1.getY(), p2.getX(), p2.getY(), p3.getX(), p3.getY());

    // TODO: especificar la cantidad de segmentos por cuadrante
    // mediante una preferencia
    Geometry geom = builder.getGeometry(15);
    if (geom == null) {
      throw new IllegalStateException("null geom");
    }

    // backproject resulting geom from map crs to layer's crs
    try {
      geom = GeoToolsUtils.reproject(geom, mapCrs, layerCrs);
    } catch (OperationNotFoundException onfe) {
      throw new IllegalStateException(
          "Could not reproject back to data crs:" + onfe.getLocalizedMessage(), onfe);
    } catch (TransformException te) {
      throw new IllegalStateException(
          "Could not reproject back to data crs:" + te.getLocalizedMessage(), te);
    }

    EditCommandFactory editCmdFac = AppGISMediator.getEditCommandFactory();

    ILayer layer = editLayer;
    SimpleFeatureType schema = layer.getSchema();
    SimpleFeature feature;
    try {
      feature = SimpleFeatureBuilder.build(schema, (Object[]) null, null);
      Class type = schema.getDefaultGeometry().getType().getBinding();
      geom = GeometryUtil.adapt(geom, type);
      feature.setDefaultGeometry(geom);
    } catch (IllegalAttributeException e) {
      // consider using the bubble feedback
      throw new IllegalStateException("Could not create Arc:" + e, e);
    }
    UndoableMapCommand command = editCmdFac.createAddFeatureCommand(feature, layer);

    handler.setCurrentShape(null);
    handler.setCurrentState(EditState.NONE);

    return command;
  }