package com.github.pfichtner.jrunalyser.base.data.jaxb;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.math.BigDecimal;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.PropertyException;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import com.github.pfichtner.jrunalyser.base.data.LinkedTrackPoint;
import com.github.pfichtner.jrunalyser.base.data.track.Metadata;
import com.github.pfichtner.jrunalyser.base.data.track.Track;
import com.google.common.base.Throwables;
import com.topografix.gpx._1._1.GpxType;
import com.topografix.gpx._1._1.MetadataType;
import com.topografix.gpx._1._1.ObjectFactory;
import com.topografix.gpx._1._1.TrkType;
import com.topografix.gpx._1._1.TrksegType;
import com.topografix.gpx._1._1.WptType;
public final class GpxMarshaller {
private GpxMarshaller() {
super();
}
public static void writeTrack(Writer writer, Track track)
throws IOException {
try {
createMarshaller().marshal(createJaxbElement(toGpxType(track)),
writer);
} catch (Exception e) {
throw new IOException("Error writing to " + writer, e);
}
}
public static void writeTrack(File file, Track track) throws IOException {
try {
createMarshaller().marshal(createJaxbElement(toGpxType(track)),
file);
} catch (Exception e) {
throw new IOException("Error writing " + file, e);
}
}
private static JAXBElement<GpxType> createJaxbElement(GpxType gpxType) {
return new ObjectFactory().createGpx(gpxType);
}
private static Marshaller createMarshaller() throws JAXBException,
PropertyException {
Marshaller marshaller = JAXBContext.newInstance(GpxType.class)
.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
return marshaller;
}
private static GpxType toGpxType(Track track) {
GpxType gpxType = new GpxType();
gpxType.setMetadata(createMetaData(track.getMetadata()));
TrkType trkType = new TrkType();
TrksegType trksegType = new TrksegType();
List<WptType> trkpt = trksegType.getTrkpt();
for (LinkedTrackPoint ltrkpts : (List<? extends LinkedTrackPoint>) track
.getTrackpoints()) {
trkpt.add(createWptType(ltrkpts));
}
trkType.getTrkseg().add(trksegType);
gpxType.getTrk().add(trkType);
return gpxType;
}
private static MetadataType createMetaData(Metadata metadata) {
MetadataType result = new MetadataType();
result.setDesc(metadata.getDescription());
result.setName(metadata.getName());
if (metadata.getTime() != null) {
result.setTime(toXMLGregorianCalendar(metadata.getTime()));
}
return result;
}
private static WptType createWptType(LinkedTrackPoint wp) {
WptType result = new WptType();
if (wp.getElevation() != null) {
result.setEle(new BigDecimal(wp.getElevation().toString()));
}
result.setLat(BigDecimal.valueOf(wp.getLatitude()));
result.setLon(BigDecimal.valueOf(wp.getLongitude()));
result.setTime(toXMLGregorianCalendar(wp.getTime()));
return result;
}
private static XMLGregorianCalendar toXMLGregorianCalendar(Long time) {
return time == null ? null : toXMLGregorianCalendar(new Date(
time.longValue()));
}
private static XMLGregorianCalendar toXMLGregorianCalendar(Date date) {
try {
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(date);
XMLGregorianCalendar newXMLGregorianCalendar = DatatypeFactory
.newInstance().newXMLGregorianCalendar(cal);
return newXMLGregorianCalendar;
} catch (DatatypeConfigurationException e) {
throw Throwables.propagate(e);
}
}
}