content: /* amodeus - Copyright (c) 2018, ETH Zurich, Institute for Dynamic Systems and Control */
  package amodeus.amodeus.dispatcher.core;
  
  import java.util.Collection;
  import java.util.HashMap;
  import java.util.Map;
  
  import org.matsim.amodeus.components.AmodeusRouter;
  import org.matsim.amodeus.config.AmodeusModeConfig;
  import org.matsim.api.core.v01.network.Network;
  import org.matsim.contrib.drt.optimizer.rebalancing.RebalancingStrategy;
  import org.matsim.contrib.dvrp.passenger.PassengerRequest;
  import org.matsim.core.api.experimental.events.EventsManager;
  import org.matsim.core.config.Config;
  import org.matsim.core.network.NetworkUtils;
  import org.matsim.core.router.util.TravelTime;
  
  import amodeus.amodeus.cycling.CyclePreventer;
  import amodeus.amodeus.dispatcher.util.DrivebyRequestStopper;
  import amodeus.amodeus.dispatcher.util.TensorLocation;
  import amodeus.amodeus.dispatcher.util.TreeMaintainer;
  import amodeus.amodeus.dispatcher.util.WeberMaintainer;
  import amodeus.amodeus.net.MatsimAmodeusDatabase;
  import amodeus.amodeus.util.io.MultiFileTools;
  
  /** Arsie, Alessandro, Ketan Savla, and Emilio Frazzoli. "Efficient routing algorithms for multiple
   * vehicles with no explicit communications." IEEE Transactions on Automatic Control 54.10 (2009): 2302-2317. */
  public abstract class AbstractNoExplicitCommunication extends RebalancingDispatcher {
      private final int dispatchPeriod;
      private final Network network;
      private final CyclePreventer cyclePreventer = new CyclePreventer();
      protected final Map<RoboTaxi, WeberMaintainer> weberMaintainers = new HashMap<>();
      protected final TreeMaintainer<PassengerRequest> requestMaintainer;
  
      protected AbstractNoExplicitCommunication(Network network, Config config, //
              AmodeusModeConfig operatorConfig, TravelTime travelTime, //
              AmodeusRouter router, EventsManager eventsManager, MatsimAmodeusDatabase db, RebalancingStrategy rebalancingStrategy) {
          super(config, operatorConfig, travelTime, router, eventsManager, db, rebalancingStrategy, RoboTaxiUsageType.SINGLEUSED);
          DispatcherConfigWrapper dispatcherConfig = DispatcherConfigWrapper.wrap(operatorConfig.getDispatcherConfig());
          dispatchPeriod = dispatcherConfig.getDispatchPeriod(30);
          this.network = network;
          double[] networkBounds = NetworkUtils.getBoundingBox(network.getNodes().values());
          requestMaintainer = new TreeMaintainer<>(networkBounds, TensorLocation::of);
      }
  
      @Override
      protected void redispatch(double now) {
          /** ensure that {@link RoboTaxi}s are not driving cycles (due to Euclidean distance measure in algorithm) */
          cyclePreventer.update(getRoboTaxis(), this::setRoboTaxiRebalance);
  
          /** get set D(t), the open requests */
          Collection<PassengerRequest> d = getPassengerRequests();
          d.forEach(requestMaintainer::add);
          
          /** as soon as {@link RoboTaxi}s appear, initialize with present location */
          if (weberMaintainers.isEmpty())
              getRoboTaxis().forEach(rt -> weberMaintainers.put(rt, new WeberMaintainer(rt.getDivertableLocation(), network)));
  
          /** if a {@link RoboTaxi} is on the same {@link Link} as a {@link AVRquest}, a pickup
           * is executed */
          Map<RoboTaxi, PassengerRequest> matched = DrivebyRequestStopper.stopDrivingBy(DispatcherUtils.getPassengerRequestsAtLinks(getPassengerRequests()), //
                  getDivertableRoboTaxis(), (rt, avr) -> setRoboTaxiPickup(rt, avr, Double.NaN, Double.NaN));
          matched.values().forEach(requestMaintainer::remove);
  
          /** add all successful pickups to the {@link WeberMaintainer}s */
          matched.forEach((rt, avr) -> weberMaintainers.get(rt).update(avr));
  
          final long round_now = Math.round(now);
          if (round_now % dispatchPeriod == 0) {
              cyclePreventer.printStatus();
  
              redispatchIteration();
          }
  
          /** Save Weber maintainers */
          if (round_now == 107500) // TODO @clruch check hardcoded
              try {
                  WeberMaintainer.saveWeberLocations(weberMaintainers, MultiFileTools.getDefaultWorkingDirectory());
              } catch (Exception ex) {
                  System.err.println("not able to save weber maintainers");
                  ex.printStackTrace();
              }
      }
  
      protected abstract void redispatchIteration();
  }
  