package com.revolsys.record.io.format.gpx;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import javax.xml.namespace.QName;
import com.revolsys.geometry.model.Geometry;
import com.revolsys.geometry.model.LineString;
import com.revolsys.geometry.model.Point;
import com.revolsys.io.AbstractRecordWriter;
import com.revolsys.record.Record;
import com.revolsys.record.io.format.xml.XmlWriter;
public class GpxWriter extends AbstractRecordWriter {
private String commentAttribute = "comment";
private String descriptionAttribute = "description";
private File file;
private String nameAttribute = "name";
private final XmlWriter out;
public GpxWriter(final File file) throws IOException {
this(new FileWriter(file));
this.file = file;
}
public GpxWriter(final Writer writer) {
this.out = new XmlWriter(new BufferedWriter(writer));
this.out.setIndent(false);
this.out.startDocument("UTF-8", "1.0");
this.out.startTag(GpxConstants.GPX_ELEMENT);
this.out.attribute(GpxConstants.VERSION_ATTRIBUTE, "1.1");
this.out.attribute(GpxConstants.CREATOR_ATTRIBUTE, "Revolution Systems Inc. - GIS");
}
@Override
public void close() {
this.out.endTag();
this.out.endDocument();
this.out.close();
}
@Override
public void flush() {
this.out.flush();
}
public String getCommentAttribute() {
return this.commentAttribute;
}
public String getDescriptionAttribute() {
return this.descriptionAttribute;
}
public String getNameAttribute() {
return this.nameAttribute;
}
public void setCommentAttribute(final String commentAttribute) {
this.commentAttribute = commentAttribute;
}
public void setDescriptionAttribute(final String descriptionAttribute) {
this.descriptionAttribute = descriptionAttribute;
}
public void setNameAttribute(final String nameAttribute) {
this.nameAttribute = nameAttribute;
}
@Override
public String toString() {
return this.file.getAbsolutePath();
}
@Override
public void write(final Record object) {
try {
final Geometry geometry = object.getGeometry();
if (geometry instanceof Point) {
writeWaypoint(object);
} else if (geometry instanceof LineString) {
writeTrack(object);
}
} catch (final IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
private void writeAttributes(final Record object) {
final Object time = object.getValue("timestamp");
if (time != null) {
if (time instanceof Date) {
final DateFormat timestampFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
timestampFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
this.out.element(GpxConstants.TIME_ELEMENT, timestampFormat.format(time));
} else {
this.out.element(GpxConstants.TIME_ELEMENT, time.toString());
}
}
writeElement(object, GpxConstants.NAME_ELEMENT, this.nameAttribute);
writeElement(object, GpxConstants.COMMENT_ELEMENT, this.commentAttribute);
writeElement(object, GpxConstants.DESCRIPTION_ELEMENT, this.descriptionAttribute);
}
private void writeElement(final Record object, final QName tag, final String fieldName) {
final String name = object.getValue(fieldName);
if (name != null && name.length() > 0) {
this.out.element(tag, name);
}
}
private void writeTrack(final Record object) throws IOException {
this.out.startTag(GpxConstants.TRACK_ELEMENT);
LineString line = object.getGeometry();
line = line.convertGeometry(GpxConstants.GEOMETRY_FACTORY);
writeAttributes(object);
this.out.startTag(GpxConstants.TRACK_SEGMENT_ELEMENT);
final int vertexCount = line.getVertexCount();
for (int vertexIndex = 0; vertexIndex < vertexCount; vertexIndex++) {
final double x = line.getX(vertexIndex);
final double y = line.getY(vertexIndex);
this.out.startTag(GpxConstants.TRACK_POINT_ELEMENT);
this.out.attribute(GpxConstants.LON_ATTRIBUTE, x);
this.out.attribute(GpxConstants.LAT_ATTRIBUTE, y);
if (line.getAxisCount() > 2) {
final double elevation = line.getZ(vertexIndex);
if (!Double.isNaN(elevation)) {
this.out.element(GpxConstants.ELEVATION_ELEMENT, String.valueOf(elevation));
}
}
this.out.endTag(GpxConstants.TRACK_POINT_ELEMENT);
}
this.out.endTag(GpxConstants.TRACK_SEGMENT_ELEMENT);
this.out.endTag(GpxConstants.TRACK_ELEMENT);
}
private void writeWaypoint(final Record wayPoint) throws IOException {
this.out.startTag(GpxConstants.WAYPOINT_ELEMENT);
final Point point = wayPoint.getGeometry();
final Point geoPoint = point.convertGeometry(GpxConstants.GEOMETRY_FACTORY);
this.out.attribute(GpxConstants.LON_ATTRIBUTE, geoPoint.getX());
this.out.attribute(GpxConstants.LAT_ATTRIBUTE, geoPoint.getY());
if (point.getAxisCount() > 2) {
final double elevation = geoPoint.getZ();
if (!Double.isNaN(elevation)) {
this.out.element(GpxConstants.ELEVATION_ELEMENT, String.valueOf(elevation));
}
}
writeAttributes(wayPoint);
this.out.endTag(GpxConstants.WAYPOINT_ELEMENT);
}
}