private Point parsePoint(int dimension, CoordinateReferenceSystem crs)
      throws XmlPullParserException, IOException, NoSuchAuthorityCodeException, FactoryException {

    parser.require(START_TAG, GML.NAMESPACE, GML.Point.getLocalPart());

    crs = crs(crs);

    Point geom;
    parser.nextTag();
    parser.require(START_TAG, GML.NAMESPACE, null);
    Coordinate point;
    if (GML.pos.getLocalPart().equals(parser.getName())) {
      Coordinate[] coords = parseCoordList(dimension, crs);
      point = coords[0];
      parser.nextTag();
    } else if (GML.coordinates.getLocalPart().equals(parser.getName())) {
      Coordinate[] coords = parseCoordinates(dimension, crs);
      point = coords[0];
      parser.nextTag();
    } else if (GML.coord.getLocalPart().equals(parser.getName())) {
      point = parseCoord();
      parser.nextTag();
    } else {
      throw new IllegalStateException("Unknown coordinate element for Point: " + parser.getName());
    }

    parser.require(END_TAG, GML.NAMESPACE, GML.Point.getLocalPart());

    geom = geomFac.createPoint(point);
    geom.setUserData(crs);
    return geom;
  }
  /**
   * Precondition: parser cursor positioned on a geometry property (ej, {@code gml:Point}, etc)
   *
   * <p>Postcondition: parser gets positioned at the end tag of the element it started parsing the
   * geometry at
   *
   * @return
   * @throws FactoryException
   * @throws NoSuchAuthorityCodeException
   * @throws IOException
   * @throws XmlPullParserException
   */
  private Geometry parseGeom()
      throws NoSuchAuthorityCodeException, FactoryException, XmlPullParserException, IOException {
    final QName startingGeometryTagName = new QName(parser.getNamespace(), parser.getName());
    int dimension = crsDimension(2);
    CoordinateReferenceSystem crs = crs(DefaultGeographicCRS.WGS84);

    Geometry geom;
    if (GML.Point.equals(startingGeometryTagName)) {
      geom = parsePoint(dimension, crs);
    } else if (GML.LineString.equals(startingGeometryTagName)) {
      geom = parseLineString(dimension, crs);
    } else if (GML.Polygon.equals(startingGeometryTagName)) {
      geom = parsePolygon(dimension, crs);
    } else if (GML.MultiPoint.equals(startingGeometryTagName)) {
      geom = parseMultiPoint(dimension, crs);
    } else if (GML.MultiLineString.equals(startingGeometryTagName)) {
      geom = parseMultiLineString(dimension, crs);
    } else if (GML.MultiSurface.equals(startingGeometryTagName)) {
      geom = parseMultiSurface(dimension, crs);
    } else if (GML.MultiPolygon.equals(startingGeometryTagName)) {
      geom = parseMultiPolygon(dimension, crs);
    } else {
      throw new IllegalStateException("Unrecognized geometry element " + startingGeometryTagName);
    }

    parser.require(
        END_TAG, startingGeometryTagName.getNamespaceURI(), startingGeometryTagName.getLocalPart());

    return geom;
  }
  /**
   * Parses a MultiPoint.
   *
   * <p>Precondition: parser positioned at a {@link GML#MultiPoint MultiPoint} start tag
   *
   * <p>Postcondition: parser positioned at the {@link GML#MultiPoint MultiPoint} end tag of the
   * starting tag
   *
   * @throws IOException
   * @throws XmlPullParserException
   * @throws IOException
   * @throws XmlPullParserException
   * @throws FactoryException
   * @throws NoSuchAuthorityCodeException
   * @throws FactoryException
   * @throws NoSuchAuthorityCodeException
   */
  private Geometry parseMultiPoint(int dimension, CoordinateReferenceSystem crs)
      throws XmlPullParserException, IOException, NoSuchAuthorityCodeException, FactoryException {
    Geometry geom;
    parser.nextTag();
    final QName memberTag = new QName(parser.getNamespace(), parser.getName());
    List<Point> points = new ArrayList<Point>(4);
    if (GML.pointMembers.equals(memberTag)) {
      while (true) {
        parser.nextTag();
        if (END_TAG == parser.getEventType()
            && GML.pointMembers.getLocalPart().equals(parser.getName())) {
          // we're done
          break;
        }
        Point p = parsePoint(dimension, crs);
        points.add(p);
      }
      parser.nextTag();
    } else if (GML.pointMember.equals(memberTag)) {
      while (true) {
        parser.nextTag();
        parser.require(START_TAG, GML.NAMESPACE, GML.Point.getLocalPart());

        Point p = parsePoint(dimension, crs);
        points.add(p);
        parser.nextTag();
        parser.require(END_TAG, GML.NAMESPACE, GML.pointMember.getLocalPart());
        parser.nextTag();
        if (END_TAG == parser.getEventType()
            && GML.MultiPoint.getLocalPart().equals(parser.getName())) {
          // we're done
          break;
        }
      }
    }
    parser.require(END_TAG, GML.NAMESPACE, GML.MultiPoint.getLocalPart());

    geom = geomFac.createMultiPoint(points.toArray(new Point[points.size()]));
    return geom;
  }