package com.revolsys.record.io.format.csv;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.revolsys.collection.iterator.AbstractIterator;
import com.revolsys.collection.map.Maps;
import com.revolsys.datatype.DataType;
import com.revolsys.datatype.DataTypes;
import com.revolsys.geometry.model.Geometry;
import com.revolsys.geometry.model.GeometryFactory;
import com.revolsys.io.PathName;
import com.revolsys.record.Record;
import com.revolsys.record.RecordFactory;
import com.revolsys.record.io.RecordReader;
import com.revolsys.record.property.FieldProperties;
import com.revolsys.record.schema.FieldDefinition;
import com.revolsys.record.schema.RecordDefinition;
import com.revolsys.record.schema.RecordDefinitionImpl;
import com.revolsys.record.schema.RecordStoreSchema;
import com.revolsys.util.Property;
public abstract class AbstractRecordReader extends AbstractIterator<Record>
implements RecordReader {
private String geometryColumnName;
private GeometryFactory geometryFactory = GeometryFactory.DEFAULT_3D;
private DataType geometryType = DataTypes.GEOMETRY;
private boolean hasPointFields;
private String pointXFieldName;
private String pointYFieldName;
private RecordDefinition recordDefinition;
private RecordFactory<? extends Record> recordFactory;
public AbstractRecordReader(final RecordFactory<? extends Record> recordFactory) {
this.recordFactory = recordFactory;
}
@Override
protected void closeDo() {
this.recordFactory = null;
this.geometryFactory = null;
}
@Override
public GeometryFactory getGeometryFactory() {
return this.geometryFactory;
}
public String getPointXFieldName() {
return this.pointXFieldName;
}
public String getPointYFieldName() {
return this.pointYFieldName;
}
@Override
public RecordDefinition getRecordDefinition() {
open();
return this.recordDefinition;
}
@SuppressWarnings("unchecked")
@Override
public <R extends Record> RecordFactory<R> getRecordFactory() {
return (RecordFactory<R>)this.recordFactory;
}
@Override
protected void initDo() {
this.pointXFieldName = getProperty("pointXFieldName");
this.pointYFieldName = getProperty("pointYFieldName");
this.geometryColumnName = getProperty("geometryColumnName", "GEOMETRY");
this.geometryFactory = GeometryFactory.get(getProperty("geometryFactory"));
if (this.geometryFactory == null || this.geometryFactory == GeometryFactory.DEFAULT_3D) {
final Integer geometrySrid = Property.getInteger(this, "geometrySrid");
if (geometrySrid == null) {
this.geometryFactory = loadGeometryFactory();
} else {
this.geometryFactory = GeometryFactory.floating3(geometrySrid);
}
}
if (this.geometryFactory == null) {
this.geometryFactory = GeometryFactory.DEFAULT_3D;
}
final DataType geometryType = DataTypes.getDataType((String)getProperty("geometryType"));
if (Geometry.class.isAssignableFrom(geometryType.getJavaClass())) {
this.geometryType = geometryType;
}
}
public boolean isHasPointFields() {
return this.hasPointFields;
}
protected GeometryFactory loadGeometryFactory() {
return GeometryFactory.DEFAULT_3D;
}
protected Record newRecord() {
return this.recordFactory.newRecord(this.recordDefinition);
}
protected RecordDefinition newRecordDefinition(final String baseName,
final List<String> fieldNames) throws IOException {
this.hasPointFields = Property.hasValue(this.pointXFieldName)
&& Property.hasValue(this.pointYFieldName);
if (this.hasPointFields) {
this.geometryType = DataTypes.POINT;
} else {
this.pointXFieldName = null;
this.pointYFieldName = null;
}
final List<FieldDefinition> fields = new ArrayList<>();
FieldDefinition geometryField = null;
for (final String fieldName : fieldNames) {
if (fieldName != null) {
DataType type;
int length = 0;
boolean isGeometryField = false;
if (fieldName.equalsIgnoreCase(this.geometryColumnName)) {
type = this.geometryType;
isGeometryField = true;
} else if ("GEOMETRY".equalsIgnoreCase(fieldName)) {
type = DataTypes.GEOMETRY;
isGeometryField = true;
} else if ("SHAPE".equalsIgnoreCase(fieldName)) {
type = DataTypes.GEOMETRY;
isGeometryField = true;
} else if ("GEOMETRYCOLLECTION".equalsIgnoreCase(fieldName)
|| "GEOMETRY_COLLECTION".equalsIgnoreCase(fieldName)) {
type = DataTypes.GEOMETRY_COLLECTION;
isGeometryField = true;
} else if ("POINT".equalsIgnoreCase(fieldName)) {
type = DataTypes.POINT;
isGeometryField = true;
} else if ("MULTI_POINT".equalsIgnoreCase(fieldName)
|| "MULTIPOINT".equalsIgnoreCase(fieldName)) {
type = DataTypes.MULTI_POINT;
isGeometryField = true;
} else if ("LINE_STRING".equalsIgnoreCase(fieldName)
|| "LINESTRING".equalsIgnoreCase(fieldName) || "LINE".equalsIgnoreCase(fieldName)) {
type = DataTypes.LINE_STRING;
isGeometryField = true;
} else if ("MULTI_LINESTRING".equalsIgnoreCase(fieldName)
|| "MULTILINESTRING".equalsIgnoreCase(fieldName)
|| "MULTILINE".equalsIgnoreCase(fieldName) || "MULTI_LINE".equalsIgnoreCase(fieldName)) {
type = DataTypes.MULTI_LINE_STRING;
isGeometryField = true;
} else if ("POLYGON".equalsIgnoreCase(fieldName)) {
type = DataTypes.POLYGON;
isGeometryField = true;
} else if ("MULTI_POLYGON".equalsIgnoreCase(fieldName)
|| "MULTIPOLYGON".equalsIgnoreCase(fieldName)) {
type = DataTypes.MULTI_POLYGON;
isGeometryField = true;
} else {
type = DataTypes.STRING;
length = 4000;
}
final FieldDefinition field = new FieldDefinition(fieldName, type, length, false);
if (isGeometryField) {
geometryField = field;
}
fields.add(field);
}
}
if (this.hasPointFields) {
if (geometryField == null) {
geometryField = new FieldDefinition(this.geometryColumnName, this.geometryType, true);
fields.add(geometryField);
}
}
if (geometryField != null) {
geometryField.setProperty(FieldProperties.GEOMETRY_FACTORY, this.geometryFactory);
}
final RecordStoreSchema schema = getProperty("schema");
String typePath = getProperty("typePath");
if (!Property.hasValue(typePath)) {
typePath = "/" + baseName;
String schemaPath = getProperty("schemaPath");
if (Property.hasValue(schemaPath)) {
if (!schemaPath.startsWith("/")) {
schemaPath = "/" + schemaPath;
}
typePath = schemaPath + typePath;
}
}
final PathName pathName = PathName.newPathName(typePath);
this.recordDefinition = new RecordDefinitionImpl(schema, pathName, getProperties(), fields);
return this.recordDefinition;
}
/**
* Parse a record containing an array of String values into a Record with
* the strings converted to the objects based on the attribute data type.
*
* @param values The record.
* @return The Record.
*/
protected Record parseRecord(final List<String> values) {
final Record record = this.recordFactory.newRecord(this.recordDefinition);
final int valueCount = values.size();
final int fieldCount = this.recordDefinition.getFieldCount();
final int count = Math.min(valueCount, fieldCount);
for (int i = 0; i < count; i++) {
final String valueString = values.get(i);
if (valueString != null) {
final DataType dataType = this.recordDefinition.getFieldType(i);
final Object convertedValue = dataType.toObject(valueString);
record.setValue(i, convertedValue);
}
}
if (this.hasPointFields) {
final Double x = Maps.getDouble(record, this.pointXFieldName);
final Double y = Maps.getDouble(record, this.pointYFieldName);
if (x != null && y != null) {
final GeometryFactory geometryFactory = getGeometryFactory();
final Geometry geometry = geometryFactory.point(x, y);
record.setGeometryValue(geometry);
}
}
return record;
}
public void setGeometryColumnName(final String geometryColumnName) {
this.geometryColumnName = geometryColumnName;
}
public void setGeometryFactory(final GeometryFactory geometryFactory) {
this.geometryFactory = geometryFactory;
}
public void setPointXFieldName(final String pointXFieldName) {
this.pointXFieldName = pointXFieldName;
}
public void setPointYFieldName(final String pointYFieldName) {
this.pointYFieldName = pointYFieldName;
}
protected void setRecordDefinition(final RecordDefinition recordDefinition) {
this.recordDefinition = recordDefinition;
}
}