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 TransitRouteData(Network network, TransitRoute transitRoute) {

    this.transportMode = transitRoute.getTransportMode();

    this.firstDeparture = Double.MAX_VALUE;
    this.lastDeparture = -Double.MAX_VALUE;
    this.vehIds = new TreeSet<String>();
    this.numberOfDepartures = 0;

    for (Departure departure : transitRoute.getDepartures().values()) {
      this.firstDeparture = Math.min(this.firstDeparture, departure.getDepartureTime());
      this.lastDeparture = Math.max(this.lastDeparture, departure.getDepartureTime());
      this.vehIds.add(departure.getVehicleId().toString());
      this.numberOfDepartures++;
    }

    this.firstStop = transitRoute.getStops().get(0).getStopFacility();
    this.lastStop =
        transitRoute.getStops().get(transitRoute.getStops().size() - 1).getStopFacility();

    if (this.firstStop == this.lastStop) {
      // get the stop location of stop with the largest distance between first and last stop
      TransitStopFacility currentViaStop = null;
      double currentViaDistance = Double.NEGATIVE_INFINITY;
      for (TransitRouteStop stop : transitRoute.getStops()) {
        double distanceFirstPotentialVia =
            CoordUtils.calcDistance(this.firstStop.getCoord(), stop.getStopFacility().getCoord());
        double distanceLastProtenialVia =
            CoordUtils.calcDistance(this.lastStop.getCoord(), stop.getStopFacility().getCoord());
        double newDistance =
            Math.sqrt(
                Math.pow(distanceFirstPotentialVia, 2) + Math.pow(distanceLastProtenialVia, 2));

        if (newDistance > currentViaDistance) {
          // this one is farther away - keep it
          currentViaStop = stop.getStopFacility();
          currentViaDistance = newDistance;
        }
      }
      this.viaStop = currentViaStop;
    } else {
      // get the stop in the middle of the line
      this.viaStop =
          transitRoute.getStops().get((int) (transitRoute.getStops().size() / 2)).getStopFacility();
    }

    // calculate the length of the route
    double distance = 0.0;
    double freeSpeedTravelTime = 0.0;
    for (Id<Link> linkId : transitRoute.getRoute().getLinkIds()) {
      Link link = network.getLinks().get(linkId);
      distance += link.getLength();
      freeSpeedTravelTime += link.getLength() / link.getFreespeed();
    }
    // add last link but not the first link
    Link link = network.getLinks().get(transitRoute.getRoute().getEndLinkId());
    distance += link.getLength();
    freeSpeedTravelTime += link.getLength() / link.getFreespeed();

    this.distance = distance;
    this.freeSpeedTravelTime = freeSpeedTravelTime;

    this.travelTime =
        transitRoute.getStops().get(transitRoute.getStops().size() - 1).getArrivalOffset();

    this.avgSpeed = this.distance / this.travelTime;
  }
  private final void convertSchedules(
      OTTDataContainer dataContainer, ObjectAttributes trainTypes, boolean isPerformance) {
    TransitScheduleFactory scheduleFactory = scenario.getTransitSchedule().getFactory();
    VehiclesFactory vehiclesFactory = ((ScenarioImpl) scenario).getVehicles().getFactory();

    VehicleType vehicleType =
        vehiclesFactory.createVehicleType(new IdImpl(WagonSimConstants.DEFAULT_VEHICLE_TYPE));
    VehicleCapacity vehicleCapacity = vehiclesFactory.createVehicleCapacity();
    // we do not use this capacity. Therefore it should infinite, otherwise this capacity may exceed
    // before ``our'' capacities are exceeded // dr, oct'13
    vehicleCapacity.setSeats(999999);
    vehicleCapacity.setStandingRoom(999999);
    // we defined the vehicle-enter/leave-time is implicit included in transfer-times which
    // are defined in the transitrouterconfig (for handling see
    // WagonSimTripRouterFactoryImpl#WagonSimRouterWrapper)
    // dr, oct'13
    vehicleType.setAccessTime(0);
    vehicleType.setEgressTime(0);
    vehicleType.setCapacity(vehicleCapacity);
    ((ScenarioImpl) scenario).getVehicles().addVehicleType(vehicleType);

    Date startDate = extractStartDate(dataContainer, isPerformance);
    System.out.println("startDate=" + startDate.toString());

    for (Locomotive locomotive : dataContainer.locomotives.values()) {

      Departure departure = null;
      List<TransitRouteStop> transitRouteStops = new ArrayList<TransitRouteStop>();
      for (StationData stationData : locomotive.trips.values()) {

        TransitStopFacility stopFacility =
            scenario.getTransitSchedule().getFacilities().get(stationData.stationId);
        if (stopFacility == null) {
          throw new RuntimeException(
              "locomotive id="
                  + locomotive.id
                  + ": station id="
                  + stationData.stationId
                  + " not found. Bailing out.");
        }

        double arrivalDelay = Double.NaN;
        double departureDelay = Double.NaN;
        if (departure == null) {
          double lineDepartureOffset =
              (stationData.departure.getTime() - startDate.getTime()) / 1000.0;
          if (!isPerformance) {
            lineDepartureOffset -= stationData.delayDeparture;
          }
          departure = scheduleFactory.createDeparture(locomotive.id, lineDepartureOffset);
          arrivalDelay = 0.0;
        } else {
          arrivalDelay =
              (stationData.arrival.getTime() - startDate.getTime()) / 1000.0
                  - departure.getDepartureTime();
          if (!isPerformance) {
            arrivalDelay -= stationData.delayArrival;
          }
        }
        departureDelay =
            (stationData.departure.getTime() - startDate.getTime()) / 1000.0
                - departure.getDepartureTime();
        if (!isPerformance) {
          departureDelay -= stationData.delayDeparture;
        }

        if (departureDelay < arrivalDelay) {
          throw new RuntimeException(
              "locomotive id="
                  + locomotive.id
                  + ": arrival="
                  + stationData.arrival.toString()
                  + " does not fit with departure="
                  + stationData.departure.toString()
                  + ". ("
                  + departureDelay
                  + "<"
                  + arrivalDelay
                  + ") Bailing out.");
        }

        TransitRouteStop stop =
            scheduleFactory.createTransitRouteStop(stopFacility, arrivalDelay, departureDelay);
        stop.setAwaitDepartureTime(true);
        transitRouteStops.add(stop);
      }

      if (transitRouteStops.size() > 1) {

        // check if train type is given
        if (trainTypes.getAttribute(locomotive.type.toString(), WagonSimConstants.TRAIN_MAX_SPEED)
            == null) {
          throw new RuntimeException(
              "locomotive id="
                  + locomotive.id
                  + ": type="
                  + locomotive.type
                  + " is not defined by the train type table. Bailing out.");
        }

        TransitLine line = scheduleFactory.createTransitLine(locomotive.id);
        scenario.getTransitSchedule().addTransitLine(line);
        TransitRoute route =
            scheduleFactory.createTransitRoute(
                line.getId(), null, transitRouteStops, TransportMode.pt);
        line.addRoute(route);

        Vehicle vehicle = vehiclesFactory.createVehicle(route.getId(), vehicleType);
        ((ScenarioImpl) scenario).getVehicles().addVehicle(vehicle);
        departure.setVehicleId(vehicle.getId());
        route.addDeparture(departure);
        this.vehicleAttributes.putAttribute(
            vehicle.getId().toString(), WagonSimConstants.TRAIN_TYPE, locomotive.type);
        this.vehicleAttributes.putAttribute(
            vehicle.getId().toString(),
            WagonSimConstants.TRAIN_MAX_SPEED,
            (Double)
                trainTypes.getAttribute(
                    locomotive.type.toString(), WagonSimConstants.TRAIN_MAX_SPEED));
        this.vehicleAttributes.putAttribute(
            vehicle.getId().toString(),
            WagonSimConstants.TRAIN_MAX_WEIGHT,
            (Double)
                trainTypes.getAttribute(
                    locomotive.type.toString(), WagonSimConstants.TRAIN_MAX_WEIGHT));
        this.vehicleAttributes.putAttribute(
            vehicle.getId().toString(),
            WagonSimConstants.TRAIN_MAX_LENGTH,
            (Double)
                trainTypes.getAttribute(
                    locomotive.type.toString(), WagonSimConstants.TRAIN_MAX_LENGTH));

        // the next day
        vehicle = vehiclesFactory.createVehicle(new IdImpl(route.getId() + ".1"), vehicleType);
        ((ScenarioImpl) scenario).getVehicles().addVehicle(vehicle);
        departure =
            scheduleFactory.createDeparture(
                vehicle.getId(), departure.getDepartureTime() + 24 * 3600);
        departure.setVehicleId(vehicle.getId());
        route.addDeparture(departure);
        this.vehicleAttributes.putAttribute(
            vehicle.getId().toString(), WagonSimConstants.TRAIN_TYPE, locomotive.type);
        this.vehicleAttributes.putAttribute(
            vehicle.getId().toString(),
            WagonSimConstants.TRAIN_MAX_SPEED,
            (Double)
                trainTypes.getAttribute(
                    locomotive.type.toString(), WagonSimConstants.TRAIN_MAX_SPEED));
        this.vehicleAttributes.putAttribute(
            vehicle.getId().toString(),
            WagonSimConstants.TRAIN_MAX_WEIGHT,
            (Double)
                trainTypes.getAttribute(
                    locomotive.type.toString(), WagonSimConstants.TRAIN_MAX_WEIGHT));
        this.vehicleAttributes.putAttribute(
            vehicle.getId().toString(),
            WagonSimConstants.TRAIN_MAX_LENGTH,
            (Double)
                trainTypes.getAttribute(
                    locomotive.type.toString(), WagonSimConstants.TRAIN_MAX_LENGTH));

        // the day after the next day
        vehicle = vehiclesFactory.createVehicle(new IdImpl(route.getId() + ".2"), vehicleType);
        ((ScenarioImpl) scenario).getVehicles().addVehicle(vehicle);
        departure =
            scheduleFactory.createDeparture(
                vehicle.getId(), departure.getDepartureTime() + 24 * 3600);
        departure.setVehicleId(vehicle.getId());
        route.addDeparture(departure);
        this.vehicleAttributes.putAttribute(
            vehicle.getId().toString(), WagonSimConstants.TRAIN_TYPE, locomotive.type);
        this.vehicleAttributes.putAttribute(
            vehicle.getId().toString(),
            WagonSimConstants.TRAIN_MAX_SPEED,
            (Double)
                trainTypes.getAttribute(
                    locomotive.type.toString(), WagonSimConstants.TRAIN_MAX_SPEED));
        this.vehicleAttributes.putAttribute(
            vehicle.getId().toString(),
            WagonSimConstants.TRAIN_MAX_WEIGHT,
            (Double)
                trainTypes.getAttribute(
                    locomotive.type.toString(), WagonSimConstants.TRAIN_MAX_WEIGHT));
        this.vehicleAttributes.putAttribute(
            vehicle.getId().toString(),
            WagonSimConstants.TRAIN_MAX_LENGTH,
            (Double)
                trainTypes.getAttribute(
                    locomotive.type.toString(), WagonSimConstants.TRAIN_MAX_LENGTH));
      } else if (transitRouteStops.size() == 1) {
        System.out.println(
            "locomotive id="
                + locomotive.id
                + ": only one station given. Therefore, no transitLine created.");
      } else {
        System.out.println(
            "locomotive id="
                + locomotive.id
                + ": no station is given. Therefore, no transitLine created.");
      }
    }
  }