package jeql.io.shapefile;
import java.io.IOException;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import jeql.api.row.ArrayRowList;
import jeql.api.row.Row;
import jeql.api.row.RowSchema;
import org.geotools.dbffile.DbfFieldDef;
import org.geotools.dbffile.DbfFile;
import org.geotools.dbffile.DbfFileException;
import org.geotools.dbffile.DbfFileWriter;
import com.vividsolutions.jts.geom.Geometry;
class TableDbfWriter {
public TableDbfWriter() {
}
/**
* Write a dbf file with the information from a RowList.
*
* @param RowList
* column data from collection
* @param fname
* name of the dbf file to write to
*/
void write(ArrayRowList memRowList, String fname)
throws IOException, DbfFileException {
RowSchema schema = memRowList.getSchema();
List rows = memRowList.getRows();
int num = rows.size();
DbfFieldDef[] fields = createFields(memRowList);
// write header
DbfFileWriter dbf = new DbfFileWriter(fname);
dbf.writeHeader(fields, num);
// write rows
for (int t = 0; t < num; t++) {
// System.out.println("dbf: record "+t);
Row row = (Row) rows.get(t);
Vector DBFrow = new Vector();
// make data for each column in this row
for (int u = 0; u < schema.size(); u++) {
Class columnType = schema.getType(u);
Object a = row.getValue(u);
if (columnType == Integer.class) {
if (a == null) {
DBFrow.add(new Integer(0));
} else {
DBFrow.add((Integer) a);
}
} else if (columnType == Double.class) {
if (a == null) {
DBFrow.add(new Double(0.0));
} else {
DBFrow.add((Double) a);
}
}
// not handled for now
else if (columnType == Date.class) {
if (a == null) {
DBFrow.add("");
} else {
DBFrow.add(DbfFile.DATE_PARSER.format((Date) a));
}
}
else if (columnType == String.class) {
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();
}
private DbfFieldDef[] createFields(ArrayRowList rowList)
throws IOException {
RowSchema schema = rowList.getSchema();
// -1 because one of the columns is geometry
DbfFieldDef[] fields = new DbfFieldDef[nonGeomColumnCount(schema)];
// dbf column type and size
int f = 0;
for (int i = 0; i < schema.size(); i++) {
Class columnType = schema.getType(i);
String columnName = schema.getName(i);
if (columnType == Integer.class) {
fields[f] = new DbfFieldDef(columnName, 'N', 16, 0);
f++;
} else if (columnType == Double.class) {
fields[f] = new DbfFieldDef(columnName, 'N', 33, 16);
f++;
} else if (columnType == String.class) {
int maxlength = findMaxStringLength(rowList, i);
if (maxlength > 255) {
throw new IOException(
"DBF files do not support strings longer than 255 characters");
}
fields[f] = new DbfFieldDef(columnName, 'C', maxlength, 0);
f++;
} else if (columnType == Date.class) {
fields[f] = new DbfFieldDef(columnName, 'D', 8, 0);
f++;
}
else if (columnType == Geometry.class) {
// do nothing - the .shp file handles this
} else {
throw new IOException("Unsupported attribute type");
}
}
return fields;
}
/**
* look at all the data in the column of the featurecollection, and find the
* largest string!
*
* @param fc
* features to look at
* @param attributeNumber
* which of the column to test.
* @return the maximum length of the strings in the column
* @return 0 if there are no rows
*/
private int findMaxStringLength(ArrayRowList rowList, int index) {
int maxLen = 0;
for (Iterator i = rowList.getRows().iterator(); i.hasNext();) {
Row row = (Row) i.next();
String s = (String) row.getValue(index);
if (s != null) {
int len = s.length();
if (len > maxLen) {
maxLen = len;
}
}
}
return maxLen;
}
private static int nonGeomColumnCount(RowSchema schema) {
int count = 0;
for (int t = 0; t < schema.size(); t++) {
Class colType = schema.getType(t);
if (colType != Geometry.class)
count++;
}
return count;
}
}