/**
   * return a single geometry collection <br>
   * result.GeometryN(i) = the i-th feature in the FeatureCollection<br>
   * All the geometry types will be the same type (ie. all polygons) - or they will be set to<br>
   * NULL geometries<br>
   * <br>
   * GeometryN(i) = {Multipoint,Multilinestring, or Multipolygon)<br>
   *
   * @param fc feature collection to make homogeneous
   */
  public GeometryCollection makeSHAPEGeometryCollection(FeatureCollection fc) throws Exception {
    GeometryCollection result;
    Geometry[] allGeoms = new Geometry[fc.size()];

    int geomtype = findBestGeometryType(fc);

    if (geomtype == 0) {
      throw new Exception(
          "Could not determine shapefile type - data is either all GeometryCollections or empty");
    }

    List features = fc.getFeatures();

    for (int t = 0; t < features.size(); t++) {
      Geometry geom;
      geom = ((Feature) features.get(t)).getGeometry();

      switch (geomtype) {
        case 1: // point
          if ((geom instanceof Point)) {
            // good!
            Point[] p = new Point[1];
            p[0] = (Point) geom;

            allGeoms[t] = new MultiPoint(p, new PrecisionModel(), 0);
          } else if (geom instanceof MultiPoint) {
            allGeoms[t] = geom;
          } else {
            allGeoms[t] = new MultiPoint(null, new PrecisionModel(), 0);
          }

          break;

        case 2: // line
          if ((geom instanceof LineString)) {
            LineString[] l = new LineString[1];
            l[0] = (LineString) geom;

            allGeoms[t] = new MultiLineString(l, new PrecisionModel(), 0);
          } else if (geom instanceof MultiLineString) {
            allGeoms[t] = geom;
          } else {
            allGeoms[t] = new MultiLineString(null, new PrecisionModel(), 0);
          }

          break;

        case 3: // polygon
          if (geom instanceof Polygon) {
            // good!
            Polygon[] p = new Polygon[1];
            p[0] = (Polygon) geom;

            allGeoms[t] = makeGoodSHAPEMultiPolygon(new MultiPolygon(p, new PrecisionModel(), 0));
          } else if (geom instanceof MultiPolygon) {
            allGeoms[t] = makeGoodSHAPEMultiPolygon((MultiPolygon) geom);
          } else {
            allGeoms[t] = new MultiPolygon(null, new PrecisionModel(), 0);
          }

          break;
      }
    }

    result = new GeometryCollection(allGeoms, new PrecisionModel(), 0);

    return result;
  }
  /**
   * Write a dbf file with the information from the featureCollection.
   *
   * @param featureCollection column data from collection
   * @param fname name of the dbf file to write to
   */
  void writeDbf(FeatureCollection featureCollection, String fname) throws Exception {
    DbfFileWriter dbf;
    FeatureSchema fs;
    int t;
    int f;
    int u;
    int num;

    fs = featureCollection.getFeatureSchema();

    // -1 because one of the columns is geometry
    DbfFieldDef[] fields = new DbfFieldDef[fs.getAttributeCount() - 1];

    // dbf column type and size
    f = 0;

    for (t = 0; t < fs.getAttributeCount(); t++) {
      AttributeType columnType = fs.getAttributeType(t);
      String columnName = fs.getAttributeName(t);

      if (columnType == AttributeType.INTEGER) {
        fields[f] = new DbfFieldDef(columnName, 'N', 16, 0);
        f++;
      } else if (columnType == AttributeType.DOUBLE) {
        fields[f] = new DbfFieldDef(columnName, 'N', 33, 16);
        f++;
      } else if (columnType == AttributeType.STRING) {
        int maxlength = findMaxStringLength(featureCollection, t);

        if (maxlength > 255) {
          throw new Exception(
              "ShapefileWriter does not support strings longer than 255 characters");
        }

        fields[f] = new DbfFieldDef(columnName, 'C', maxlength, 0);
        f++;
      } else if (columnType == AttributeType.DATE) {
        fields[f] = new DbfFieldDef(columnName, 'D', 8, 0);
        f++;
      } else if (columnType == AttributeType.GEOMETRY) {
        // do nothing - the .shp file handles this
      } else {
        throw new Exception("Shapewriter: unsupported AttributeType found in featurecollection.");
      }
    }

    // write header
    dbf = new DbfFileWriter(fname);
    dbf.writeHeader(fields, featureCollection.size());

    // write rows
    num = featureCollection.size();

    List features = featureCollection.getFeatures();

    for (t = 0; t < num; t++) {
      // System.out.println("dbf: record "+t);
      Feature feature = (Feature) features.get(t);
      Vector DBFrow = new Vector();

      // make data for each column in this feature (row)
      for (u = 0; u < fs.getAttributeCount(); u++) {
        AttributeType columnType = fs.getAttributeType(u);

        if (columnType == AttributeType.INTEGER) {
          Object a = feature.getAttribute(u);

          if (a == null) {
            DBFrow.add(new Integer(0));
          } else {
            DBFrow.add((Integer) a);
          }
        } else if (columnType == AttributeType.DOUBLE) {
          Object a = feature.getAttribute(u);

          if (a == null) {
            DBFrow.add(new Double(0.0));
          } else {
            DBFrow.add((Double) a);
          }
        } else if (columnType == AttributeType.DATE) {
          Object a = feature.getAttribute(u);
          if (a == null) {
            DBFrow.add("");
          } else {
            DBFrow.add(DbfFile.DATE_PARSER.format((Date) a));
          }
        } else if (columnType == AttributeType.STRING) {
          Object a = feature.getAttribute(u);

          if (a == null) {
            DBFrow.add(new String(""));
          } else {
            // MD 16 jan 03 - added some defensive programming
            if (a instanceof String) {
              DBFrow.add(a);
            } else {
              DBFrow.add(a.toString());
            }
          }
        }
      }

      dbf.writeRecord(DBFrow);
    }

    dbf.close();
  }