package org.opentripplanner.profile;
import com.beust.jcommander.internal.Sets;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import org.opentripplanner.routing.core.TraverseMode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
// Jackson will serialize fields with getters, or @JsonProperty annotations.
public class ProfileResponse {
private static final Logger LOG = LoggerFactory.getLogger(ProfileResponse.class);
public Set<Option> options = Sets.newHashSet();
/**
* The constructed response will include all the options that do not use transit,
* as well as the top N options that do use transit for each access mode.
*
* @param allOptions a collection of Options with a mix of all access and egress modes, using transit or not.
* @param orderBy specifies how the top N transit options will be chosen.
* @param limit the maximum number of transit options to include in the response per access mode.
* zero or negative means no limit.
*/
public ProfileResponse (Collection<Option> allOptions, Option.SortOrder orderBy, int limit) {
List<Option> transitOptions = Lists.newArrayList();
// Always return all non-transit options
for (Option option : allOptions) {
if (option.transit == null || option.transit.isEmpty()) options.add(option);
else transitOptions.add(option);
}
// Order all transit options by the specified method
Comparator<Option> c;
switch (orderBy) {
case MAX:
c = new Option.MaxComparator();
break;
case AVG:
c = new Option.AvgComparator();
break;
case MIN:
default:
c = new Option.MinComparator();
}
Collections.sort(transitOptions, c);
// Group options by access mode, retaining ordering.
// ListMultimap can hold duplicate key-value pairs and maintains the insertion ordering of values for a given key.
// TODO update this to also use the egress mode in the key, and to consider the qualifiers on the modes
ListMultimap<TraverseMode, Option> transitOptionsByAccessMode = ArrayListMultimap.create();
for (Option option : transitOptions) {
for (StreetSegment segment : option.access) {
transitOptionsByAccessMode.put(segment.mode.mode, option);
}
}
// Retain the top N transit options for each access mode. Duplicates may be present, but options is a Set.
for (Collection<Option> singleModeOptions : transitOptionsByAccessMode.asMap().values()) {
int n = 0;
for (Option option : singleModeOptions) {
options.add(option);
if (limit > 0 && ++n >= limit) break;
}
}
for (Option option : this.options) {
LOG.info("{} {}", option.stats, option.summary);
}
}
}