/**
   * Ensure Line crosses the other Line at a node.
   *
   * <p>
   *
   * @param layers a HashMap of key="TypeName" value="FeatureSource"
   * @param envelope The bounding box of modified features
   * @param results Storage for the error and warning messages
   * @return True if no features intersect. If they do then the validation failed.
   * @throws Exception DOCUMENT ME!
   * @see org.geotools.validation.IntegrityValidation#validate(java.util.Map,
   *     com.vividsolutions.jts.geom.Envelope, org.geotools.validation.ValidationResults)
   */
  public boolean validate(Map layers, Envelope envelope, ValidationResults results)
      throws Exception {
    boolean r = true;

    FeatureSource<SimpleFeatureType, SimpleFeature> fsLine =
        (FeatureSource<SimpleFeatureType, SimpleFeature>) layers.get(getLineTypeRef());

    FeatureCollection<SimpleFeatureType, SimpleFeature> fcLine = fsLine.getFeatures();
    FeatureIterator<SimpleFeature> fLine = fcLine.features();

    FeatureSource<SimpleFeatureType, SimpleFeature> fsRLine =
        (FeatureSource<SimpleFeatureType, SimpleFeature>) layers.get(getRestrictedLineTypeRef());

    FeatureCollection<SimpleFeatureType, SimpleFeature> fcRLine = fsRLine.getFeatures();

    while (fLine.hasNext()) {
      SimpleFeature line = fLine.next();
      FeatureIterator<SimpleFeature> fRLine = fcRLine.features();
      Geometry lineGeom = (Geometry) line.getDefaultGeometry();
      if (envelope.contains(lineGeom.getEnvelopeInternal())) {
        // 	check for valid comparison
        if (LineString.class.isAssignableFrom(lineGeom.getClass())) {
          while (fRLine.hasNext()) {
            SimpleFeature rLine = fRLine.next();
            Geometry rLineGeom = (Geometry) rLine.getDefaultGeometry();
            if (envelope.contains(rLineGeom.getEnvelopeInternal())) {
              if (LineString.class.isAssignableFrom(rLineGeom.getClass())) {
                if (lineGeom.intersects(rLineGeom)) {
                  if (!hasPair(
                      ((LineString) lineGeom).getCoordinateSequence(),
                      ((LineString) rLineGeom).getCoordinateSequence())) {
                    results.error(
                        rLine,
                        "Line does not intersect line at node covered by the specified Line.");
                    r = false;
                  }
                } else {
                  results.warning(rLine, "Does not intersect the LineString");
                }
                // do next.
              } else {
                fcRLine.remove(rLine);
                results.warning(
                    rLine, "Invalid type: this feature is not a derivative of a LineString");
              }
            } else {
              fcRLine.remove(rLine);
            }
          }
        } else {
          results.warning(line, "Invalid type: this feature is not a derivative of a LineString");
        }
      }
    }
    return r;
  }
  /**
   * <b>validateMultipleLayers Purpose:</b> <br>
   *
   * <p>This validation tests for a geometry containing another geometry. Uses JTS'
   * Geometry.contains(Geometry) method. DE-9IM intersection matrix is T*F**F***.
   * <b>Description:</b><br>
   *
   * <p>The function filters the FeatureSources using the given bounding box. It creates iterators
   * over both filtered FeatureSources. It calls contains() using the geometries in the
   * SimpleFeatureSource layers. Tests the results of the method call against the given expected
   * results. Returns true if the returned results and the expected results are true, false
   * otherwise. Author: bowens<br>
   * Created on: Apr 27, 2004<br>
   *
   * @param featureSourceA - the SimpleFeatureSource to pull the original geometries from. This
   *     geometry is the one that is tested for containing the other
   * @param featureSourceB - the SimpleFeatureSource to pull the other geometries from - these
   *     geometries will be those that may be contained within the first geometry
   * @param expected - boolean value representing the user's expected outcome of the test
   * @param results - ValidationResults
   * @param bBox - Envelope - the bounding box within which to perform the contains()
   * @return boolean result of the test
   * @throws Exception - IOException if iterators improperly closed
   */
  private boolean validateMultipleLayers(
      SimpleFeatureSource featureSourceA,
      SimpleFeatureSource featureSourceB,
      boolean expected,
      ValidationResults results,
      Envelope bBox)
      throws Exception {
    boolean success = true;

    FilterFactory ff = CommonFactoryFinder.getFilterFactory(null);
    Filter filter = null;

    SimpleFeatureCollection featureResultsA = featureSourceA.getFeatures(filter);
    SimpleFeatureCollection featureResultsB = featureSourceB.getFeatures(filter);

    SimpleFeatureIterator fr1 = null;
    SimpleFeatureIterator fr2 = null;
    try {
      fr1 = featureResultsA.features();

      if (fr1 == null) return false;

      while (fr1.hasNext()) {
        SimpleFeature f1 = fr1.next();
        Geometry g1 = (Geometry) f1.getDefaultGeometry();
        fr2 = featureResultsB.features();
        try {
          while (fr2 != null && fr2.hasNext()) {
            SimpleFeature f2 = fr2.next();
            Geometry g2 = (Geometry) f2.getDefaultGeometry();
            if (g1.contains(g2) != expected) {
              results.error(
                  f1,
                  ((Geometry) f1.getDefaultGeometry()).getGeometryType()
                      + " "
                      + getGeomTypeRefA()
                      + " contains "
                      + getGeomTypeRefB()
                      + "("
                      + f2.getID()
                      + "), Result was not "
                      + expected);
              success = false;
            }
          }
        } finally {
          fr2.close();
        }
      }
    } finally {
      fr1.close();
      fr2.close();
    }

    return success;
  }