content: /* amodeus - Copyright (c) 2018, ETH Zurich, Institute for Dynamic Systems and Control */
  package amodeus.amodeus.prep;
  
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Random;
  
  import org.matsim.amodeus.config.AmodeusModeConfig;
  import org.matsim.api.core.v01.population.Person;
  import org.matsim.api.core.v01.population.Population;
  
  import amodeus.amodeus.util.math.GlobalAssert;
  
  public final class TheRequestApocalypse {
      /** the seed is deliberately public */
      public static final long DEFAULT_SEED = 7582456789L;
  
      public static TheRequestApocalypse reducesThe(Population population) {
          return new TheRequestApocalypse(population);
      }
  
      // ---
      private final Population population;
  
      private TheRequestApocalypse(Population population) {
          this.population = population;
      }
  
      public TheRequestApocalypse toNoMoreThan(int maxRequests) {
          return toNoMoreThan(maxRequests, DEFAULT_SEED);
      }
  
      public TheRequestApocalypse toNoMoreThan(int maxRequests, long seed) {
          final long legCount = LegCount.of(population, AmodeusModeConfig.DEFAULT_MODE);
          GlobalAssert.that(maxRequests <= legCount);
          if (legCount == maxRequests)
              return this;
  
          /** shuffle list of {@link Person}s */
          List<Person> list = new ArrayList<>(population.getPersons().values());
          Collections.shuffle(list, new Random(seed));
          Iterator<Person> iterator = list.iterator();
  
          // skip all persons that should completely remain in the population
          Person person = iterator.next();
          int totReq = 0;
          long req = LegCount.of(person, AmodeusModeConfig.DEFAULT_MODE);
          while (totReq + req <= maxRequests) {
              totReq += req;
              person = iterator.next();
              req = LegCount.of(person, AmodeusModeConfig.DEFAULT_MODE);
          }
  
          // create new person if needed to fill requests
          int split = maxRequests - totReq;
          if (split != 0) {
              Person splitPerson = SplitUp.of(population, person, split, AmodeusModeConfig.DEFAULT_MODE);
              req = LegCount.of(splitPerson, AmodeusModeConfig.DEFAULT_MODE);
              totReq += req;
              GlobalAssert.that(totReq == maxRequests);
              population.addPerson(splitPerson);
          }
  
          // remove all remaining persons
          iterator.forEachRemaining(p -> population.removePerson(p.getId()));
          population.removePerson(person.getId());
          GlobalAssert.that(LegCount.of(population, AmodeusModeConfig.DEFAULT_MODE) == maxRequests);
          return this;
      }
  
      public final void requests() {
          System.out.println("Population size: " + population.getPersons().values().size());
      }
  }
  