/*
* Copyright 2011, Nabil Benothman, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package com.ubike.processor;
import com.ubike.util.StatisticManager;
import com.ubike.model.RawGpsFile;
import com.ubike.model.TrackPoint;
import com.ubike.model.Trip;
import com.ubike.util.UbikeEntity;
import com.ubike.model.UbikeUser;
import com.ubike.model.UserProfile;
import com.ubike.services.GPSFileServiceLocal;
import com.ubike.services.StatisticServiceLocal;
import com.ubike.services.TripManagerLocal;
import com.ubike.services.TripServiceLocal;
import com.ubike.services.UserServiceLocal;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author Benothman
*/
public class RawFileProcessor implements GpsFileProcessor {
private static final Logger logger = Logger.getLogger(RawFileProcessor.class.getName());
public static final String GPGGA = "$GPGGA";
public static final String GPRMC = "$GPRMC";
public static final String GPGLL = "$GPGLL";
private double totalDisatance = 0.0;
long minTimestamp = Long.MAX_VALUE;
long maxTimestamp = Long.MIN_VALUE;
private TripManagerLocal tml;
private UbikeUser user;
private Calendar cal = Calendar.getInstance();
private StatisticManager statManager;
private UserServiceLocal userService;
private TripServiceLocal tripService;
private GPSFileServiceLocal gpsFileService;
private StatisticServiceLocal statisticService;
/**
*
* @param tripManager
* @param user
*/
private RawFileProcessor(TripManagerLocal tripManager, UbikeUser user) {
super();
this.tml = tripManager;
this.user = user;
this.statManager = new StatisticManager(getTml());
}
/**
*
* @param user
*/
private RawFileProcessor(UbikeUser user) {
super();
this.user = user;
}
/**
* @return a new instance of <code>RawFileProcessor</code>
*/
public static RawFileProcessor create(TripManagerLocal tml, UbikeUser user) {
return new RawFileProcessor(tml, user);
}
/**
* Create a new instance of {@code RawFileProcessor}
*
* @param user the current user
* @return a new instance of {@code RawFileProcessor}
*/
public static RawFileProcessor create(UbikeUser user) {
return new RawFileProcessor(user);
}
/* (non-Javadoc)
* @see com.ubike.processor.GpsFileProcessor#process(java.io.File)
*/
@Override
public void process(File inputFile) throws Exception {
LinkedList<TrackPoint> tracks = new LinkedList<TrackPoint>();
BufferedReader br = new BufferedReader(new FileReader(inputFile));
String line = null, tokens[];
double latitude, longitude, altitude, tmpValue;
long tmp = 0;
int x;
while ((line = br.readLine()) != null) {
tokens = line.split(",");
if (tokens.length == 0) {
continue;
}
TrackPoint trackPoint = null;
if (tokens[0].equals(GPGGA)) {
// $GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
// 4807.038,N Latitude 48 deg 07.038' N
// 01131.000,E Longitude 11 deg 31.000' E
int fixQuality = Integer.parseInt(tokens[6]);
if (fixQuality == 0) {
// The GPS line entry is not valid
continue;
}
// dRetVal = Int(sNMEA / 100) + (sNMEA - Int(sNMEA / 100) * 100) / 60
tmpValue = Double.parseDouble(tokens[2]);
x = (int) (tmpValue / 100);
latitude = (tokens[3].equals("S") ? -1 : 1) * (x + (tmpValue - x * 100) / 60);
tmpValue = Double.parseDouble(tokens[4]);
x = (int) (tmpValue / 100);
longitude = (tokens[5].equals("W") ? -1 : 1) * (x + (tmpValue - x * 100) / 60);
int satNum = Integer.parseInt(tokens[7]);
altitude = Double.parseDouble(tokens[9]);
trackPoint = new TrackPoint(latitude, longitude, altitude, tmp);
trackPoint.setFixQuality(fixQuality);
trackPoint.setNumberOfSatellites(satNum);
} else if (tokens[0].equals(GPRMC)) {
// $GPRMC,142959.780,A,4647.3516,N,00631.2997,E,0.60,45.06,150707,,*3A
// 4807.038,N Latitude 48 deg 07.038' N
// 01131.000,E Longitude 11 deg 31.000' E
tmpValue = Double.parseDouble(tokens[3]);
x = (int) (tmpValue / 100);
latitude = (tokens[4].equals("S") ? -1 : 1) * (x + (tmpValue - x * 100) / 60);
tmpValue = Double.parseDouble(tokens[5]);
x = (int) (tmpValue / 100);
longitude = (tokens[6].equals("W") ? -1 : 1) * (x + (tmpValue - x * 100) / 60);
if (latitude == 0 && longitude == 0) {
// The GPS line entry is not valid
continue;
}
double speedKnot = tokens[7].equals("") ? 0.0 : Double.parseDouble(tokens[7]);
long timestamp = getFromString(tokens[9] + tokens[1]);
tmp = timestamp;
minTimestamp = timestamp < minTimestamp ? timestamp : minTimestamp;
maxTimestamp = timestamp > maxTimestamp ? timestamp : maxTimestamp;
trackPoint = new TrackPoint(latitude, longitude, 0.0, timestamp);
trackPoint.setSpeedKnot(speedKnot);
} else if (tokens[0].equals(GPGLL)) {
// $GPGLL,4642.3628,N,00630.1560,E,125256.518,A*33
// 4916.46,N Latitude 49 deg. 16.45 min. North
// 12311.12,W Longitude 123 deg. 11.12 min. West
tmpValue = Double.parseDouble(tokens[1]);
x = (int) (tmpValue / 100);
latitude = (tokens[2].equals("S") ? -1 : 1) * (x + (tmpValue - x * 100) / 60);
tmpValue = Double.parseDouble(tokens[3]);
x = (int) (tmpValue / 100);
longitude = (tokens[4].equals("W") ? -1 : 1) * (x + (tmpValue - x * 100) / 60);
if (latitude == 0 && longitude == 0) {
// The GPS line entry is not valid
continue;
}
trackPoint = new TrackPoint(latitude, longitude, 0, tmp);
} else {
continue;
}
totalDisatance += tracks.isEmpty() ? 0.0 : trackPoint.distanceTo(tracks.getLast());
tracks.addLast(trackPoint);
}
// adding Trip to the database
Trip trip = initializeTrip(tracks);
if (trip != null) {
logger.log(Level.INFO, "Add trip to datastore");
trip.setOwner(user);
this.tripService.create(trip);
// computing general statistics
this.setUserStats(user, trip);
RawGpsFile gpsFile = new RawGpsFile(inputFile.getName(), inputFile.length(),
new Date(System.currentTimeMillis()));
this.gpsFileService.create(gpsFile);
user.getTrips().add(trip);
this.userService.update(user);
/*
updateEntityStatistics(user, trip);
user.getMemberShips().size();
for (MemberShip m : user.getMemberShips()) {
updateEntityStatistics(m.getGroup(), trip);
}
*/
} else {
logger.log(Level.INFO, "The trip is null");
}
}
/**
* Computing the general statistics for the user with the new trip
*
* @param user
* @param trip
*/
private void setUserStats(UbikeUser user, Trip trip) {
UserProfile userProfile = user.getUserProfile();
/* Setting speed values (min, avg and max) */
double avg = userProfile.getAvgSpeed();
avg = (avg == 0 ? trip.getAvgSpeed() : (avg + trip.getAvgSpeed()) / 2);
userProfile.setAvgSpeed(getDoubleValue(avg));
double max = Math.max(userProfile.getMaxSpeed(), trip.getMaxSpeed());
userProfile.setMaxSpeed(getDoubleValue(max));
double min = userProfile.getMinSpeed();
min = (min == 0 ? trip.getAvgSpeed() : Math.min(min, trip.getAvgSpeed()));
userProfile.setMinSpeed(getDoubleValue(min));
/* Setting distance values (min, avg and max) */
userProfile.setTotalDistance(getDoubleValue(userProfile.getTotalDistance() + trip.getDistance()));
max = Math.max(userProfile.getMaxDistance(), trip.getDistance());
userProfile.setMaxDistance(getDoubleValue(max));
min = userProfile.getMinDistance();
min = (min == 0 ? trip.getDistance() : Math.min(min, trip.getDistance()));
userProfile.setMinDistance(getDoubleValue(min));
avg = userProfile.getAvgDistance();
avg = (avg == 0 ? trip.getDistance() : (avg + trip.getDistance()) / 2);
userProfile.setAvgDistance(getDoubleValue(avg));
/* Setting duration values (min, avg and max) */
// Setting total duration
userProfile.setTotalDuration(userProfile.getTotalDuration() + trip.getDuration());
int avgD = userProfile.getAvgDuration();
avgD = (avgD == 0 ? trip.getDuration() : (avgD + trip.getDuration()) / 2);
userProfile.setAvgDuration(avgD);
// Setting the maximal duration
userProfile.setMaxDuration(Math.max(userProfile.getMaxDuration(), trip.getDuration()));
// Setting the minimal duration
int minD = userProfile.getMinDuration();
minD = (minD == 0 ? trip.getDuration() : Math.min(minD, trip.getDuration()));
userProfile.setMinDuration(minD);
}
/**
* Initialize a trip from the given track points
* @param tracks a list of track points
* @return a new Trip instance
*/
public Trip initializeTrip(List<TrackPoint> tracks) {
// Create the trip composed by TrackPoints
if (!tracks.isEmpty() && totalDisatance > 0) {
PolylineEncoder encoder = new PolylineEncoder();
HashMap<String, String> my_hm = encoder.dpEncode(tracks);
//HashMap<String, String> my_hm = PolylineEncoder.createEncodings(tracks, 13);
totalDisatance = getDoubleValue(totalDisatance);
double avgSpeed = getDoubleValue(Double.parseDouble(my_hm.get("avgSpeed")));
double maxSpeed = getDoubleValue(Double.parseDouble(my_hm.get("maxSpeed")));
int delta = (int) ((maxTimestamp - minTimestamp) / 1000);
Trip trip = new Trip(new Date(minTimestamp), new Date(maxTimestamp), delta,
totalDisatance, avgSpeed, maxSpeed);
trip.setMapCode(my_hm.get("encodedPoints"));
trip.setMapLevels(my_hm.get("encodedLevels"));
trip.setAvgLat(Double.parseDouble(my_hm.get("avgLat")));
trip.setAvgLon(Double.parseDouble(my_hm.get("avgLon")));
trip.setStartLat(tracks.get(0).getLatitude());
trip.setStartLon(tracks.get(0).getLongitude());
trip.setEndLat(tracks.get(tracks.size() - 1).getLatitude());
trip.setEndLon(tracks.get(tracks.size() - 1).getLongitude());
return trip;
}
return null;
}
/**
*
* @param user
* @param trip
*/
public void updateUserRankings(UbikeUser user, Trip trip) {
UbikeUser tmp = this.userService.findWithMemberShips(user.getId());
// TODO
}
/**
* Update the statistics of the given entity with the given trip data
* @param entity
* @param trip
*/
private void updateEntityStatistics(UbikeEntity entity, Trip trip) {
statManager.updateEntityStatistics(entity, trip);
}
/**
*
* @param value
* @return a double value with less or equal than 3 fraction digits.
*/
private double getDoubleValue(double value) {
String tmpTab[] = ("" + value).split("\\.");
if (tmpTab[1].length() > 3) {
tmpTab[1] = tmpTab[1].substring(0, 3);
value = Double.parseDouble(tmpTab[0] + "." + tmpTab[1]);
}
return value;
}
/**
* Convert the given String to a date
*
* @param str
* @return
*/
private long getFromString(String dateTime) {
// Example : 280383123519 => Date - 28th of March 1983 at 12:35:19
int day = Integer.parseInt(dateTime.substring(0, 2));
int month = Integer.parseInt(dateTime.substring(2, 4)) - 1;
int year = Integer.parseInt("20" + dateTime.substring(4, 6));
int hour = Integer.parseInt(dateTime.substring(6, 8));
int minute = Integer.parseInt(dateTime.substring(8, 10));
int second = Integer.parseInt(dateTime.substring(10, 12));
cal.set(year, month, day, hour, minute, second);
return cal.getTimeInMillis();
}
/**
* @return the tml
*/
public TripManagerLocal getTml() {
return tml;
}
/**
* @param tml the tml to set
*/
public void setTml(TripManagerLocal tml) {
this.tml = tml;
}
/**
* @return the tripService
*/
public TripServiceLocal getTripService() {
return tripService;
}
/**
* @param tripService the tripService to set
*/
public void setTripService(TripServiceLocal tripService) {
this.tripService = tripService;
}
/**
* @return the gpsFileService
*/
public GPSFileServiceLocal getGpsFileService() {
return gpsFileService;
}
/**
* @param gpsFileService the gpsFileService to set
*/
public void setGpsFileService(GPSFileServiceLocal gpsFileService) {
this.gpsFileService = gpsFileService;
}
/**
* @return the statisticService
*/
public StatisticServiceLocal getStatisticService() {
return statisticService;
}
/**
* @param statisticService the statisticService to set
*/
public void setStatisticService(StatisticServiceLocal statisticService) {
this.statisticService = statisticService;
}
/**
* @return the userService
*/
public UserServiceLocal getUserService() {
return userService;
}
/**
* @param userService the userService to set
*/
public void setUserService(UserServiceLocal userService) {
this.userService = userService;
}
}