private void updateInsertionData(
     final TreeSet<VersionedInsertionData>[] priorityQueues,
     final Collection<VehicleRoute> routes,
     List<Job> unassignedJobList,
     final int updateRound) {
   List<Callable<Boolean>> tasks = new ArrayList<Callable<Boolean>>();
   for (final Job unassignedJob : unassignedJobList) {
     if (priorityQueues[unassignedJob.getIndex()] == null) {
       priorityQueues[unassignedJob.getIndex()] =
           new TreeSet<VersionedInsertionData>(InsertionDataUpdater.getComparator());
     }
     final TreeSet<VersionedInsertionData> priorityQueue =
         priorityQueues[unassignedJob.getIndex()];
     tasks.add(
         new Callable<Boolean>() {
           @Override
           public Boolean call() throws Exception {
             return InsertionDataUpdater.update(
                 switchAllowed,
                 initialVehicleIds,
                 fleetManager,
                 insertionCostsCalculator,
                 priorityQueue,
                 updateRound,
                 unassignedJob,
                 routes);
           }
         });
   }
   try {
     List<Future<Boolean>> futures = executor.invokeAll(tasks);
   } catch (InterruptedException e) {
     Thread.currentThread().interrupt();
     throw new RuntimeException(e);
   }
 }
  /**
   * Runs insertion.
   *
   * <p>
   *
   * <p>Before inserting a job, all unassigned jobs are scored according to its best- and
   * secondBest-insertion plus additional scoring variables.
   *
   * @throws java.lang.RuntimeException if smth went wrong with thread execution
   */
  @Override
  public Collection<Job> insertUnassignedJobs(
      Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
    List<Job> badJobs = new ArrayList<Job>(unassignedJobs.size());

    Iterator<Job> jobIterator = unassignedJobs.iterator();
    while (jobIterator.hasNext()) {
      Job job = jobIterator.next();
      if (job instanceof Break) {
        VehicleRoute route = InsertionDataUpdater.findRoute(routes, job);
        if (route == null) {
          badJobs.add(job);
        } else {
          InsertionData iData =
              insertionCostsCalculator.getInsertionData(
                  route,
                  job,
                  NO_NEW_VEHICLE_YET,
                  NO_NEW_DEPARTURE_TIME_YET,
                  NO_NEW_DRIVER_YET,
                  Double.MAX_VALUE);
          if (iData instanceof InsertionData.NoInsertionFound) {
            badJobs.add(job);
          } else {
            insertJob(job, iData, route);
          }
        }
        jobIterator.remove();
      }
    }

    List<Job> jobs = new ArrayList<Job>(unassignedJobs);
    TreeSet<VersionedInsertionData>[] priorityQueues =
        new TreeSet[vrp.getJobs().values().size() + 2];
    VehicleRoute lastModified = null;
    boolean firstRun = true;
    int updateRound = 0;
    Map<VehicleRoute, Integer> updates = new HashMap<VehicleRoute, Integer>();
    while (!jobs.isEmpty()) {
      List<Job> unassignedJobList = new ArrayList<Job>(jobs);
      List<Job> badJobList = new ArrayList<Job>();
      if (!firstRun && lastModified == null)
        throw new IllegalStateException("ho. this must not be.");
      if (firstRun) {
        firstRun = false;
        updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound);
        for (VehicleRoute r : routes) updates.put(r, updateRound);
      } else {
        updateInsertionData(
            priorityQueues, Arrays.asList(lastModified), unassignedJobList, updateRound);
        updates.put(lastModified, updateRound);
      }
      updateRound++;
      ScoredJob bestScoredJob =
          InsertionDataUpdater.getBest(
              switchAllowed,
              initialVehicleIds,
              fleetManager,
              insertionCostsCalculator,
              scoringFunction,
              priorityQueues,
              updates,
              unassignedJobList,
              badJobList);
      if (bestScoredJob != null) {
        if (bestScoredJob.isNewRoute()) {
          routes.add(bestScoredJob.getRoute());
        }
        insertJob(
            bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
        jobs.remove(bestScoredJob.getJob());
        lastModified = bestScoredJob.getRoute();
      } else lastModified = null;
      for (Job bad : badJobList) {
        jobs.remove(bad);
        badJobs.add(bad);
      }
    }
    return badJobs;
  }