Package org.onebusaway.transit_data_federation.impl.beans.itineraries

Source Code of org.onebusaway.transit_data_federation.impl.beans.itineraries.ItinerariesBeanServiceImpl$TripToStop

/**
* Copyright (C) 2011 Brian Ferris <bdferris@onebusaway.org>
* Copyright (C) 2011 Google, Inc.
*
* 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 org.onebusaway.transit_data_federation.impl.beans.itineraries;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.ObjectUtils;
import org.onebusaway.collections.CollectionsLibrary;
import org.onebusaway.exceptions.NoSuchTripServiceException;
import org.onebusaway.exceptions.ServiceException;
import org.onebusaway.geospatial.model.CoordinatePoint;
import org.onebusaway.geospatial.model.EncodedPolylineBean;
import org.onebusaway.geospatial.services.PolylineEncoder;
import org.onebusaway.geospatial.services.SphericalGeometryLibrary;
import org.onebusaway.gtfs.model.AgencyAndId;
import org.onebusaway.transit_data.model.ListBean;
import org.onebusaway.transit_data.model.StopBean;
import org.onebusaway.transit_data.model.oba.LocalSearchResult;
import org.onebusaway.transit_data.model.oba.MinTravelTimeToStopsBean;
import org.onebusaway.transit_data.model.oba.TimedPlaceBean;
import org.onebusaway.transit_data.model.schedule.FrequencyBean;
import org.onebusaway.transit_data.model.tripplanning.ConstraintsBean;
import org.onebusaway.transit_data.model.tripplanning.EdgeNarrativeBean;
import org.onebusaway.transit_data.model.tripplanning.ItinerariesBean;
import org.onebusaway.transit_data.model.tripplanning.ItineraryBean;
import org.onebusaway.transit_data.model.tripplanning.LegBean;
import org.onebusaway.transit_data.model.tripplanning.LocationBean;
import org.onebusaway.transit_data.model.tripplanning.Modes;
import org.onebusaway.transit_data.model.tripplanning.StreetLegBean;
import org.onebusaway.transit_data.model.tripplanning.TransitLegBean;
import org.onebusaway.transit_data.model.tripplanning.TransitLocationBean;
import org.onebusaway.transit_data.model.tripplanning.TransitShedConstraintsBean;
import org.onebusaway.transit_data.model.tripplanning.VertexBean;
import org.onebusaway.transit_data.model.trips.TripBean;
import org.onebusaway.transit_data_federation.impl.beans.ApplicationBeanLibrary;
import org.onebusaway.transit_data_federation.impl.beans.FrequencyBeanLibrary;
import org.onebusaway.transit_data_federation.impl.otp.OBAState;
import org.onebusaway.transit_data_federation.impl.otp.OBATraverseOptions;
import org.onebusaway.transit_data_federation.impl.otp.graph.AbstractBlockVertex;
import org.onebusaway.transit_data_federation.impl.otp.graph.AbstractStopVertex;
import org.onebusaway.transit_data_federation.impl.otp.graph.ArrivalVertex;
import org.onebusaway.transit_data_federation.impl.otp.graph.BlockArrivalVertex;
import org.onebusaway.transit_data_federation.impl.otp.graph.BlockDepartureVertex;
import org.onebusaway.transit_data_federation.impl.otp.graph.DepartureVertex;
import org.onebusaway.transit_data_federation.impl.otp.graph.tp.TPBlockArrivalVertex;
import org.onebusaway.transit_data_federation.impl.otp.graph.tp.TPBlockDepartureVertex;
import org.onebusaway.transit_data_federation.impl.otp.graph.tp.TPTransferEdge;
import org.onebusaway.transit_data_federation.model.ShapePoints;
import org.onebusaway.transit_data_federation.model.narrative.StopTimeNarrative;
import org.onebusaway.transit_data_federation.services.AgencyAndIdLibrary;
import org.onebusaway.transit_data_federation.services.ArrivalAndDepartureQuery;
import org.onebusaway.transit_data_federation.services.ArrivalAndDepartureService;
import org.onebusaway.transit_data_federation.services.beans.ItinerariesBeanService;
import org.onebusaway.transit_data_federation.services.beans.StopBeanService;
import org.onebusaway.transit_data_federation.services.beans.TripBeanService;
import org.onebusaway.transit_data_federation.services.blocks.BlockCalendarService;
import org.onebusaway.transit_data_federation.services.blocks.BlockInstance;
import org.onebusaway.transit_data_federation.services.blocks.BlockTripInstance;
import org.onebusaway.transit_data_federation.services.blocks.BlockTripInstanceLibrary;
import org.onebusaway.transit_data_federation.services.narrative.NarrativeService;
import org.onebusaway.transit_data_federation.services.otp.OTPConfigurationService;
import org.onebusaway.transit_data_federation.services.otp.TransitShedPathService;
import org.onebusaway.transit_data_federation.services.realtime.ArrivalAndDepartureInstance;
import org.onebusaway.transit_data_federation.services.realtime.BlockLocation;
import org.onebusaway.transit_data_federation.services.shapes.ShapePointService;
import org.onebusaway.transit_data_federation.services.transit_graph.BlockEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.BlockStopTimeEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.BlockTripEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.FrequencyEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.StopEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.StopTimeEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.TransitGraphDao;
import org.onebusaway.transit_data_federation.services.transit_graph.TripEntry;
import org.onebusaway.transit_data_federation.services.tripplanner.ItinerariesService;
import org.opentripplanner.routing.core.Edge;
import org.opentripplanner.routing.core.EdgeNarrative;
import org.opentripplanner.routing.core.Graph;
import org.opentripplanner.routing.core.GraphVertex;
import org.opentripplanner.routing.core.HasEdges;
import org.opentripplanner.routing.core.State;
import org.opentripplanner.routing.core.TraverseMode;
import org.opentripplanner.routing.core.Vertex;
import org.opentripplanner.routing.edgetype.StreetEdge;
import org.opentripplanner.routing.edgetype.StreetTraversalPermission;
import org.opentripplanner.routing.edgetype.StreetVertex;
import org.opentripplanner.routing.services.GraphService;
import org.opentripplanner.routing.services.StreetVertexIndexService;
import org.opentripplanner.routing.spt.BasicShortestPathTree;
import org.opentripplanner.routing.spt.GraphPath;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.LineString;

@Component
public class ItinerariesBeanServiceImpl implements ItinerariesBeanService {

  private static final String MODE_WALK = "walk";

  private static final String MODE_BICYCLE = "bicycle";

  private static final String MODE_TRANSIT = "transit";

  private ItinerariesService _itinerariesService;

  private TransitShedPathService _transitShedPathService;

  private StreetVertexIndexService _streetVertexIndexService;

  private GraphService _graphService;

  private OTPConfigurationService _otpConfigurationService;

  private TripBeanService _tripBeanService;

  private NarrativeService _narrativeService;

  private StopBeanService _stopBeanService;

  private ShapePointService _shapePointService;

  private TransitGraphDao _transitGraphDao;

  private ArrivalAndDepartureService _arrivalAndDepartureService;

  private BlockCalendarService _blockCalendarService;

  private boolean _enabled = true;

  @Autowired
  public void setItinerariesService(ItinerariesService itinerariesService) {
    _itinerariesService = itinerariesService;
  }

  @Autowired
  public void setTransitShedPathService(
      TransitShedPathService transitShedPathService) {
    _transitShedPathService = transitShedPathService;
  }

  @Autowired
  public void setStreetVertexIndexService(
      StreetVertexIndexService streetVertexIndexService) {
    _streetVertexIndexService = streetVertexIndexService;
  }

  @Autowired
  public void setGraphService(GraphService graphService) {
    _graphService = graphService;
  }

  @Autowired
  public void setOtpConfigurationService(
      OTPConfigurationService otpConfigurationService) {
    _otpConfigurationService = otpConfigurationService;
  }

  @Autowired
  public void setTripBeanService(TripBeanService tripBeanService) {
    _tripBeanService = tripBeanService;
  }

  @Autowired
  public void setStopBeanService(StopBeanService stopBeanService) {
    _stopBeanService = stopBeanService;
  }

  @Autowired
  public void setNarrativeService(NarrativeService narrativeService) {
    _narrativeService = narrativeService;
  }

  @Autowired
  public void setShapePointService(ShapePointService shapePointService) {
    _shapePointService = shapePointService;
  }

  @Autowired
  public void setTransitGraphDao(TransitGraphDao transitGraphDao) {
    _transitGraphDao = transitGraphDao;
  }

  @Autowired
  public void setArrivalAndDepartureService(
      ArrivalAndDepartureService arrivalAndDepartureService) {
    _arrivalAndDepartureService = arrivalAndDepartureService;
  }

  @Autowired
  public void setBlockCalendarService(BlockCalendarService blockCalendarService) {
    _blockCalendarService = blockCalendarService;
  }

  public void setEnabled(boolean enabled) {
    _enabled = enabled;
  }

  /****
   * {@link ItinerariesBeanService} Interface
   ****/

  @Override
  public ItinerariesBean getItinerariesBetween(TransitLocationBean from,
      TransitLocationBean to, long targetTime, ConstraintsBean constraints)
      throws ServiceException {

    if (!_enabled)
      throw new ServiceException("service disabled");

    OBATraverseOptions options = createTraverseOptions();
    applyConstraintsToOptions(constraints, options);

    List<GraphPath> paths = _itinerariesService.getItinerariesBetween(from, to,
        targetTime, options);

    LocationBean fromBean = getPointAsLocation(from);
    LocationBean toBean = getPointAsLocation(to);

    ItinerariesBean itineraries = getPathsAsItineraries(paths, fromBean,
        toBean, options);

    ensureSelectedItineraryIsIncluded(from, to, targetTime, itineraries,
        constraints.getSelectedItinerary(), options);

    if (options.isArriveBy())
      Collections.sort(itineraries.getItineraries(), new SortByArrival());
    else
      Collections.sort(itineraries.getItineraries(), new SortByDeparture());

    return itineraries;
  }

  @Override
  public ListBean<VertexBean> getStreetGraphForRegion(double latFrom,
      double lonFrom, double latTo, double lonTo) {

    if (!_enabled)
      throw new ServiceException("service disabled");

    double x1 = Math.min(lonFrom, lonTo);
    double x2 = Math.max(lonFrom, lonTo);
    double y1 = Math.min(latFrom, latTo);
    double y2 = Math.max(latFrom, latTo);

    Envelope env = new Envelope(x1, x2, y1, y2);

    Collection<Vertex> vertices = _streetVertexIndexService.getVerticesForEnvelope(env);

    Map<Vertex, VertexBean> beansByVertex = new HashMap<Vertex, VertexBean>();

    for (Vertex vertex : vertices)
      getVertexAsBean(beansByVertex, vertex);

    for (Vertex vertex : vertices) {

      Collection<Edge> edges = null;

      if (vertex instanceof HasEdges) {
        HasEdges hasEdges = (HasEdges) vertex;
        edges = hasEdges.getOutgoing();
      } else {
        Graph graph = _graphService.getGraph();
        GraphVertex gv = graph.getGraphVertex(vertex.getLabel());
        if (gv != null)
          edges = gv.getOutgoing();
      }

      if (edges != null) {

        VertexBean from = getVertexAsBean(beansByVertex, vertex);
        List<EdgeNarrativeBean> edgeNarratives = new ArrayList<EdgeNarrativeBean>();

        for (Edge edge : edges) {
          if (edge instanceof EdgeNarrative) {
            EdgeNarrative narrative = (EdgeNarrative) edge;
            EdgeNarrativeBean narrativeBean = new EdgeNarrativeBean();
            narrativeBean.setName(narrative.getName());

            Geometry geom = narrative.getGeometry();
            if (geom != null) {
              List<CoordinatePoint> path = new ArrayList<CoordinatePoint>();
              appendGeometryToPath(geom, path, true);
              EncodedPolylineBean polyline = PolylineEncoder.createEncodings(path);
              narrativeBean.setPath(polyline.getPoints());
            }

            narrativeBean.setFrom(from);
            narrativeBean.setTo(getVertexAsBean(beansByVertex,
                narrative.getToVertex()));

            Map<String, Object> tags = new HashMap<String, Object>();
            if (edge instanceof StreetEdge) {
              StreetEdge streetEdge = (StreetEdge) edge;
              StreetTraversalPermission permission = streetEdge.getPermission();
              if (permission != null)
                tags.put("access", permission.toString().toLowerCase());
            }

            if (!tags.isEmpty())
              narrativeBean.setTags(tags);

            edgeNarratives.add(narrativeBean);
          }
        }

        if (!edgeNarratives.isEmpty())
          from.setOutgoing(edgeNarratives);
      }
    }

    List<VertexBean> beans = new ArrayList<VertexBean>(beansByVertex.values());
    return new ListBean<VertexBean>(beans, false);
  }

  @Override
  public MinTravelTimeToStopsBean getMinTravelTimeToStopsFrom(
      CoordinatePoint location, long time,
      TransitShedConstraintsBean constraints) {

    if (!_enabled)
      throw new ServiceException("service disabled");

    OBATraverseOptions options = createTraverseOptions();
    applyConstraintsToOptions(constraints.getConstraints(), options);

    Coordinate c = new Coordinate(location.getLon(), location.getLat());
    Vertex origin = _streetVertexIndexService.getClosestVertex(c, options);

    State originState = new OBAState(time, origin, options);
    BasicShortestPathTree tree = _transitShedPathService.getTransitShed(origin,
        originState, options);

    Map<StopEntry, Long> results = new HashMap<StopEntry, Long>();

    for (State state : tree.getAllStates()) {

      OBAState obaState = (OBAState) state;
      Vertex v = state.getVertex();

      if (v instanceof AbstractStopVertex) {
        AbstractStopVertex stopVertex = (AbstractStopVertex) v;
        StopEntry stop = stopVertex.getStop();
        long initialWaitTime = obaState.getInitialWaitTime();
        long duration = Math.abs(state.getTime() - time) - initialWaitTime;
        if (!results.containsKey(stop) || results.get(stop) > duration)
          results.put(stop, duration);
      } else if (v instanceof AbstractBlockVertex) {
        AbstractBlockVertex blockVertex = (AbstractBlockVertex) v;
        ArrivalAndDepartureInstance instance = blockVertex.getInstance();
        StopEntry stop = instance.getStop();
        long initialWaitTime = obaState.getInitialWaitTime();
        long duration = Math.abs(state.getTime() - time) - initialWaitTime;
        if (!results.containsKey(stop) || results.get(stop) > duration)
          results.put(stop, duration);
      }
    }

    return getStopTravelTimesAsResultsBean(results, options.speed);
  }

  @Override
  public List<TimedPlaceBean> getLocalPaths(ConstraintsBean constraints,
      MinTravelTimeToStopsBean travelTimes, List<LocalSearchResult> localResults)
      throws ServiceException {

    if (!_enabled)
      throw new ServiceException("service disabled");

    long maxTripLength = constraints.getMaxTripDuration() * 1000;

    List<TimedPlaceBean> beans = new ArrayList<TimedPlaceBean>();

    double walkingVelocity = travelTimes.getWalkingVelocity() / 1000;

    ConstraintsBean walkConstraints = new ConstraintsBean(constraints);
    walkConstraints.setModes(CollectionsLibrary.set(Modes.WALK));

    for (LocalSearchResult result : localResults) {

      double placeLat = result.getLat();
      double placeLon = result.getLon();

      List<TripToStop> closestStops = new ArrayList<TripToStop>();

      for (int index = 0; index < travelTimes.getSize(); index++) {

        String stopIdAsString = travelTimes.getStopId(index);
        AgencyAndId stopId = AgencyAndIdLibrary.convertFromString(stopIdAsString);

        long currentTripDuration = travelTimes.getTravelTime(index);
        double stopLat = travelTimes.getStopLat(index);
        double stopLon = travelTimes.getStopLon(index);
        double d = SphericalGeometryLibrary.distance(stopLat, stopLon,
            placeLat, placeLon);
        double t = currentTripDuration + d / walkingVelocity;
        if (d <= constraints.getMaxWalkingDistance() && t < maxTripLength) {
          closestStops.add(new TripToStop(stopId, currentTripDuration, t, index));
        }
      }

      if (closestStops.isEmpty())
        continue;

      Collections.sort(closestStops);

      double minTime = 0;
      TripToStop minStop = null;

      TransitLocationBean place = new TransitLocationBean();
      place.setLat(result.getLat());
      place.setLon(result.getLon());

      for (TripToStop o : closestStops) {

        long currentTripDuration = o.getTransitTimeToStop();
        double minTimeToPlace = o.getMinTansitTimeToPlace();

        // Short circuit if there is no way any of the remaining trips is going
        // to be better than our current winner
        if (minStop != null && minTimeToPlace > minTime)
          break;

        int remainingTime = (int) ((maxTripLength - currentTripDuration) / 1000);
        walkConstraints.setMaxTripDuration(remainingTime);

        int index = o.getIndex();
        TransitLocationBean stopLocation = new TransitLocationBean();
        stopLocation.setLat(travelTimes.getStopLat(index));
        stopLocation.setLon(travelTimes.getStopLon(index));

        ItinerariesBean itineraries = getItinerariesBetween(stopLocation,
            place, System.currentTimeMillis(), walkConstraints);

        for (ItineraryBean plan : itineraries.getItineraries()) {
          double t = currentTripDuration
              + (plan.getEndTime() - plan.getStartTime());
          if (minStop == null || t < minTime) {
            minTime = t;
            minStop = o;
          }
        }
      }

      if (minStop != null && minTime <= maxTripLength) {
        TimedPlaceBean bean = new TimedPlaceBean();
        bean.setPlaceId(result.getId());
        bean.setStopId(ApplicationBeanLibrary.getId(minStop.getStopId()));
        bean.setTime((int) (minTime / 1000));
        beans.add(bean);
      }
    }

    return beans;
  }

  /****
   * Private Methods
   ****/

  private OBATraverseOptions createTraverseOptions() {
    OBATraverseOptions options = _otpConfigurationService.createTraverseOptions();
    return options;
  }

  private void applyConstraintsToOptions(ConstraintsBean constraints,
      OBATraverseOptions options) {

    _otpConfigurationService.applyConstraintsToTraverseOptions(constraints,
        options);
  }

  private LocationBean getPointAsLocation(TransitLocationBean p) {
    LocationBean bean = new LocationBean();
    bean.setLocation(new CoordinatePoint(p.getLat(), p.getLon()));
    return bean;
  }

  private ItinerariesBean getPathsAsItineraries(List<GraphPath> paths,
      LocationBean from, LocationBean to, OBATraverseOptions options) {

    ItinerariesBean bean = new ItinerariesBean();
    bean.setFrom(from);
    bean.setTo(to);

    List<ItineraryBean> beans = new ArrayList<ItineraryBean>();
    bean.setItineraries(beans);

    boolean computationTimeLimitReached = false;

    if (!CollectionsLibrary.isEmpty(paths)) {
      for (GraphPath path : paths) {

        ItineraryBean itinerary = getPathAsItinerary(path, options);
        beans.add(itinerary);
      }
    }

    bean.setComputationTimeLimitReached(computationTimeLimitReached);

    return bean;
  }

  private ItineraryBean getPathAsItinerary(GraphPath path,
      OBATraverseOptions options) {

    ItineraryBean itinerary = new ItineraryBean();

    State startState = path.states.getFirst();
    State endState = path.states.getLast();

    itinerary.setStartTime(startState.getTime());
    itinerary.setEndTime(endState.getTime());

    List<LegBean> legs = new ArrayList<LegBean>();
    itinerary.setLegs(legs);

    /**
     * We set the current state index to 1, skipping the first state, since it
     * has no back edge
     */
    List<State> states = new ArrayList<State>(path.states);
    int currentIndex = 1;

    while (currentIndex < states.size()) {

      State state = states.get(currentIndex);
      EdgeNarrative edgeNarrative = state.getBackEdgeNarrative();

      TraverseMode mode = edgeNarrative.getMode();

      if (mode.isTransit()) {
        currentIndex = extendTransitLeg(states, currentIndex, options, legs);
      } else {
        currentIndex = extendStreetLeg(states, currentIndex, mode, legs);
      }
    }

    return itinerary;
  }

  private int extendTransitLeg(List<State> states, int currentIndex,
      OBATraverseOptions options, List<LegBean> legs) {

    TransitLegBuilder builder = new TransitLegBuilder();

    while (currentIndex < states.size()) {

      State state = states.get(currentIndex);
      Edge edge = state.getBackEdge();
      EdgeNarrative narrative = state.getBackEdgeNarrative();
      TraverseMode mode = narrative.getMode();

      if (!mode.isTransit())
        break;

      Vertex vFrom = narrative.getFromVertex();
      Vertex vTo = narrative.getToVertex();

      if (vFrom instanceof BlockDepartureVertex) {

        builder = extendTransitLegWithDepartureAndArrival(legs, builder,
            (BlockDepartureVertex) vFrom, (BlockArrivalVertex) vTo);

      } else if (vFrom instanceof TPBlockDepartureVertex) {

        builder = extendTransitLegWithTPDepartureAndArrival(legs, builder,
            (TPBlockDepartureVertex) vFrom, (TPBlockArrivalVertex) vTo);

      } else if (vFrom instanceof BlockArrivalVertex) {

        builder = extendTransitLegWithArrival(legs, builder,
            (BlockArrivalVertex) vFrom, vTo, state, options);

      } else if (vFrom instanceof ArrivalVertex) {

        if (vTo instanceof BlockDepartureVertex) {

          /**
           * This vertex combination occurs when we are doing an "arrive by"
           * trip and we need to do a transfer between two stops.
           */

          ArrivalVertex fromStopVertex = (ArrivalVertex) vFrom;
          StopEntry fromStop = fromStopVertex.getStop();

          BlockDepartureVertex toStopVertex = (BlockDepartureVertex) vTo;
          ArrivalAndDepartureInstance departureInstance = toStopVertex.getInstance();
          StopEntry toStop = departureInstance.getStop();

          addTransferLegIfNeeded(state, fromStop, toStop, options, legs);
        }
      } else if (edge instanceof TPTransferEdge) {

        TPTransferEdge transferEdge = (TPTransferEdge) edge;
        StopEntry fromStop = transferEdge.getFromStop();
        StopEntry toStop = transferEdge.getToStop();

        addTransferLegIfNeeded(state, fromStop, toStop, options, legs);
      }

      currentIndex++;
    }

    return currentIndex;
  }

  private void addTransferLegIfNeeded(State state, StopEntry fromStop,
      StopEntry toStop, OBATraverseOptions options, List<LegBean> legs) {

    if (!fromStop.equals(toStop)) {

      long timeFrom = state.getBackState().getTime();
      long timeTo = state.getTime();

      GraphPath path = _itinerariesService.getWalkingItineraryBetweenStops(
          fromStop, toStop, new Date(timeFrom), options);

      if (path != null) {
        ItineraryBean walk = getPathAsItinerary(path, options);
        scaleItinerary(walk, timeFrom, timeTo);
        legs.addAll(walk.getLegs());
      }
    }
  }

  private TransitLegBuilder extendTransitLegWithDepartureAndArrival(
      List<LegBean> legs, TransitLegBuilder builder,
      BlockDepartureVertex vFrom, BlockArrivalVertex vTo) {

    ArrivalAndDepartureInstance from = vFrom.getInstance();
    ArrivalAndDepartureInstance to = vTo.getInstance();

    return extendTransitLegWithDepartureAndArrival(legs, builder, from, to);
  }

  private TransitLegBuilder extendTransitLegWithTPDepartureAndArrival(
      List<LegBean> legs, TransitLegBuilder builder,
      TPBlockDepartureVertex vFrom, TPBlockArrivalVertex vTo) {

    ArrivalAndDepartureInstance from = vFrom.getDeparture();
    ArrivalAndDepartureInstance to = vFrom.getArrival();

    builder = extendTransitLegWithDepartureAndArrival(legs, builder, from, to);

    return getTransitLegBuilderAsLeg(builder, legs);
  }

  private TransitLegBuilder extendTransitLegWithDepartureAndArrival(
      List<LegBean> legs, TransitLegBuilder builder,
      ArrivalAndDepartureInstance from, ArrivalAndDepartureInstance to) {

    BlockTripEntry tripFrom = from.getBlockTrip();
    BlockTripEntry tripTo = to.getBlockTrip();

    if (builder.getBlockTripInstanceFrom() == null) {
      builder.setScheduledDepartureTime(from.getScheduledDepartureTime());
      builder.setPredictedDepartureTime(from.getPredictedDepartureTime());
      builder.setBlockTripInstanceFrom(from.getBlockTripInstance());
      builder.setFromStop(from);
    }

    if (!tripFrom.equals(tripTo)) {

      /**
       * We switch trips during the course of the block, so we clean up the
       * current leg and introduce a new one
       */

      /**
       * We just split the difference for now
       */
      long scheduledTransitionTime = (from.getScheduledDepartureTime() + to.getScheduledArrivalTime()) / 2;
      long predictedTransitionTime = 0;

      if (from.isPredictedDepartureTimeSet() && to.isPredictedArrivalTimeSet())
        predictedTransitionTime = (from.getPredictedDepartureTime() + to.getPredictedArrivalTime()) / 2;

      builder.setScheduledArrivalTime(scheduledTransitionTime);
      builder.setPredictedArrivalTime(predictedTransitionTime);
      builder.setToStop(null);
      builder.setNextTrip(tripTo);

      getTransitLegBuilderAsLeg(builder, legs);

      builder = new TransitLegBuilder();
      builder.setScheduledDepartureTime(scheduledTransitionTime);
      builder.setPredictedDepartureTime(predictedTransitionTime);
      builder.setBlockTripInstanceTo(to.getBlockTripInstance());
    }

    builder.setToStop(to);
    builder.setScheduledArrivalTime(to.getScheduledArrivalTime());
    builder.setPredictedArrivalTime(to.getPredictedArrivalTime());
    return builder;
  }

  private TransitLegBuilder extendTransitLegWithArrival(List<LegBean> legs,
      TransitLegBuilder builder, BlockArrivalVertex arrival, Vertex vTo,
      State state, OBATraverseOptions options) {

    /**
     * Did we finish up a transit leg?
     */
    if (vTo instanceof ArrivalVertex) {

      /**
       * We've finished up our transit leg, so publish the leg
       */
      builder = getTransitLegBuilderAsLeg(builder, legs);

    }
    /**
     * Did we have a transfer to another stop?
     */
    else if (vTo instanceof DepartureVertex) {

      /**
       * We've finished up our transit leg either way, so publish the leg
       */
      builder = getTransitLegBuilderAsLeg(builder, legs);

      /**
       * We've possibly transfered to another stop, so we need to insert the
       * walk leg
       */
      ArrivalAndDepartureInstance fromStopTimeInstance = arrival.getInstance();
      StopEntry fromStop = fromStopTimeInstance.getStop();

      DepartureVertex toStopVertex = (DepartureVertex) vTo;
      StopEntry toStop = toStopVertex.getStop();

      addTransferLegIfNeeded(state, fromStop, toStop, options, legs);
    }

    return builder;
  }

  private TransitLegBuilder getTransitLegBuilderAsLeg(
      TransitLegBuilder builder, List<LegBean> legs) {

    BlockTripInstance blockTripInstanceFrom = builder.getBlockTripInstanceFrom();

    if (blockTripInstanceFrom == null)
      return new TransitLegBuilder();

    LegBean leg = createTransitLegFromBuilder(builder);
    legs.add(leg);

    return new TransitLegBuilder();
  }

  private LegBean createTransitLegFromBuilder(TransitLegBuilder builder) {

    BlockTripInstance blockTripInstanceFrom = builder.getBlockTripInstanceFrom();

    LegBean leg = new LegBean();

    leg.setStartTime(builder.getBestDepartureTime());
    leg.setEndTime(builder.getBestArrivalTime());

    double distance = getTransitLegBuilderAsDistance(builder);
    leg.setDistance(distance);

    leg.setMode(MODE_TRANSIT);

    TripEntry trip = blockTripInstanceFrom.getBlockTrip().getTrip();

    TransitLegBean transitLeg = new TransitLegBean();
    leg.setTransitLeg(transitLeg);

    transitLeg.setServiceDate(blockTripInstanceFrom.getServiceDate());

    FrequencyEntry frequencyLabel = blockTripInstanceFrom.getFrequencyLabel();
    if (frequencyLabel != null) {
      FrequencyBean frequency = FrequencyBeanLibrary.getBeanForFrequency(
          blockTripInstanceFrom.getServiceDate(), frequencyLabel);
      transitLeg.setFrequency(frequency);
    }

    TripBean tripBean = _tripBeanService.getTripForId(trip.getId());
    transitLeg.setTrip(tripBean);

    transitLeg.setScheduledDepartureTime(builder.getScheduledDepartureTime());
    transitLeg.setScheduledArrivalTime(builder.getScheduledArrivalTime());

    transitLeg.setPredictedDepartureTime(builder.getPredictedDepartureTime());
    transitLeg.setPredictedArrivalTime(builder.getPredictedArrivalTime());

    String path = getTransitLegBuilderAsPath(builder);
    transitLeg.setPath(path);

    applyFromStopDetailsForTransitLeg(builder, transitLeg, leg);
    applyToStopDetailsForTransitLeg(builder, transitLeg, leg);

    if (leg.getFrom() == null || leg.getTo() == null && path != null) {
      List<CoordinatePoint> points = PolylineEncoder.decode(path);
      if (leg.getFrom() == null)
        leg.setFrom(points.get(0));
      if (leg.getTo() == null)
        leg.setTo(points.get(points.size() - 1));
    }

    return leg;
  }

  private double getTransitLegBuilderAsDistance(TransitLegBuilder builder) {

    BlockTripInstance blockTripInstanceFrom = builder.getBlockTripInstanceFrom();
    BlockTripEntry trip = blockTripInstanceFrom.getBlockTrip();

    BlockStopTimeEntry fromStop = null;
    BlockStopTimeEntry toStop = null;

    if (builder.getFromStop() != null)
      fromStop = builder.getFromStop().getBlockStopTime();

    if (builder.getToStop() != null)
      toStop = builder.getToStop().getBlockStopTime();

    if (fromStop == null && toStop == null)
      return trip.getTrip().getTotalTripDistance();

    if (fromStop == null && toStop != null)
      return toStop.getDistanceAlongBlock() - trip.getDistanceAlongBlock();

    if (fromStop != null && toStop == null)
      return trip.getDistanceAlongBlock()
          + trip.getTrip().getTotalTripDistance()
          - fromStop.getDistanceAlongBlock();

    return toStop.getDistanceAlongBlock() - fromStop.getDistanceAlongBlock();
  }

  private String getTransitLegBuilderAsPath(TransitLegBuilder builder) {

    BlockTripInstance blockTripInstanceFrom = builder.getBlockTripInstanceFrom();
    BlockTripEntry blockTrip = blockTripInstanceFrom.getBlockTrip();
    TripEntry trip = blockTrip.getTrip();

    AgencyAndId shapeId = trip.getShapeId();

    if (shapeId == null)
      return null;

    ShapePoints shapePoints = _shapePointService.getShapePointsForShapeId(shapeId);

    BlockStopTimeEntry fromStop = null;
    BlockStopTimeEntry toStop = null;

    if (builder.getFromStop() != null)
      fromStop = builder.getFromStop().getBlockStopTime();

    if (builder.getToStop() != null)
      toStop = builder.getToStop().getBlockStopTime();

    CoordinatePoint nextPoint = null;

    BlockTripEntry nextBlockTrip = builder.getNextTrip();
    if (nextBlockTrip != null) {
      TripEntry nextTrip = nextBlockTrip.getTrip();
      AgencyAndId nextShapeId = nextTrip.getShapeId();
      if (nextShapeId != null) {
        ShapePoints nextShapePoints = _shapePointService.getShapePointsForShapeId(nextShapeId);
        nextPoint = nextShapePoints.getPointForIndex(0);
      }
    }

    if (fromStop == null && toStop == null) {
      return ShapeSupport.getFullPath(shapePoints, nextPoint);
    }

    if (fromStop == null && toStop != null) {
      return ShapeSupport.getPartialPathToStop(shapePoints,
          toStop.getStopTime());
    }

    if (fromStop != null && toStop == null) {
      return ShapeSupport.getPartialPathFromStop(shapePoints,
          fromStop.getStopTime(), nextPoint);
    }

    return ShapeSupport.getPartialPathBetweenStops(shapePoints,
        fromStop.getStopTime(), toStop.getStopTime());
  }

  private void applyFromStopDetailsForTransitLeg(TransitLegBuilder builder,
      TransitLegBean transitLeg, LegBean leg) {

    ArrivalAndDepartureInstance fromStopTimeInstance = builder.getFromStop();

    if (fromStopTimeInstance == null)
      return;

    BlockStopTimeEntry bstFrom = fromStopTimeInstance.getBlockStopTime();

    StopTimeEntry fromStopTime = bstFrom.getStopTime();
    StopTimeNarrative stopTimeNarrative = _narrativeService.getStopTimeForEntry(fromStopTime);
    transitLeg.setRouteShortName(stopTimeNarrative.getRouteShortName());
    transitLeg.setTripHeadsign(stopTimeNarrative.getStopHeadsign());

    StopEntry fromStop = fromStopTimeInstance.getStop();
    StopBean fromStopBean = _stopBeanService.getStopForId(fromStop.getId());
    transitLeg.setFromStop(fromStopBean);

    transitLeg.setFromStopSequence(fromStopTime.getSequence());

    leg.setFrom(fromStop.getStopLocation());

    BlockLocation blockLocation = fromStopTimeInstance.getBlockLocation();
    if (blockLocation != null) {
      AgencyAndId vehicleId = blockLocation.getVehicleId();
      transitLeg.setVehicleId(AgencyAndIdLibrary.convertToString(vehicleId));
    }
  }

  private void applyToStopDetailsForTransitLeg(TransitLegBuilder builder,
      TransitLegBean transitLeg, LegBean leg) {

    ArrivalAndDepartureInstance toStopTimeInstance = builder.getToStop();

    if (toStopTimeInstance == null)
      return;

    StopEntry toStop = toStopTimeInstance.getStop();
    StopBean toStopBean = _stopBeanService.getStopForId(toStop.getId());
    transitLeg.setToStop(toStopBean);

    BlockStopTimeEntry blockStopTime = toStopTimeInstance.getBlockStopTime();
    StopTimeEntry stopTime = blockStopTime.getStopTime();
    transitLeg.setToStopSequence(stopTime.getSequence());

    leg.setTo(toStop.getStopLocation());

    BlockLocation blockLocation = toStopTimeInstance.getBlockLocation();
    if (blockLocation != null) {
      AgencyAndId vehicleId = blockLocation.getVehicleId();
      transitLeg.setVehicleId(AgencyAndIdLibrary.convertToString(vehicleId));
    }
  }

  private int extendStreetLeg(List<State> states, int currentIndex,
      TraverseMode mode, List<LegBean> legs) {

    List<State> streetStates = new ArrayList<State>();

    while (currentIndex < states.size()) {

      State state = states.get(currentIndex);
      EdgeNarrative narrative = state.getBackEdgeNarrative();
      TraverseMode edgeMode = narrative.getMode();

      if (mode != edgeMode)
        break;

      streetStates.add(state);

      currentIndex++;
    }

    if (!streetStates.isEmpty()) {
      getStreetLegBuilderAsLeg(streetStates, mode, legs);
    }

    return currentIndex;
  }

  private void getStreetLegBuilderAsLeg(List<State> streetStates,
      TraverseMode mode, List<LegBean> legs) {

    List<StreetLegBean> streetLegs = new ArrayList<StreetLegBean>();

    StreetLegBean streetLeg = null;
    List<CoordinatePoint> path = new ArrayList<CoordinatePoint>();

    double distance = 0.0;
    double totalDistance = 0.0;

    long startTime = 0;
    long endTime = 0;

    CoordinatePoint from = null;
    CoordinatePoint to = null;

    for (State state : streetStates) {

      EdgeNarrative edgeResult = state.getBackEdgeNarrative();

      Geometry geom = edgeResult.getGeometry();
      if (geom == null) {
        continue;
      }

      String streetName = edgeResult.getName();

      if (streetLeg == null
          || !ObjectUtils.equals(streetLeg.getStreetName(), streetName)) {

        addPathToStreetLegIfApplicable(streetLeg, path, distance);

        streetLeg = createStreetLeg(state);
        streetLegs.add(streetLeg);
        path = new ArrayList<CoordinatePoint>();

        appendGeometryToPath(geom, path, true);
        distance = edgeResult.getDistance();

      } else {

        appendGeometryToPath(geom, path, false);
        distance += edgeResult.getDistance();
      }

      totalDistance += edgeResult.getDistance();

      if (startTime == 0)
        startTime = state.getBackState().getTime();
      endTime = state.getTime();

      if (!path.isEmpty()) {
        if (from == null)
          from = path.get(0);
        to = path.get(path.size() - 1);
      }

    }

    addPathToStreetLegIfApplicable(streetLeg, path, distance);

    LegBean leg = new LegBean();
    legs.add(leg);

    leg.setStartTime(startTime);
    leg.setEndTime(endTime);

    leg.setMode(getStreetModeAsString(mode));

    leg.setFrom(from);
    leg.setTo(to);
    leg.setDistance(totalDistance);

    leg.setStreetLegs(streetLegs);
  }

  private void addPathToStreetLegIfApplicable(StreetLegBean streetLeg,
      List<CoordinatePoint> path, double distance) {
    if (streetLeg != null) {
      EncodedPolylineBean polyline = PolylineEncoder.createEncodings(path);
      streetLeg.setPath(polyline.getPoints());
      streetLeg.setDistance(distance);
    }
  }

  private void appendGeometryToPath(Geometry geom, List<CoordinatePoint> path,
      boolean includeFirstPoint) {

    if (geom instanceof LineString) {
      LineString ls = (LineString) geom;

      for (int i = 0; i < ls.getNumPoints(); i++) {
        if (i == 0 && !includeFirstPoint)
          continue;

        Coordinate c = ls.getCoordinateN(i);
        CoordinatePoint p = new CoordinatePoint(c.y, c.x);
        path.add(p);
      }
    } else {
      throw new IllegalStateException("unknown geometry: " + geom);
    }
  }

  private StreetLegBean createStreetLeg(State state) {

    StreetLegBean bean = new StreetLegBean();
    bean.setStreetName(state.getBackEdgeNarrative().getName());
    return bean;
  }

  private String getStreetModeAsString(TraverseMode mode) {

    switch (mode) {
      case BICYCLE:
        return MODE_BICYCLE;
      case WALK:
        return MODE_WALK;
    }

    throw new IllegalStateException("unknown street mode: " + mode);
  }

  private void scaleItinerary(ItineraryBean bean, long timeFrom, long timeTo) {

    long tStart = bean.getStartTime();
    long tEnd = bean.getEndTime();

    double ratio = (timeTo - timeFrom) / (tEnd - tStart);

    bean.setStartTime(scaleTime(tStart, timeFrom, ratio, tStart));
    bean.setEndTime(scaleTime(tStart, timeFrom, ratio, tEnd));

    for (LegBean leg : bean.getLegs()) {
      leg.setStartTime(scaleTime(tStart, timeFrom, ratio, leg.getStartTime()));
      leg.setEndTime(scaleTime(tStart, timeFrom, ratio, leg.getEndTime()));
    }
  }

  private long scaleTime(long tStartOrig, long tStartNew, double ratio, long t) {
    return (long) ((t - tStartOrig) * ratio + tStartNew);
  }

  private void ensureSelectedItineraryIsIncluded(TransitLocationBean from,
      TransitLocationBean to, long targetTime, ItinerariesBean itineraries,
      ItineraryBean selected, OBATraverseOptions options) {

    if (selected == null)
      return;

    if (!isItinerarySufficientlySpecified(selected))
      return;

    for (ItineraryBean itinerary : itineraries.getItineraries()) {
      if (isItineraryMatch(itinerary, selected)) {
        itinerary.setSelected(true);
        return;
      }
    }

    updateItinerary(selected, from, to, targetTime, options);
    selected.setSelected(true);

    itineraries.getItineraries().add(selected);
  }

  private boolean isItinerarySufficientlySpecified(ItineraryBean itinerary) {
    for (LegBean leg : itinerary.getLegs()) {
      if (!isLegSufficientlySpecified(leg))
        return false;
    }
    return true;
  }

  private boolean isLegSufficientlySpecified(LegBean leg) {

    if (leg == null)
      return false;

    if (leg.getFrom() == null || leg.getTo() == null)
      return false;

    String mode = leg.getMode();
    if (MODE_TRANSIT.equals(mode)) {
      if (!isTransitLegSufficientlySpecified(leg.getTransitLeg()))
        return false;
    } else if (MODE_WALK.equals(mode) || MODE_BICYCLE.equals(mode)) {

    } else {
      return false;
    }

    return true;
  }

  private boolean isTransitLegSufficientlySpecified(TransitLegBean leg) {
    if (leg == null)
      return false;
    if (leg.getTrip() == null || leg.getTrip().getId() == null)
      return false;
    if (leg.getServiceDate() <= 0)
      return false;
    return true;
  }

  private boolean isItineraryMatch(ItineraryBean a, ItineraryBean b) {
    List<String> instancesA = getTransitInstancesForItinerary(a);
    List<String> instancesB = getTransitInstancesForItinerary(b);
    return instancesA.equals(instancesB);
  }

  private List<String> getTransitInstancesForItinerary(ItineraryBean itinerary) {
    List<String> instances = new ArrayList<String>();
    for (LegBean leg : itinerary.getLegs()) {
      TransitLegBean transitLeg = leg.getTransitLeg();
      if (transitLeg != null) {
        String instance = transitLeg.getTrip().getId() + " "
            + transitLeg.getServiceDate();
        instances.add(instance);
      }
    }
    return instances;
  }

  private void updateItinerary(ItineraryBean itinerary,
      TransitLocationBean from, TransitLocationBean to, long targetTime,
      OBATraverseOptions options) {

    List<LegBean> legs = itinerary.getLegs();

    int firstTransitLegIndex = -1;

    /**
     * Update the legs
     */
    for (int i = 0; i < legs.size(); i++) {

      LegBean leg = legs.get(i);
      TransitLegBean transitLeg = leg.getTransitLeg();

      if (transitLeg != null) {
        LegBean updatedLeg = updateTransitLeg(transitLeg, options);
        legs.set(i, updatedLeg);

        if (firstTransitLegIndex == -1)
          firstTransitLegIndex = i;

      } else if (isStreetLeg(leg)) {

        Date time = new Date(targetTime);

        CoordinatePoint walkFrom = leg.getFrom();
        CoordinatePoint walkTo = leg.getTo();

        /**
         * Adjust the start and end locations for walk-legs to match the query
         * points. This is a hack, since it allows the client to pass in the
         * original unmodified itinerary from a previous to call, but also
         * slightly change their start or end point (aka user walks some
         * distance) without having to understand how to update the itinerary
         * object itself.
         */
        if (i == 0)
          walkFrom = from.getLocation();
        if (i + 1 == legs.size())
          walkTo = to.getLocation();

        GraphPath path = _itinerariesService.getWalkingItineraryBetweenPoints(
            walkFrom, walkTo, time, options);

        if (path == null) {
          throw new IllegalStateException("expected walking path to exist");
        }

        ItineraryBean walkItinerary = getPathAsItinerary(path, options);
        legs.set(i, walkItinerary.getLegs().get(0));
      }
    }

    /**
     * Update the times
     */
    if (firstTransitLegIndex == -1) {

    } else {

      long nextTime = legs.get(firstTransitLegIndex).getStartTime();
      for (int i = firstTransitLegIndex - 1; i >= 0; i--) {

        LegBean leg = legs.get(i);
        if (isStreetLeg(leg)) {
          long duration = leg.getEndTime() - leg.getStartTime();
          leg.setEndTime(nextTime);
          leg.setStartTime(nextTime - duration);
        }

        nextTime = leg.getStartTime();
      }

      long prevTime = legs.get(firstTransitLegIndex).getEndTime();
      for (int i = firstTransitLegIndex + 1; i < legs.size(); i++) {

        LegBean leg = legs.get(i);
        if (isStreetLeg(leg)) {
          long duration = leg.getEndTime() - leg.getStartTime();
          leg.setStartTime(prevTime);
          leg.setEndTime(prevTime + duration);
        }

        prevTime = leg.getEndTime();
      }

      itinerary.setStartTime(nextTime);
      itinerary.setEndTime(prevTime);
    }
  }

  private boolean isStreetLeg(LegBean leg) {
    return MODE_WALK.equals(leg.getMode())
        || MODE_BICYCLE.equals(leg.getMode());
  }

  private LegBean updateTransitLeg(TransitLegBean transitLeg,
      OBATraverseOptions options) {

    TransitLegBuilder b = new TransitLegBuilder();

    AgencyAndId tripId = AgencyAndIdLibrary.convertFromString(transitLeg.getTrip().getId());
    TripEntry trip = _transitGraphDao.getTripEntryForId(tripId);

    if (trip == null)
      throw new NoSuchTripServiceException(transitLeg.getTrip().getId());

    long serviceDate = transitLeg.getServiceDate();

    AgencyAndId vehicleId = null;
    if (transitLeg.getVehicleId() != null)
      vehicleId = AgencyAndIdLibrary.convertFromString(transitLeg.getVehicleId());

    if (transitLeg.getFromStop() != null
        && transitLeg.getFromStop().getId() != null) {

      AgencyAndId fromStopId = AgencyAndIdLibrary.convertFromString(transitLeg.getFromStop().getId());
      StopEntry fromStop = _transitGraphDao.getStopEntryForId(fromStopId, true);
      int fromStopSequence = transitLeg.getFromStopSequence();

      ArrivalAndDepartureQuery query = new ArrivalAndDepartureQuery();
      query.setStop(fromStop);
      query.setStopSequence(fromStopSequence);
      query.setTrip(trip);
      query.setServiceDate(serviceDate);
      query.setVehicleId(vehicleId);
      query.setTime(options.currentTime);

      ArrivalAndDepartureInstance instance = _arrivalAndDepartureService.getArrivalAndDepartureForStop(query);

      b.setFromStop(instance);
      b.setBlockTripInstanceFrom(instance.getBlockTripInstance());
      b.setScheduledDepartureTime(instance.getScheduledDepartureTime());
      b.setPredictedDepartureTime(instance.getPredictedDepartureTime());
    }

    if (transitLeg.getToStop() != null
        && transitLeg.getToStop().getId() != null) {

      AgencyAndId toStopId = AgencyAndIdLibrary.convertFromString(transitLeg.getToStop().getId());
      StopEntry toStop = _transitGraphDao.getStopEntryForId(toStopId, true);
      int toStopSequence = transitLeg.getToStopSequence();

      ArrivalAndDepartureQuery query = new ArrivalAndDepartureQuery();
      query.setStop(toStop);
      query.setStopSequence(toStopSequence);
      query.setTrip(trip);
      query.setServiceDate(serviceDate);
      query.setVehicleId(vehicleId);
      query.setTime(options.currentTime);

      ArrivalAndDepartureInstance instance = _arrivalAndDepartureService.getArrivalAndDepartureForStop(query);

      b.setToStop(instance);
      b.setBlockTripInstanceTo(instance.getBlockTripInstance());
      b.setScheduledArrivalTime(instance.getScheduledArrivalTime());
      b.setPredictedArrivalTime(instance.getPredictedArrivalTime());
    }

    if (b.getBlockTripInstanceFrom() == null) {

      BlockEntry block = trip.getBlock();

      BlockInstance blockInstance = _blockCalendarService.getBlockInstance(
          block.getId(), serviceDate);
      BlockTripInstance tripInstance = BlockTripInstanceLibrary.getBlockTripInstance(
          blockInstance, trip.getId());
      b.setBlockTripInstanceFrom(tripInstance);
    }

    return createTransitLegFromBuilder(b);
  }

  private VertexBean getVertexAsBean(Map<Vertex, VertexBean> beansByVertex,
      Vertex vertex) {

    VertexBean bean = beansByVertex.get(vertex);

    if (bean == null) {

      bean = new VertexBean();
      bean.setId(vertex.getLabel());
      bean.setLocation(new CoordinatePoint(vertex.getY(), vertex.getX()));

      Map<String, Object> tags = new HashMap<String, Object>();

      tags.put("class", vertex.getClass().getName());

      if (vertex instanceof StreetVertex) {
        StreetVertex sv = (StreetVertex) vertex;
        StreetTraversalPermission perms = sv.getPermission();
        if (perms != null)
          tags.put("access", perms.toString().toLowerCase());
      } else if (vertex instanceof AbstractStopVertex) {
        AbstractStopVertex stopVertex = (AbstractStopVertex) vertex;
        StopEntry stop = stopVertex.getStop();
        StopBean stopBean = _stopBeanService.getStopForId(stop.getId());
        tags.put("stop", stopBean);
      }

      bean.setTags(tags);

      beansByVertex.put(vertex, bean);

    }

    return bean;
  }

  private MinTravelTimeToStopsBean getStopTravelTimesAsResultsBean(
      Map<StopEntry, Long> results, double walkingVelocity) {

    int n = results.size();

    String[] stopIds = new String[n];
    double[] lats = new double[n];
    double[] lons = new double[n];
    long[] times = new long[n];

    int index = 0;
    String agencyId = null;

    for (Map.Entry<StopEntry, Long> entry : results.entrySet()) {
      StopEntry stop = entry.getKey();
      agencyId = stop.getId().getAgencyId();
      Long time = entry.getValue();
      stopIds[index] = ApplicationBeanLibrary.getId(stop.getId());
      lats[index] = stop.getStopLat();
      lons[index] = stop.getStopLon();
      times[index] = time;
      index++;
    }
    return new MinTravelTimeToStopsBean(agencyId, stopIds, lats, lons, times,
        walkingVelocity);
  }

  private static class SortByDeparture implements Comparator<ItineraryBean> {

    @Override
    public int compare(ItineraryBean o1, ItineraryBean o2) {
      long t1 = o1.getStartTime();
      long t2 = o2.getStartTime();
      return t1 == t2 ? 0 : (t1 < t2 ? -1 : 1);
    }
  }

  private static class SortByArrival implements Comparator<ItineraryBean> {

    @Override
    public int compare(ItineraryBean o1, ItineraryBean o2) {
      long t1 = o1.getEndTime();
      long t2 = o2.getEndTime();
      return t1 == t2 ? 0 : (t1 > t2 ? -1 : 1);
    }
  }

  private static class TripToStop implements Comparable<TripToStop> {

    private AgencyAndId _stopId;
    private long _transitTimeToStop;
    private double _minTransitTimeToPlace;
    private int _index;

    public TripToStop(AgencyAndId stopId, long transitTimeToStop,
        double minTransitTimeToPlace, int index) {
      _stopId = stopId;
      _transitTimeToStop = transitTimeToStop;
      _minTransitTimeToPlace = minTransitTimeToPlace;
      _index = index;
    }

    public AgencyAndId getStopId() {
      return _stopId;
    }

    public long getTransitTimeToStop() {
      return _transitTimeToStop;
    }

    public double getMinTansitTimeToPlace() {
      return _minTransitTimeToPlace;
    }

    public int getIndex() {
      return _index;
    }

    public int compareTo(TripToStop o) {
      return _minTransitTimeToPlace == o._minTransitTimeToPlace ? 0
          : (_minTransitTimeToPlace < o._minTransitTimeToPlace ? -1 : 1);
    }
  }
}
TOP

Related Classes of org.onebusaway.transit_data_federation.impl.beans.itineraries.ItinerariesBeanServiceImpl$TripToStop

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.