/*
* KMLExporter.java - Copyright(c) 2013, 2014 Joe Pasqua
* Provided under the MIT License. See the LICENSE file for details.
* Created: Nov 27, 2013
*/
package org.noroomattheinn.visibletesla.data;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.util.Date;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.FileUtils;
import static org.noroomattheinn.tesla.Tesla.logger;
/**
* KMLExporter: Export a Trip to a KML file
*
* @author Joe Pasqua <joe at NoRoomAtTheInn dot org>
*/
class KMLExporter {
private static final String CarIconFileName = "car.png";
private static final String CarIconResource = "org/noroomattheinn/TeslaResources/02_loc_arrow@2x.png";
private final String[] pathColors = {
"ff0000ff", // Red
"ff00ff00", // Green
"ffff0000", // Blue
"ffffff00", // Cyan
"ffff00ff", // Magenta
"ff0000ff" // Yellow
};
private int pathColorIndex = 0;
private int indent = 0;
private PrintWriter pw;
private void emitIndent() {
for (int i = 0; i < indent; i++) {
pw.print(" ");
}
}
private void println(String s) { emitIndent(); pw.println(s); }
private void emitOpen(String s) { emitIndent(); pw.println(s); indent++; }
private void emitClose(String s) { indent--; emitIndent(); pw.println(s); }
private void format(String s, Object... args) {
emitIndent();
pw.format(s, args);
}
boolean export(List<Trip> trips, File toFile) {
File tempDir;
File kmlFile;
try {
tempDir = Files.createTempDirectory("VTKML").toFile();
kmlFile = File.createTempFile("VTKML", ".kml", tempDir);
pw = new PrintWriter(kmlFile);
InputStream is =
getClass().getClassLoader().getResourceAsStream(CarIconResource);
File carIconFile = new File(tempDir, CarIconFileName);
FileUtils.copyInputStreamToFile(is, carIconFile);
emitKML(trips);
pw.flush(); pw.close();
return zipEm(toFile, carIconFile, kmlFile);
} catch (IOException ex) {
logger.warning("Unable to create KML file or directory");
return false;
}
}
private void emitKML(List<Trip> trips) {
println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
println("<kml xmlns=\"http://www.opengis.net/kml/2.2\">");
emitOpen("<Document>");
for (Trip t : trips) {
emitPath(t);
emitFolderOfMarkers(t);
}
emitClose("</Document>");
println("</kml>");
}
private void emitCarMarker(WayPoint wp) {
emitOpen("<Placemark>");
emitExtendedData(wp);
emitPoint(wp);
emitIcon(wp);
emitClose("</Placemark>");
}
private void emitExtendedData(WayPoint wp) {
emitOpen("<ExtendedData>");
format("<Data name=\"Time\"><value>%1$tH:%1$tM:%1$tS</value></Data>\n", new Date(wp.getTime()));
format("<Data name=\"Power\"><value>%.1f</value></Data>\n", wp.getPower());
format("<Data name=\"SOC\"><value>%.1f</value></Data>\n", wp.getSOC());
emitClose("</ExtendedData>");
}
private void emitFolderOfMarkers(Trip t) {
emitOpen("<Folder>");
println("<open>0</open>");
format( "<name>"+
"Tesla Positions on %1$tY-%1$tm-%1$td @ "+
"%1$tH:%1$tM</name>\n", new Date(t.firstWayPoint().getTime()));
for (WayPoint wp : t.getWayPoints()) {
emitCarMarker(wp);
}
emitClose("</Folder>");
}
private void emitPath(Trip t) {
emitOpen("<Placemark>");
format(
"<name>Tesla Path on %1$tY-%1$tm-%1$td @ %1$tH:%1$tM</name>\n",
new Date(t.firstWayPoint().getTime()));
emitOpen("<Style>");
emitOpen("<LineStyle>");
format("<color>%s</color>\n", pathColors[pathColorIndex++ % pathColors.length]);
println("<width>3</width>");
emitClose("</LineStyle>");
emitClose("</Style>");
emitOpen("<LineString>");
println("<tessellate>1</tessellate>");
emitOpen("<coordinates>");
for (WayPoint wp : t.getWayPoints()) {
format("%f,%f,0\n", wp.getLng(), wp.getLat());
}
emitClose("</coordinates>");
emitClose("</LineString>");
emitClose("</Placemark>");
}
private void emitPoint(WayPoint wp) {
emitOpen("<Point>");
format("<coordinates>%f,%f,0</coordinates>\n", wp.getLng(), wp.getLat());
emitClose("</Point>");
}
private void emitIcon(WayPoint wp) {
emitOpen("<Style>");
emitOpen("<IconStyle>");
println("<scale>0.7</scale>");
format("<heading>%f</heading>\n", wp.getHeading());
format("<Icon><href>%s</href></Icon>\n", CarIconFileName);
emitClose("</IconStyle>");
emitClose("</Style>");
}
private boolean zipEm(File toFile, File... files) {
FileInputStream fis = null;
try {
byte[] buffer = new byte[1024];
FileOutputStream fos = new FileOutputStream(toFile);
ZipOutputStream zos = new ZipOutputStream(fos);
for (File file : files) {
fis = new FileInputStream(file);
zos.putNextEntry(new ZipEntry(file.getName()));
int length;
while ((length = fis.read(buffer)) > 0) {
zos.write(buffer, 0, length);
}
zos.closeEntry();
fis.close();
fis = null;
}
zos.close();
} catch (IOException ioe) {
logger.warning("Error creating zip file: " + ioe);
return false;
} finally {
if (fis != null) try {
fis.close();
} catch (IOException ex) {
logger.warning("Failed closing FileInputStream: " + ex);
}
}
return true;
}
}