/*
GNU General Public License
CacheWolf is a software for PocketPC, Win and Linux that
enables paperless caching.
It supports the sites geocaching.com and opencaching.de
Copyright (C) 2006 CacheWolf development team
See http://www.cachewolf.de/ for more information.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package CacheWolf.exp;
import CacheWolf.MainForm;
import CacheWolf.Preferences;
import CacheWolf.controls.InputPanel;
import CacheWolf.database.CacheHolder;
import CacheWolf.database.CacheHolderDetail;
import CacheWolf.database.CacheType;
import CacheWolf.navi.TransformCoordinates;
import CacheWolf.utils.MyLocale;
import CacheWolf.utils.STRreplace;
import CacheWolf.utils.SafeXML;
import ewe.io.BufferedWriter;
import ewe.io.FileBase;
import ewe.io.FileOutputStream;
import ewe.io.FileWriter;
import ewe.io.IOException;
import ewe.io.InputStream;
import ewe.io.PrintWriter;
import ewe.sys.Handle;
import ewe.ui.FormBase;
import ewe.ui.ProgressBarForm;
import ewe.util.Hashtable;
import ewe.util.Iterator;
import ewe.util.Map.MapEntry;
import ewe.util.Vector;
import ewe.util.zip.ZipEntry;
import ewe.util.zip.ZipException;
import ewe.util.zip.ZipFile;
/**
* Class to export the cache database (index) to an KML-File
* which can be read by Google Earth
*
*/
public class KMLExporter extends Exporter {
private static final String COLOR_FOUND = "ff98fb98";
private static final String COLOR_OWNED = "ffffaa55";
private static final String COLOR_AVAILABLE = "ffffffff";
private static final String COLOR_NOT_AVAILABLE = "ff0000ff";
static final int AVAILABLE = 0;
static final int FOUND = 1;
static final int OWNED = 2;
static final int NOT_AVAILABLE = 3;
static final int UNKNOWN = 4;
String[] categoryNames = { "Available", "Found", "Owned", "Not Available", "UNKNOWN" };
Hashtable[] outDB = new Hashtable[categoryNames.length];
String scale = "";
public KMLExporter() {
super();
this.setOutputFileExtension("*.kml");
}
public void doIt() {
scale = Preferences.itself().getExportPref(exporterName + "-scale");
if (scale.length() == 0) {
scale = "0.7";
}
InputPanel inputScale = new InputPanel(MyLocale.getMsg(2301, "Input scale"), MyLocale.getMsg(2302, "Scale") + ": ", scale);
if (inputScale.execute() == FormBase.IDOK) {
scale = inputScale.input();
}
Preferences.itself().setExportPref(exporterName + "-scale", scale);
String str;
CacheHolder ch;
CacheHolder addiWpt;
ProgressBarForm pbf = new ProgressBarForm();
Handle h = new Handle();
if (outFile == null) {
askForOutputFile();
if (outFile == null)
return;
}
pbf.showMainTask = false;
pbf.setTask(h, "Exporting ...");
pbf.exec();
DB = MainForm.profile.cacheDB.getVectorDB();
int expCount = 0;
copyIcons(outFile.getParent());
buildOutDB();
try {
PrintWriter outp = new PrintWriter(new BufferedWriter(new FileWriter(outFile)));
str = STRreplace.replace(this.header(), "CacheWolf", MainForm.profile.name);
if (str != null)
outp.print(str);
for (int cat = 0; cat < categoryNames.length; cat++) {
// skip over empty categories
if (outDB[cat].size() == 0)
continue;
Iterator outLoop = outDB[cat].entries();
outp.print(startFolder(categoryNames[cat]));
Vector tmp;
MapEntry entry;
while (outLoop.hasNext()) {
entry = (MapEntry) outLoop.next();
tmp = (Vector) entry.getValue();
// skip over empty cachetypes
if (tmp.size() == 0)
continue;
outp.print(startFolder(CacheType.type2Gui(Integer.valueOf(entry.getKey().toString()).byteValue())));
for (int i = 0; i < tmp.size(); i++) {
ch = (CacheHolder) tmp.get(i);
if (ch.isAddiWpt())
continue;
expCount++;
h.progress = (float) expCount / (float) anzVisibleCaches;
h.changed();
if (ch.getWpt().isValid()) {
str = record(ch, ch.getWpt().getLatDeg(TransformCoordinates.DD).replace('.', this.decimalSeparator), ch.getWpt().getLonDeg(TransformCoordinates.DD).replace('.', this.decimalSeparator));
if (str != null)
outp.print(str);
}
if (ch.hasAddiWpt()) {
boolean createdAdditionalWaypointsFolder = false;
for (int j = 0; j < ch.addiWpts.size(); j++) {
addiWpt = (CacheHolder) ch.addiWpts.get(j);
expCount++;
if (ch.getWpt().isValid() && addiWpt.isVisible()) {
if (!createdAdditionalWaypointsFolder) {
outp.print(startFolder("Additional Waypoints", false));
createdAdditionalWaypointsFolder = true;
}
str = record(addiWpt, addiWpt.getWpt().getLatDeg(TransformCoordinates.DD).replace('.', this.decimalSeparator), addiWpt.getWpt().getLonDeg(TransformCoordinates.DD).replace('.', this.decimalSeparator));
if (str != null)
outp.print(str);
}
}
if (createdAdditionalWaypointsFolder) {
outp.print(endFolder());// addi wpts
}
}
}
outp.print(endFolder());// cachetype
}
outp.print(endFolder());// category
}
str = trailer();
if (str != null)
outp.print(str);
outp.close();
pbf.exit(0);
} catch (IOException ioE) {
Preferences.itself().log("Error opening " + outFile.getName(), ioE);
}
// try
}
private void buildOutDB() {
CacheHolder ch;
Vector tmp;
// create the roots for the different categories
for (int i = 0; i < categoryNames.length; i++) {
outDB[i] = new Hashtable();
}
// fill structure with data from cacheDB
for (int i = 0; i < DB.size(); i++) {
ch = (CacheHolder) DB.get(i);
if (ch.isVisible() && !ch.isAddiWpt()) {
if (ch.isFound()) {
tmp = (Vector) outDB[FOUND].get(new Byte(ch.getType()));
if (tmp == null) {
tmp = new Vector();
outDB[FOUND].put(new Byte(ch.getType()), tmp);
}
} else if (ch.isOwned()) {
tmp = (Vector) outDB[OWNED].get(new Byte(ch.getType()));
if (tmp == null) {
tmp = new Vector();
outDB[OWNED].put(new Byte(ch.getType()), tmp);
}
} else if (ch.isArchived() || !ch.isAvailable()) {
tmp = (Vector) outDB[NOT_AVAILABLE].get(new Byte(ch.getType()));
if (tmp == null) {
tmp = new Vector();
outDB[NOT_AVAILABLE].put(new Byte(ch.getType()), tmp);
}
} else if (ch.isAvailable()) {
tmp = (Vector) outDB[AVAILABLE].get(new Byte(ch.getType()));
if (tmp == null) {
tmp = new Vector();
outDB[AVAILABLE].put(new Byte(ch.getType()), tmp);
}
} else {
tmp = (Vector) outDB[UNKNOWN].get(new Byte(ch.getType()));
if (tmp == null) {
tmp = new Vector();
outDB[UNKNOWN].put(new Byte(ch.getType()), tmp);
}
}
tmp.add(ch);
}
}
}
private String startFolder(String name) {
return startFolder(name, true);
}
private String startFolder(String name, boolean open) {
StringBuffer strBuf = new StringBuffer(200);
strBuf.append("<Folder>\r\n");
strBuf.append("<name>" + name + "</name>\r\n");
strBuf.append("<open>" + (open ? "1" : "0") + "</open>\r\n");
return strBuf.toString();
}
private String endFolder() {
return "</Folder>\r\n";
}
public void copyIcons(String dir) {
ZipFile zif = null;
try {
zif = new ZipFile(FileBase.getProgramDirectory() + FileBase.separator + "exporticons" + FileBase.separator + "GoogleEarth.zip");
} catch (IOException e) {
}
try {
if (zif == null) {
zif = new ZipFile(FileBase.getProgramDirectory() + FileBase.separator + "exporticons" + FileBase.separator + "exporticons" + FileBase.separator + "GoogleEarth.zip");
}
ZipEntry zipEnt;
int len;
String fileName;
for (int i = 0; i < CacheType.guiTypeStrings().length; i++) {
fileName = CacheType.typeImageForId(CacheType.guiSelect2Cw(i));
zipEnt = zif.getEntry(fileName);
if (zipEnt == null)
continue;
byte[] buff = new byte[zipEnt.getSize()];
InputStream fis = zif.getInputStream(zipEnt);
FileOutputStream fos = new FileOutputStream(dir + "/" + fileName);
while (0 < (len = fis.read(buff)))
fos.write(buff, 0, len);
fos.flush();
fos.close();
fis.close();
}
} catch (ZipException e) {
Preferences.itself().log("Problem copying Icon", e, true);
} catch (IOException e) {
Preferences.itself().log("Problem copying Icon", e, true);
}
}
StringBuffer strBuf = new StringBuffer(200);
public String header() {
strBuf.setLength(0);
strBuf.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n");
strBuf.append("<kml xmlns=\"http://earth.google.com/kml/2.0\">\r\n");
strBuf.append("<Folder>\r\n");
strBuf.append("<name>CacheWolf</name>\r\n");
strBuf.append("<open>1</open>\r\n");
return strBuf.toString();
}
public String record(CacheHolder ch, String lat, String lon) {
strBuf.setLength(0);
CacheHolderDetail det = ch.getDetails();
strBuf.append(" <Placemark>\r\n");
if (det.URL != null) {
strBuf.append(" <description>" + SafeXML.string2Html(det.URL) + "</description>\r\n");
}
strBuf.append(" <name>" + ch.getCode() + " - " + SafeXML.string2Html(ch.getName()) + "</name>\r\n");
strBuf.append(" <LookAt>\r\n");
strBuf.append(" <latitude>" + lat + "</latitude>\r\n");
strBuf.append(" <longitude>" + lon + "</longitude>\r\n");
strBuf.append(" <range>10000</range><tilt>0</tilt><heading>0</heading>\r\n");
strBuf.append(" </LookAt>\r\n");
strBuf.append(" <Point>\r\n");
strBuf.append(" <coordinates>" + lon + "," + lat + "</coordinates>\r\n");
strBuf.append(" </Point>\r\n");
strBuf.append(" <Style>\r\n");
strBuf.append(" <IconStyle>\r\n");
strBuf.append(" <Icon>\r\n");
// strBuf.append(" <href>"+ File.getProgramDirectory()+ "/" + CacheType.type2pic(Convert.parseInt(ch.type))+ "</href>\r\n");
strBuf.append(" <href>" + CacheType.typeImageForId(ch.getType()) + "</href>\r\n");
strBuf.append(" </Icon>\r\n");
strBuf.append(" </IconStyle>\r\n");
strBuf.append(" <LabelStyle>\r\n");
strBuf.append(" <color>" + getColor(ch) + "</color>\r\n");
strBuf.append(" <scale>" + scale + "</scale>\r\n");
strBuf.append(" </LabelStyle>\r\n");
strBuf.append(" </Style>\r\n");
strBuf.append(" </Placemark>\r\n");
return strBuf.toString();
}
/**
* Overrides: trailer() in Exporter
*/
public String trailer() {
strBuf.setLength(0);
strBuf.append("</Folder>\r\n");
strBuf.append("</kml>\r\n");
return strBuf.toString();
}
private String getColor(CacheHolder ch) {
if (ch.isFound())
return COLOR_FOUND;
if (ch.isOwned())
return COLOR_OWNED;
if (ch.isArchived() || !ch.isAvailable())
return COLOR_NOT_AVAILABLE;
return COLOR_AVAILABLE;
}
}