package de.fub.agg2graph.gpseval.data;
import de.fub.agg2graph.gpseval.data.file.TrackFile;
import de.fub.agg2graph.gpseval.data.file.TrackFileFactory;
import de.fub.agg2graph.gpseval.data.filter.TrackFilter;
import de.fub.agg2graph.gpseval.data.filter.WaypointFilter;
import de.fub.agg2graph.gpseval.features.Feature;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* A DataLoader is used to load GPS-data stored in files.
*
* <p>For each GPS-data-file a TrackFile-instance is created using
* TrackFileFactory. This allows one to read GPS-data from files of different
* formats (e.g. csv, gpx, ...) based on file-extension. To support a new
* extension you can register your own TrackFile-class on the
* TrackFileFactory.</p>
*
* <p>When loading GPS-data-files, TrackFilters and WaypointFilters are applied,
* which you need to add (before loading data) using the methods addTrackFilters
* and addWaypointFilters.</p>
*
* <p>Moreover you need to specify the feature set to use by using the methods
* {@link de.fub.agg2graph.gpseval.data.DataLoader#addFeature(Feature feature) addFeature}
* and {@link de.fub.agg2graph.gpseval.data.DataLoader#addFeatures(List) addFeatures}
* before loading data.</p>
*/
public class DataLoader {
private TrackFileFactory mGPSDataFileFactory = TrackFileFactory.getFactory();
private List<Feature> mFeatures = new ArrayList<>();
private List<TrackFilter> mTrackFilters = new ArrayList<>();
private List<WaypointFilter> mWaypointFilters = new ArrayList<>();
/**
* Load all GPS-data-files for each folder of a class.
*
* @param classesFolderMapping The mapping from class-names to folders,
* which contain the GPS-data-files of the respective class.
* @return
* @throws FileNotFoundException
* @throws IOException
*/
public Map<String, List<AggregatedData>> loadData(Map<String, List<String>> classesFolderMapping) throws FileNotFoundException, IOException {
Map<String, List<AggregatedData>> gpsData = new HashMap<>();
for (String className : classesFolderMapping.keySet()) {
List<String> dataFolders = classesFolderMapping.get(className);
List<AggregatedData> classGpsData = loadDataFolders(className, dataFolders);
gpsData.put(className, classGpsData);
}
return gpsData;
}
/**
* Load all GPS-data-files of a folder which contains data for the specified
* class.
*
* @param className The name of the class to which the data inside the
* dataFolders belong to.
* @param dataFolders
* @return
* @throws FileNotFoundException
* @throws IOException
*/
public List<AggregatedData> loadDataFolders(String className, List<String> dataFolders) throws FileNotFoundException, IOException {
List<AggregatedData> gpsData = new ArrayList<>();
for (String dataFolder : dataFolders) {
List<AggregatedData> folderGpsData = loadDataFolder(className, dataFolder);
gpsData.addAll(folderGpsData);
}
return gpsData;
}
/**
* Load all GPS-data-files of a single folder which contains data for the
* specified class.
*
* @param className The name of the class to which the data inside the
* dataFolders belong to.
* @param dataFolder
* @return
* @throws FileNotFoundException
* @throws IOException
*/
public List<AggregatedData> loadDataFolder(String className, String dataFolder) throws FileNotFoundException, IOException {
List<AggregatedData> gpsData = new ArrayList<>();
Path dataPath = Paths.get(dataFolder);
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dataPath)) {
for (Path entry : stream) {
if (!Files.isDirectory(entry)) {
TrackFile gpsFile = mGPSDataFileFactory.newGPSDataFile(entry);
boolean passedAllFilter = true;
for (TrackFilter filter : mTrackFilters) {
if (!filter.filter(gpsFile, className)) {
passedAllFilter = false;
break;
}
}
if (passedAllFilter) {
AggregatedData data = loadDataFile(gpsFile);
if (data != null) {
gpsData.add(data);
}
}
}
}
}
return gpsData;
}
/**
* Load a single GPS-data-file and return the aggregated data.
* <p>Note: {@link de.fub.agg2graph.gpseval.data.filter.WaypointFilter WaypointFilter}s will be applied.</p>
*
* @param gpsFile The GPS-data-file to load.
* @return The aggregated data or null if file could not be loaded.
*/
public AggregatedData loadDataFile(TrackFile gpsFile) {
if (gpsFile == null) {
Logger.getLogger(DataLoader.class.getName()).log(Level.WARNING, "No suitable GPSDataFile-class found!");
return null;
}
// reset filters and add to file
decorateWithWaypointFilters(gpsFile);
for (Feature feature : mFeatures) {
feature.reset();
}
for (Waypoint gpsData : gpsFile) {
for (Feature feature : mFeatures) {
feature.addWaypoint(gpsData);
}
}
AggregatedData data = new AggregatedData();
for (Feature feature : mFeatures) {
data.addData(feature);
}
return data;
}
/**
* Add a feature to the feature set.
*
* @param feature
*/
public void addFeature(Feature feature) {
mFeatures.add(feature);
}
/**
* Add the given features to the feature set.
*
* @param features
*/
public void addFeatures(List<Feature> features) {
mFeatures.addAll(features);
}
/**
* Add a track filter to the list of track filters.
*
* @param trackFilters
*/
public void addTrackFilters(List<TrackFilter> trackFilters) {
mTrackFilters.addAll(trackFilters);
}
/**
* Add a waypoint filter to the list of waypoint filters.
*
* @param waypointFilters
*/
public void addWaypointFilters(List<WaypointFilter> waypointFilters) {
mWaypointFilters.addAll(waypointFilters);
}
/**
* Decorate the given GPS-data-file with each waypoint filter.
*
* @param gpsFile
*/
private void decorateWithWaypointFilters(TrackFile gpsFile) {
for (WaypointFilter waypointFilter : mWaypointFilters) {
waypointFilter.reset();
gpsFile.addWaypointFilter(waypointFilter);
}
}
}