package com.revolsys.gdal.record;
import java.sql.Date;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.TimeZone;
import org.gdal.ogr.DataSource;
import org.gdal.ogr.Feature;
import org.gdal.ogr.Layer;
import com.revolsys.collection.iterator.AbstractIterator;
import com.revolsys.geometry.model.Geometry;
import com.revolsys.geometry.model.GeometryFactory;
import com.revolsys.geometry.model.LineString;
import com.revolsys.geometry.model.LinearRing;
import com.revolsys.record.Record;
import com.revolsys.record.RecordFactory;
import com.revolsys.record.RecordState;
import com.revolsys.record.query.Query;
import com.revolsys.record.schema.RecordDefinition;
import com.revolsys.util.count.LabelCountMap;
public class OgrQueryIterator extends AbstractIterator<Record> {
private int count;
private GeometryFactory geometryFactory;
private final String idFieldName;
private Layer layer;
private final int limit;
private final int offset;
private Query query;
private RecordDefinition recordDefinition;
private RecordFactory<Record> recordFactory;
private OgrRecordStore recordStore;
private LabelCountMap labelCountMap;
protected OgrQueryIterator(final OgrRecordStore recordStore, final Query query) {
this.recordStore = recordStore;
this.query = query;
RecordFactory<Record> recordFactory = query.getRecordFactory();
if (recordFactory == null) {
recordFactory = recordStore.getRecordFactory();
}
this.recordFactory = recordFactory;
this.recordDefinition = query.getRecordDefinition();
this.offset = query.getOffset();
this.limit = query.getLimit();
this.labelCountMap = query.getStatistics();
this.geometryFactory = this.recordDefinition.getGeometryFactory();
this.idFieldName = recordStore.getIdFieldName(this.recordDefinition);
}
@Override
protected synchronized void closeDo() {
if (this.layer != null) {
this.recordStore.releaseLayerToClose(this.layer);
}
this.geometryFactory = null;
this.layer = null;
this.query = null;
this.recordDefinition = null;
this.recordFactory = null;
this.recordStore = null;
this.labelCountMap = null;
}
protected Calendar getCalendar(final Feature feature, final int fieldIndex) {
final int[] year = new int[1];
final int[] month = new int[1];
final int[] day = new int[1];
final int[] hour = new int[1];
final int[] minute = new int[1];
final int[] second = new int[1];
final int[] timeZoneId = new int[1];
feature.GetFieldAsDateTime(fieldIndex, year, month, day, hour, minute, second, timeZoneId);
TimeZone timeZone;
if (timeZoneId[0] == 100) {
timeZone = TimeZone.getTimeZone("GMT");
} else {
timeZone = TimeZone.getDefault();
}
final Calendar calendar = new GregorianCalendar(timeZone);
calendar.set(Calendar.YEAR, year[0]);
calendar.set(Calendar.MONTH, month[0]);
calendar.set(Calendar.DAY_OF_MONTH, day[0]);
calendar.set(Calendar.HOUR, hour[0]);
calendar.set(Calendar.MINUTE, minute[0]);
calendar.set(Calendar.SECOND, second[0]);
return calendar;
}
protected double[] getCoordinates(final org.gdal.ogr.Geometry ogrGeometry, final int axisCount) {
final int vertexCount = ogrGeometry.GetPointCount();
final double[] coordinates = new double[vertexCount * axisCount];
int coordinateIndex = 0;
for (int vertexIndex = 0; vertexIndex < vertexCount; vertexIndex++) {
coordinates[coordinateIndex++] = ogrGeometry.GetX(vertexIndex);
coordinates[coordinateIndex++] = ogrGeometry.GetY(vertexIndex);
if (axisCount > 2) {
coordinates[coordinateIndex++] = ogrGeometry.GetZ(vertexIndex);
}
}
return coordinates;
}
@Override
protected Record getNext() throws NoSuchElementException {
if (this.layer == null) {
throw new NoSuchElementException();
} else {
while (this.offset > 0 && this.count < this.offset) {
final Feature feature = this.layer.GetNextFeature();
if (feature == null) {
throw new NoSuchElementException();
} else {
feature.delete();
}
this.count++;
}
if (this.count - this.offset >= this.limit) {
throw new NoSuchElementException();
}
final Feature feature = this.layer.GetNextFeature();
this.count++;
if (feature == null) {
throw new NoSuchElementException();
} else {
try {
final Record record = this.recordFactory.newRecord(this.recordDefinition);
record.setState(RecordState.INITIALIZING);
if (this.labelCountMap == null) {
this.recordStore.addStatistic("query", record);
} else {
this.labelCountMap.addCount(record);
}
final int fieldCount = feature.GetFieldCount();
for (int fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) {
final String fieldName = feature.GetFieldDefnRef(fieldIndex).GetName();
if (feature.IsFieldSet(fieldIndex)) {
final int fieldType = feature.GetFieldType(fieldIndex);
Object value;
switch (fieldType) {
case 0:
value = feature.GetFieldAsInteger(fieldIndex);
break;
case 1:
value = feature.GetFieldAsIntegerList(fieldIndex);
break;
case 2:
value = feature.GetFieldAsDouble(fieldIndex);
break;
case 3:
value = feature.GetFieldAsDoubleList(fieldIndex);
break;
case 4:
case 6:
value = feature.GetFieldAsString(fieldIndex);
break;
case 5:
case 7:
value = feature.GetFieldAsStringList(fieldIndex);
break;
case 8:
value = null;
// binary
break;
case 9:
final Calendar date = getCalendar(feature, fieldIndex);
value = new Date(date.getTimeInMillis());
break;
case 10:
value = null;
// time
break;
case 11:
final Calendar dateTime = getCalendar(feature, fieldIndex);
value = new java.util.Date(dateTime.getTimeInMillis());
break;
default:
value = null;
break;
}
record.setValue(fieldName, value);
}
}
final int geometryCount = feature.GetGeomFieldCount();
for (int geometryIndex = 0; geometryIndex < geometryCount; geometryIndex++) {
final String fieldName = feature.GetGeomFieldDefnRef(geometryIndex).GetName();
final org.gdal.ogr.Geometry ogrGeometry = feature.GetGeomFieldRef(geometryIndex);
final Geometry geometry = toGeometry(ogrGeometry);
record.setValue(fieldName, geometry);
}
record.setState(RecordState.PERSISTED);
return record;
} finally {
feature.delete();
}
}
}
}
@Override
protected synchronized void initDo() {
if (this.recordStore != null) {
final DataSource dataSource = this.recordStore.getDataSource();
if (dataSource != null) {
final String sql = this.recordStore.getSql(this.query);
this.layer = dataSource.ExecuteSQL(sql);
this.recordStore.addLayerToClose(this.layer);
}
}
}
protected Geometry toGeometry(final org.gdal.ogr.Geometry ogrGeometry) {
if (ogrGeometry == null) {
return null;
} else {
final int geometryType = ogrGeometry.GetGeometryType();
final int axisCount = ogrGeometry.GetCoordinateDimension();
switch (geometryType) {
case 1:
case 0x80000000 + 1:
final double[] pointCoordinates = getCoordinates(ogrGeometry, axisCount);
return this.geometryFactory.point(pointCoordinates);
case 2:
case 0x80000000 + 2:
final double[] lineCoordinates = getCoordinates(ogrGeometry, axisCount);
return this.geometryFactory.lineString(axisCount, lineCoordinates);
case 3:
case 0x80000000 + 3:
final List<LineString> rings = new ArrayList<>();
for (int partIndex = 0; partIndex < ogrGeometry.GetGeometryCount(); partIndex++) {
final org.gdal.ogr.Geometry ogrRing = ogrGeometry.GetGeometryRef(partIndex);
final double[] ringCoordinates = getCoordinates(ogrRing, axisCount);
final LinearRing ring = this.geometryFactory.linearRing(axisCount, ringCoordinates);
rings.add(ring);
}
return this.geometryFactory.polygon(rings);
case 4:
case 0x80000000 + 4:
case 5:
case 0x80000000 + 5:
case 6:
case 0x80000000 + 6:
case 7:
case 0x80000000 + 7:
final List<Geometry> parts = new ArrayList<>();
for (int partIndex = 0; partIndex < ogrGeometry.GetGeometryCount(); partIndex++) {
final org.gdal.ogr.Geometry ogrPart = ogrGeometry.GetGeometryRef(partIndex);
final Geometry part = toGeometry(ogrPart);
parts.add(part);
}
return this.geometryFactory.geometry(parts);
case 101:
final double[] ringCoordinates = getCoordinates(ogrGeometry, axisCount);
return this.geometryFactory.linearRing(axisCount, ringCoordinates);
default:
return null;
}
}
}
@Override
public String toString() {
if (this.query == null) {
return super.toString();
} else {
return this.query.toString();
}
}
}