package org.batfish.question.loop;

import com.google.common.base.Functions;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import java.util.List;
import java.util.Set;
import java.util.SortedMap;
import java.util.stream.Collectors;
import org.batfish.common.Answerer;
import org.batfish.common.plugin.IBatfish;
import org.batfish.datamodel.Flow;
import org.batfish.datamodel.Ip;
import org.batfish.datamodel.answers.AnswerElement;
import org.batfish.datamodel.flow.Trace;
import org.batfish.datamodel.questions.Question;
import org.batfish.datamodel.table.TableAnswerElement;
import org.batfish.question.traceroute.TracerouteAnswerer;

/** {@link Answerer} for {@link DetectLoopsQuestion}. */
public final class DetectLoopsAnswerer extends Answerer {
  public DetectLoopsAnswerer(Question question, IBatfish batfish) {
    super(question, batfish);
  }

  @Override
  public AnswerElement answer() {
    DetectLoopsQuestion question = (DetectLoopsQuestion) _question;
    Set<Flow> flows = _batfish.bddLoopDetection();

    /*
     * There can be many flows exercising the same loop, so let's pick one per dstIp.
     */
    Multimap<Ip, Flow> flowsPerDst =
        flows.stream()
            .collect(
                Multimaps.toMultimap(Flow::getDstIp, Functions.identity(), HashMultimap::create));

    flows =
        flowsPerDst.asMap().values().stream()
            .flatMap(flowsWithSameDst -> flowsWithSameDst.stream().limit(1))
            .collect(Collectors.toSet());

    SortedMap<Flow, List<Trace>> flowTraces = _batfish.buildFlows(flows, false);
    TableAnswerElement tableAnswer = new TableAnswerElement(TracerouteAnswerer.metadata(false));
    TracerouteAnswerer.flowTracesToRows(flowTraces, question.getMaxTraces())
        .forEach(tableAnswer::addRow);
    return tableAnswer;
  }
}

@@ -58,69 +58,34 @@
 mon.
-base.Functions;%0Aimport com.google.common.collect.HashMultimap
+collect.ImmutableSortedSet
 ;%0Aim
@@ -115,24 +115,24 @@
 collect.
-Multimap
+Ordering
 ;%0Aimport
@@ -136,43 +136,22 @@
 ort 
-com.google.common.collect.Multimaps
+java.util.List
 ;%0Aim
@@ -157,36 +157,40 @@
 mport java.util.
-List
+Optional
 ;%0Aimport java.ut
@@ -379,41 +379,8 @@
 ow;%0A
-import org.batfish.datamodel.Ip;%0A
 impo
@@ -1125,38 +1125,13 @@
     
-Multimap%3CIp, Flow%3E flowsPerDst
+flows
  =%0A 
@@ -1177,282 +1177,295 @@
 ect(
-%0A                Multimaps.toMultimap(Flow::getDstIp, Functions.identity(), HashMultimap::create));%0A%0A    flows =%0A        flowsPerDst.asMap().values().stream()%0A            .flatMap(flowsWithSameDst -%3E flowsWithSameDst.stream().limit(1))%0A            .collect(Collectors.toSet(
+Collectors.groupingBy(Flow::getDstIp, Collectors.minBy(Ordering.natural())))%0A            .values()%0A            .stream()%0A            .map(Optional::get) // safe: the min here cannot be empty by construction.%0A            .collect(ImmutableSortedSet.toImmutableSortedSet(Ordering.natural()
 ));%0A

add determinism using flow min (#3454)