public WaitTimeStuckCalculator(
     final Population population,
     final TransitSchedule transitSchedule,
     final int timeSlot,
     final int totalTime) {
   this.population = population;
   this.timeSlot = timeSlot;
   for (TransitLine line : transitSchedule.getTransitLines().values())
     for (TransitRoute route : line.getRoutes().values()) {
       double[] sortedDepartures = new double[route.getDepartures().size()];
       int d = 0;
       for (Departure departure : route.getDepartures().values())
         sortedDepartures[d++] = departure.getDepartureTime();
       Arrays.sort(sortedDepartures);
       Map<Id<TransitStopFacility>, WaitTimeData> stopsMap =
           new HashMap<Id<TransitStopFacility>, WaitTimeData>(100);
       Map<Id<TransitStopFacility>, double[]> stopsScheduledMap =
           new HashMap<Id<TransitStopFacility>, double[]>(100);
       for (TransitRouteStop stop : route.getStops()) {
         stopsMap.put(
             stop.getStopFacility().getId(), new WaitTimeDataArray(totalTime / timeSlot + 1));
         double[] cacheWaitTimes = new double[totalTime / timeSlot + 1];
         for (int i = 0; i < cacheWaitTimes.length; i++) {
           double endTime = timeSlot * (i + 1);
           if (endTime > 24 * 3600) endTime -= 24 * 3600;
           cacheWaitTimes[i] = Time.UNDEFINED_TIME;
           SORTED_DEPARTURES:
           for (double departure : sortedDepartures) {
             double arrivalTime =
                 departure
                     + (stop.getArrivalOffset() != Time.UNDEFINED_TIME
                         ? stop.getArrivalOffset()
                         : stop.getDepartureOffset());
             if (arrivalTime >= endTime) {
               cacheWaitTimes[i] = arrivalTime - endTime;
               break SORTED_DEPARTURES;
             }
           }
           if (cacheWaitTimes[i] == Time.UNDEFINED_TIME)
             cacheWaitTimes[i] =
                 sortedDepartures[0]
                     + 24 * 3600
                     + (stop.getArrivalOffset() != Time.UNDEFINED_TIME
                         ? stop.getArrivalOffset()
                         : stop.getDepartureOffset())
                     - endTime;
         }
         stopsScheduledMap.put(stop.getStopFacility().getId(), cacheWaitTimes);
       }
       Tuple<Id<TransitLine>, Id<TransitRoute>> key =
           new Tuple<Id<TransitLine>, Id<TransitRoute>>(line.getId(), route.getId());
       waitTimes.put(key, stopsMap);
       scheduledWaitTimes.put(key, stopsScheduledMap);
     }
 }
 public void testInitialization() {
   TransitStopFacility stopFacility =
       new TransitStopFacilityImpl(
           Id.create(1, TransitStopFacility.class), new CoordImpl(2, 3), false);
   double arrivalDelay = 4;
   double departureDelay = 5;
   TransitRouteStop routeStop = createTransitRouteStop(stopFacility, arrivalDelay, departureDelay);
   assertEquals(stopFacility, routeStop.getStopFacility());
   assertEquals(arrivalDelay, routeStop.getArrivalOffset(), EPSILON);
   assertEquals(departureDelay, routeStop.getDepartureOffset(), EPSILON);
 }
  private final void createVehicleLinkSpeedAttributes() {
    for (TransitLine transitLine : scenario.getTransitSchedule().getTransitLines().values()) {
      for (TransitRoute transitRoute : transitLine.getRoutes().values()) {
        Set<Id> vehIds = new HashSet<Id>();
        for (Departure departure : transitRoute.getDepartures().values()) {
          vehIds.add(departure.getVehicleId());
        }

        Iterator<TransitRouteStop> iterator = transitRoute.getStops().iterator();
        double departure = iterator.next().getDepartureOffset();
        while (iterator.hasNext()) {
          TransitRouteStop routeStop = iterator.next();
          double arrival = routeStop.getArrivalOffset();
          Link link = scenario.getNetwork().getLinks().get(routeStop.getStopFacility().getLinkId());
          double speed = link.getLength() / (arrival - departure);
          if (speed >= 200.0) {
            System.out.println(
                "line="
                    + transitLine.getId()
                    + ";route="
                    + transitRoute.getId()
                    + "stop="
                    + routeStop.getStopFacility().getId()
                    + ": lLenth="
                    + link.getLength()
                    + ";arr="
                    + arrival
                    + ";dep="
                    + departure
                    + "");
          }

          for (Id vehId : vehIds) {
            this.vehicleAttributes.putAttribute(vehId.toString(), link.getId().toString(), speed);
          }

          departure = routeStop.getDepartureOffset();
        }
      }
    }
  }
  @Override
  public double getLinkTravelTime(Link link, final double time, Person person, Vehicle vehicle) {

    // if its a RoutingNetworkLink, unwrap it
    if (link instanceof RoutingNetworkLink) link = ((RoutingNetworkLink) link).getLink();

    //		Link previousLink = this.previousLinks.get();
    //		Double previousTime = this.previousTimes.get();	// has to be Double since get() might return
    // null!

    //		if ((link == previousLink) && (time == previousTime)) {
    //			return this.cachedTravelTimes.get();
    //		}
    //		this.previousLinks.set(link);
    //		this.previousTimes.set(time);

    BufferedData bd = bufferedData.get();
    if (bd == null) {
      bd = new BufferedData();
      bufferedData.set(bd);
    }
    if ((link == bd.previousLink) && (time == bd.previousTime)) {
      return bd.cachedTravelTime;
    }
    bd.previousLink = link;
    bd.previousTime = time;

    TransitRouterNetworkLink wrapped = (TransitRouterNetworkLink) link;
    TransitRouteStop fromStop = wrapped.fromNode.stop;
    TransitRouteStop toStop = wrapped.toNode.stop;
    if (wrapped.getRoute() != null) {
      // (agent stays on the same route, so use transit line travel time)

      double bestDepartureTime =
          departureTimeCache.getNextDepartureTime(wrapped.getRoute(), fromStop, time);

      // the travel time on the link is
      //   the time until the departure (``dpTime - now'')
      //   + the travel time on the link (there.arrivalTime - here.departureTime)
      // But quite often, we only have the departure time at the next stop.  Then we use that:
      double arrivalOffset =
          (toStop.getArrivalOffset() != Time.UNDEFINED_TIME)
              ? toStop.getArrivalOffset()
              : toStop.getDepartureOffset();
      double time2 = (bestDepartureTime - time) + (arrivalOffset - fromStop.getDepartureOffset());
      if (time2 < 0) {
        // ( this can only happen, I think, when ``bestDepartureTime'' is after midnight but
        // ``time'' was before )
        time2 += MIDNIGHT;
      }
      //			this.cachedTravelTimes.set(time2);
      bd.cachedTravelTime = time2;
      return time2;
    }
    // different transit routes, so it must be a line switch
    double distance = wrapped.getLength();
    double time2 =
        distance / this.config.getBeelineWalkSpeed() + this.config.getAdditionalTransferTime();
    //		this.cachedTravelTimes.set(time2);
    bd.cachedTravelTime = time2;

    return time2;
  }