protected Link getNearestFreeRank(Id linkId) {
    Link nearestLink = null;
    if (this.rankHandler.getRanks().get(this.nearestRanks.get(linkId).getId()).hasCapacity()) {
      nearestLink = this.nearestRanks.get(linkId);
    } else {
      Link positionLink = optimConfig.context.getScenario().getNetwork().getLinks().get(linkId);

      double bestTravelCost = Double.MAX_VALUE;
      for (Id cid : rankHandler.getRanks().keySet()) {

        Link currentLink = optimConfig.context.getScenario().getNetwork().getLinks().get(cid);
        double currentCost = DistanceUtils.calculateSquaredDistance(positionLink, currentLink);
        if ((currentCost < bestTravelCost)
            && (this.rankHandler
                .getRanks()
                .get(this.nearestRanks.get(linkId).getId())
                .hasCapacity())) {
          bestTravelCost = currentCost;
          nearestLink = currentLink;
        }
      }
    }
    if (nearestLink == null) nearestLink = this.nearestRanks.get(linkId);

    // assumption: all ranks full --> drive to next rank and wait until something becomes available

    return nearestLink;
  }
  private Link findNearestRank(Id positionLinkId) {
    Link positionLink =
        optimConfig.context.getScenario().getNetwork().getLinks().get(positionLinkId);
    Link nearestRankLink = null;
    double bestTravelCost = Double.MAX_VALUE;
    for (Id cid : rankHandler.getRanks().keySet()) {

      Link currentLink = optimConfig.context.getScenario().getNetwork().getLinks().get(cid);
      double currentCost = DistanceUtils.calculateSquaredDistance(positionLink, currentLink);
      if (currentCost < bestTravelCost) {
        bestTravelCost = currentCost;
        nearestRankLink = currentLink;
      }
    }
    return nearestRankLink;
  }