/*
* Copyright (C) 2012 The Serval Project
*
* This file is part of the Serval Maps Data Manipulator Software
*
* Serval Maps Data Manipulator Software 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; either
* version 3 of the License, or (at your option) any later version.
*
* This source code 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 source code; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.servalproject.maps.dataman.tasks;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import org.servalproject.maps.dataman.Utils;
import org.servalproject.maps.dataman.builders.BuildException;
import org.servalproject.maps.dataman.builders.KmlBuilder;
import org.servalproject.maps.dataman.types.GpsTraceElement;
import org.servalproject.maps.dataman.types.KmlStyle;
import org.servalproject.maps.protobuf.BinaryFileContract;
import org.servalproject.maps.protobuf.LocationMessage;
import org.servalproject.maps.protobuf.LocationMessage.Message.Builder;
/**
* methods to process location data and output KML data
*/
public class LocationsToKml {
/*
* public class level constants
*/
public static final int BINARY_FILE_TYPE = 1;
/*
* private class level variables
*/
private boolean verbose = false;
private File inputFile;
private File outputFile;
private int fileType;
private KmlStyle style;
/**
* convert the locations stored in a file into a KML file
*
* @param inputFile the input file containing the data data
* @param outputFile the output file to contain the KML data
* @param fileType the type of input file
* @param verbose indicates if verbose output is required
*/
public LocationsToKml(File inputFile, File outputFile, int fileType, boolean verbose, KmlStyle style) {
// check the parameters
if(inputFile == null) {
throw new IllegalArgumentException("the input file parameter is required");
}
if(outputFile == null) {
throw new IllegalArgumentException("the output file parameter is required");
}
try {
if(Utils.isFileAccessible(inputFile.getCanonicalPath()) == false) {
throw new IllegalArgumentException("the input file cannot be accessed");
}
} catch(IOException e) {
throw new IllegalArgumentException("the input file cannot be accessed", e);
}
try {
if(Utils.isFileAccessible(outputFile.getCanonicalPath()) == true) {
throw new IllegalArgumentException("the output file already exists");
}
}catch(IOException e) {
throw new IllegalArgumentException("the output file already exists", e);
}
this.verbose = verbose;
switch(fileType) {
case BINARY_FILE_TYPE:
if(inputFile.getName().endsWith(BinaryFileContract.LOCATION_EXT) == false) {
throw new IllegalArgumentException("a binary file is required to end with '" + BinaryFileContract.LOCATION_EXT + "'");
}
break;
default:
throw new IllegalArgumentException("the provided input type is invalid");
}
this.inputFile = inputFile;
this.outputFile = outputFile;
this.fileType = fileType;
this.style = style;
}
/**
* undertake the task
*/
public void undertakeTask(String taskType) throws TaskException {
// check on the parameters
if(Utils.isEmpty(taskType) == true) {
throw new IllegalArgumentException("the taskType parameter is required");
}
if(taskType.equals("binloctokml") == true) {
switch(fileType) {
case BINARY_FILE_TYPE:
processBinaryFileBasicOutput(inputFile, outputFile);
break;
default:
return;
}
} else if(taskType.equals("binloctokml2") == true) {
switch(fileType) {
case BINARY_FILE_TYPE:
processBinaryFileTimeOutput(inputFile, outputFile);
break;
default:
return;
}
} else {
throw new TaskException("unrecognised task type parameter");
}
}
// private method to retrieve the GPS trace from the binary file
private ArrayList<GpsTraceElement> retrieveTraceFromBinaryFile(File inputFile) throws TaskException {
// declare helper variables
FileInputStream inputStream = null;
ArrayList<GpsTraceElement> trace = new ArrayList<GpsTraceElement>();
// open the input stream
try {
inputStream = new FileInputStream(inputFile);
} catch(FileNotFoundException e) {
throw new TaskException("unable to open the input file", e);
}
// process the messages in the file
Builder messageBuilder = LocationMessage.Message.newBuilder();
try {
while(messageBuilder.mergeDelimitedFrom(inputStream) == true) {
// add the coordinates to the list
trace.add(new GpsTraceElement(
messageBuilder.getLatitude(),
messageBuilder.getLongitude(),
messageBuilder.getTimestamp(),
messageBuilder.getTimeZone()
));
}
// play nice and tidy up
inputStream.close();
} catch (IOException e) {
throw new TaskException("unable to read messages from the binary file", e);
}
return trace;
}
/*
* process a binary file
*/
private void processBinaryFileBasicOutput(File inputFile, File outputFile) throws TaskException {
if(verbose) {
System.out.println("processing a binary file");
}
ArrayList<GpsTraceElement> trace = retrieveTraceFromBinaryFile(inputFile);
// build the KML
try {
// start a new KML file
KmlBuilder builder = new KmlBuilder();
// add any style info
builder.setStyle(style);
// add the GPS trace
builder.addTrace(trace);
// output the KML to a file
PrintWriter printWriter = new PrintWriter(new FileOutputStream(outputFile));
builder.outputToFile(printWriter);
// close the output file
printWriter.close();
} catch (BuildException e) {
throw new TaskException("unable to build the KML file", e);
} catch (FileNotFoundException e) {
throw new TaskException("unable to build the KML file", e);
}
}
/*
* process a binary file
*/
private void processBinaryFileTimeOutput(File inputFile, File outputFile) throws TaskException {
if(verbose) {
System.out.println("processing a binary file");
}
ArrayList<GpsTraceElement> trace = retrieveTraceFromBinaryFile(inputFile);
// build the KML
try {
// start a new KML file
KmlBuilder builder = new KmlBuilder();
// add any style info
builder.setStyle(style);
// add the GPS trace
builder.addTraceWithTime(trace);
// output the KML to a file
PrintWriter printWriter = new PrintWriter(new FileOutputStream(outputFile));
builder.outputToFile(printWriter);
// close the output file
printWriter.close();
} catch (BuildException e) {
throw new TaskException("unable to build the KML file", e);
} catch (FileNotFoundException e) {
throw new TaskException("unable to build the KML file", e);
}
}
}