package com.gent.mp;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.TreeSet;
import au.com.bytecode.opencsv.CSVReader;
public class ScheduleFinder {
private int serviceIdPosition;
private int datePosition;
private int tripIdPosition;
private int tripServiceIdPosition;
private int stopTimeTripIdPosition;
private int arrivalTimeIdPosition;
private int stopIdPosition;
private int stopNamePosition;
private int stopLatPosition;
private int stopLngPosition;
private int departureTimeIdPosition;
private int sequencePosition;
private int stopTimesStopIdPosition;
private File gtfsFolder;
private static String CALENDAR_DATES = "calendar_dates.txt";
private static String TRIPS = "trips.txt";
private static String STOP_TIMES = "stop_times.txt";
private static String STOPS = "stops.txt";
private static String DATE = "date";
private static String SERVICE_ID = "service_id";
private static String TRIP_ID = "trip_id";
private static String STOP_NAME = "stop_name";
private static String STOP_LAT = "stop_lat";
private static String STOP_LNG = "stop_lon";
private static String ARRIVAL_TIME = "arrival_time";
private static String DEPARTURE_TIME = "departure_time";
private static String STOP_SEQUENCE = "stop_sequence";
private static String STOP_ID = "stop_id";
private static DateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd");
private static DateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:ss");
public ScheduleFinder(File gtfsFolder) {
this.gtfsFolder = gtfsFolder;
initialize();
}
private void initialize() {
processCalendarDateHeader();
processTripHeader();
processStopTimesHeader();
processStops();
}
private void processStops() {
String[] header = readHeader(STOPS);
for(int i = 0; i < header.length; i++) {
if(STOP_ID.equals(header[i])) {
stopIdPosition = i;
}
if(STOP_NAME.equals(header[i])) {
stopNamePosition = i;
}
if(STOP_LAT.equals(header[i])) {
stopLatPosition = i;
}
if(STOP_LNG.equals(header[i])) {
stopLngPosition = i;
}
}
}
private void processCalendarDateHeader() {
String[] header = readHeader(CALENDAR_DATES);
for (int i = 0; i < header.length; i++) {
if (DATE.equals(header[i])) {
datePosition = i;
}
if (SERVICE_ID.equals(header[i])) {
serviceIdPosition = i;
}
}
}
private void processTripHeader() {
String[] header = readHeader(TRIPS);
for (int i = 0; i < header.length; i++) {
if (TRIP_ID.equals(header[i])) {
tripIdPosition = i;
}
if (SERVICE_ID.equals(header[i])) {
tripServiceIdPosition = i;
}
}
}
private void processStopTimesHeader() {
String[] header = readHeader(STOP_TIMES);
for (int i = 0; i < header.length; i++) {
if(STOP_ID.equals(header[i])) {
stopTimesStopIdPosition = i;
}
if(TRIP_ID.equals(header[i])) {
stopTimeTripIdPosition = i;
}
if(ARRIVAL_TIME.equals(header[i])) {
arrivalTimeIdPosition = i;
}
if(DEPARTURE_TIME.equals(header[i])) {
departureTimeIdPosition = i;
}
if(STOP_SEQUENCE.equals(header[i])) {
sequencePosition = i;
}
}
}
private List<Trip> getTrips(CalendarDate calendarDate) {
CSVReader reader = null;
try {
InputStream input = new FileInputStream(new File(gtfsFolder,
TRIPS));
reader = new CSVReader(new InputStreamReader(input));
String[] line = reader.readNext();
TreeSet<String> s = new TreeSet<String>();
for (int k : calendarDate.getServiceIdToDate().keySet()) {
s.add("" + k);
}
List<Trip> trips = new ArrayList<Trip>();
while ((line = reader.readNext()) != null) {
String serviceId = line[tripServiceIdPosition];
if (s.contains(serviceId)) {
String tripId = line[tripIdPosition];
Trip trip = new Trip(Integer
.parseInt(serviceId),Integer.parseInt(tripId));
trips.add(trip);
}
}
return trips;
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
reader.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
private CalendarDate getCalendarDate(Date... dates) {
TreeSet<String> s = new TreeSet<String>();
for (Date date : dates) {
s.add(DATE_FORMAT.format(date));
}
CSVReader reader = null;
try {
InputStream input = new FileInputStream(new File(gtfsFolder,
CALENDAR_DATES));
reader = new CSVReader(new InputStreamReader(input));
CalendarDate calendarDate = null;
String[] line = reader.readNext();
while ((line = reader.readNext()) != null) {
String date = line[datePosition];
if (s.contains(date)) {
Integer serviceId = Integer
.parseInt(line[serviceIdPosition]);
if (calendarDate == null) {
Date calDate = DATE_FORMAT.parse(line[datePosition]);
calendarDate = new CalendarDate(serviceId, calDate);
} else {
Date calDate = DATE_FORMAT.parse(line[datePosition]);
calendarDate.getServiceIdToDate().put(serviceId,
calDate);
}
}
}
return calendarDate;
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
reader.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
private String[] readHeader(String file) {
CSVReader reader = null;
try {
InputStream input = new FileInputStream(new File(gtfsFolder, file));
reader = new CSVReader(new InputStreamReader(input));
return reader.readNext();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
reader.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
public StopTimesResult getStops(String departingStationId, String arrivingStationId,
Date... dates) {
CalendarDate calendarDate = getCalendarDate(dates);
List<Trip> trips = getTrips(calendarDate);
List<Stop> stops = getStops(departingStationId, arrivingStationId, trips);
return new StopTimesResult(trips,stops,calendarDate);
}
public List<Station> getStations() {
CSVReader reader = null;
try {
InputStream input = new FileInputStream(new File(gtfsFolder,
STOPS));
reader = new CSVReader(new InputStreamReader(input));
String[] line = reader.readNext();
List<Station> stations = new ArrayList<Station>();
while((line = reader.readNext())!=null) {
String name = line[stopNamePosition];
StringBuilder sb = new StringBuilder(name);
char lastChar=' ';
for(int i = 0; i < sb.length();i++) {
char nowChar = sb.charAt(i);
if(lastChar==' ' || lastChar=='/') {
sb.setCharAt(i, Character.toUpperCase(nowChar));
} else {
sb.setCharAt(i, Character.toLowerCase(nowChar));
}
lastChar = nowChar;
}
String id = line[stopIdPosition];
String lat = line[stopLatPosition];
String lng = line[stopLngPosition];
float latF=Float.NaN;
float lngF=Float.NaN;
if(lat.length()>0) {
latF = Float.parseFloat(lat);
lngF = Float.parseFloat(lng);
}
Station station = new Station(name,id,latF,lngF);
stations.add(station);
}
return stations;
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
reader.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
private List<Stop> getStops(final String departingStationId, String arrivingStationId,
List<Trip> trips) {
CSVReader reader = null;
try {
InputStream input = new FileInputStream(new File(gtfsFolder,
STOP_TIMES));
reader = new CSVReader(new InputStreamReader(input));
String[] line = reader.readNext();
TreeSet<String> tripIds = new TreeSet<String>();
for(Trip t : trips) {
tripIds.add(""+t.getTripId());
}
List<Stop> stops = new ArrayList<Stop>();
while ((line = reader.readNext()) != null) {
String tripId = line[stopTimeTripIdPosition];
if(tripIds.contains(tripId)) {
String stopId = line[stopTimesStopIdPosition];
if(stopId.equals(departingStationId) || stopId.equals(arrivingStationId)) {
Stop stop = new Stop();
stop.setStopId(stopId);
stop.setTripId(tripId);
stop.setDeparture(TIME_FORMAT.parse(line[departureTimeIdPosition]));
stop.setArrival(TIME_FORMAT.parse(line[arrivalTimeIdPosition]));
stop.setSequence(Integer.parseInt(line[sequencePosition]));
stops.add(stop);
}
}
}
Collections.sort(stops, new Comparator<Stop>() {
@Override
public int compare(Stop o1, Stop o2) {
int c = o1.getTripId().compareTo(o2.getTripId());
if(c==0) {
if(o1.getStopId().equals(departingStationId)) {
return -1;
}
return 1;
}
return c;
}
});
List<Stop> properStops = new ArrayList<Stop>();
for (int i = 0; i < stops.size(); i++) {
if (i + 1 >= stops.size()) {
break;
}
Stop a = stops.get(i);
Stop b = stops.get(i + 1);
if (a.getTripId().equals(b.getTripId())) {
if (a.getSequence() < b.getSequence()) {
Stop stop = new Stop();
stop.setDeparture(a.getDeparture());
stop.setArrival(b.getArrival());
properStops.add(stop);
}
}
}
return properStops;
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
reader.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}