com.kurtraschke.ctatt.gtfsrealtime.services.TripMatchingService.java Source code

Java tutorial

Introduction

Here is the source code for com.kurtraschke.ctatt.gtfsrealtime.services.TripMatchingService.java

Source

/*
 * Copyright (C) 2013 Kurt Raschke
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.kurtraschke.ctatt.gtfsrealtime.services;

import javax.inject.Inject;
import javax.inject.Singleton;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.common.collect.Iterables;
import com.kurtraschke.ctatt.gtfsrealtime.TripMatchingException;
import com.kurtraschke.ctatt.gtfsrealtime.api.Eta;

import org.onebusaway.collections.MappingLibrary;
import org.onebusaway.collections.Min;
import org.onebusaway.gtfs.model.AgencyAndId;
import org.onebusaway.gtfs.model.StopTime;
import org.onebusaway.gtfs.model.Trip;
import org.onebusaway.gtfs.model.calendar.CalendarServiceData;
import org.onebusaway.gtfs.model.calendar.ServiceDate;
import org.onebusaway.gtfs.services.GtfsRelationalDao;

/**
 * To identify trips, we get a "run number", which maps to multiple
 * GTFS trips.
 *
 * We then narrow down the GTFS trips by:
 * - route ID
 * - direction of travel (as determined by terminal station)
 * - active service IDs
 *
 * @author kurt
 */
@Singleton
public class TripMatchingService {

    @Inject
    GtfsDaoService daoService;

    public Trip matchTrip(String runNumber, String routeName, String destinationStationId,
            String destinationStationName, List<Eta> etas) throws TripMatchingException {
        GtfsRelationalDao dao = daoService.getGtfsRelationalDao();

        Collection<Trip> candidateTrips = daoService.getScheduledTripMapping().get("R" + runNumber);

        List<Trip> rightRouteTrips = new ArrayList<>();

        for (Trip candidateTrip : candidateTrips) {
            if (candidateTrip.getRoute().getId().getId().equalsIgnoreCase(routeName)) {
                rightRouteTrips.add(candidateTrip);
            }
        }

        if (rightRouteTrips.isEmpty()) {
            throw new TripMatchingException("No trips on route found.");
        }

        List<Trip> rightDirectionTrips = new ArrayList<>();

        for (Trip t : rightRouteTrips) {
            List<StopTime> stopTimes = dao.getStopTimesForTrip(t);

            if (Iterables.getLast(stopTimes).getStop().getName().equals(destinationStationName)
                    || Iterables.getLast(stopTimes).getStop().getId().getId().equals(destinationStationId)) {
                rightDirectionTrips.add(t);
            }
        }

        if (rightDirectionTrips.isEmpty()) {
            throw new TripMatchingException("No trips to destination found.");
        }

        Calendar c = new GregorianCalendar(daoService.getAgencyTimeZone());

        ServiceDate today = new ServiceDate(c);
        CalendarServiceData csd = daoService.getCalendarServiceData();

        Set<AgencyAndId> serviceIds = csd.getServiceIdsForDate(today);

        List<Trip> activeTrips = new ArrayList<>();

        for (Trip t : rightDirectionTrips) {
            if (serviceIds.contains(t.getServiceId())) {
                activeTrips.add(t);
            }
        }

        if (activeTrips.isEmpty()) {
            throw new TripMatchingException("No active trips found.");
        }

        Min<Trip> bestMatch = new Min<>();

        for (Trip t : activeTrips) {
            try {
                bestMatch.add(delta(today, dao.getStopTimesForTrip(t), etas), t);
            } catch (TripMatchingException ex) {
            }
        }

        return bestMatch.getMinElement();
    }

    private double delta(ServiceDate base, List<StopTime> scheduled, List<Eta> actual)
            throws TripMatchingException {
        double deltaSum = 0;

        long baseTime = base.getAsDate(daoService.getAgencyTimeZone()).getTime() / 1000L;

        Map<String, List<StopTime>> stopTimeMap = MappingLibrary.mapToValueList(scheduled, "stop.id.id");

        int comparedStops = 0;

        for (Eta e : actual) {
            List<StopTime> possibleStopTimes = stopTimeMap.get(e.stopId);

            if (possibleStopTimes == null || possibleStopTimes.isEmpty()) {
                continue;
            }

            Min<StopTime> minStopTime = new Min<>();

            for (StopTime scheduledStopTime : possibleStopTimes) {
                long arrivalTime = e.arrivalTime.getTime() / 1000L;

                minStopTime.add(Math.abs((scheduledStopTime.getArrivalTime() + baseTime) - arrivalTime),
                        scheduledStopTime);
            }
            deltaSum += minStopTime.getMinValue();
            comparedStops++;
        }

        if (comparedStops == 0) {
            throw new TripMatchingException("No compared stops.");
        }

        return deltaSum / comparedStops;
    }
}