class ForwardingAnalysisImpl implements ForwardingAnalysis, Serializable {

  @VisibleForTesting
  static Map<String, Map<String, Map<Edge, Set<AbstractRoute>>>> computeRoutesWithNextHopIpArpTrue(
      Map<String, Map<String, Map<AbstractRoute, Map<String, Map<Ip, Set<AbstractRoute>>>>>>
          nextHopInterfacesByNodeVrf,
      Topology topology,
      Map<String, Map<String, IpSpace>> arpReplies,
      Map<String, Map<String, Map<String, Set<AbstractRoute>>>> routesWithNextHop) {
    Span span =
        GlobalTracer.get()
            .buildSpan("ForwardingAnalysisImpl.computeRoutesWithNextHopIpArpTrue")
            .start();
    try (Scope scope = GlobalTracer.get().scopeManager().activate(span)) {
      assert scope != null; // avoid unused warning
      return toImmutableMap(
          routesWithNextHop,
          Entry::getKey, // node
          nodeEntry ->
              toImmutableMap(
                  nodeEntry.getValue(),
                  Entry::getKey, // vrf
                  vrfEntry -> {
                    String hostname = nodeEntry.getKey();
                    String vrf = vrfEntry.getKey();
                    Map<AbstractRoute, Map<String, Map<Ip, Set<AbstractRoute>>>> nextHopInterfaces =
                        nextHopInterfacesByNodeVrf.get(hostname).get(vrf);
                    return vrfEntry.getValue().entrySet().stream()
                        .flatMap(
                            ifaceEntry -> {
                              String outInterface = ifaceEntry.getKey();
                              Set<AbstractRoute> candidateRoutes = ifaceEntry.getValue();
                              NodeInterfacePair out = NodeInterfacePair.of(hostname, outInterface);
                              Set<NodeInterfacePair> receivers = topology.getNeighbors(out);
                              return receivers.stream()
                                  .map(
                                      receiver -> {
                                        String recvNode = receiver.getHostname();
                                        String recvInterface = receiver.getInterface();
                                        IpSpace recvReplies =
                                            arpReplies.get(recvNode).get(recvInterface);
                                        Edge edge = new Edge(out, receiver);
                                        Set<AbstractRoute> routes =
                                            candidateRoutes.stream()
                                                .filter(
                                                    route ->
                                                        nextHopInterfaces.get(route)
                                                            .get(outInterface)
                                                            .keySet() // nextHopIps
                                                            .stream()
                                                            .filter(
                                                                ip ->
                                                                    !Route.UNSET_ROUTE_NEXT_HOP_IP
                                                                        .equals(ip))
                                                            .anyMatch(
                                                                nextHopIp ->
                                                                    recvReplies.containsIp(
                                                                        nextHopIp,
                                                                        ImmutableMap.of())))
                                                .collect(ImmutableSet.toImmutableSet());
                                        return routes.isEmpty()
                                            ? null
                                            : Maps.immutableEntry(edge, routes);
                                      })
                                  .filter(Objects::nonNull);
                            })
                        .collect(ImmutableMap.toImmutableMap(Entry::getKey, Entry::getValue));
                  }));
    } finally {
      span.finish();
    }
  }

  public  ForwardingAnalysisImpl(
      Map<String, Configuration> configurations,
      Map<String, Map<String, Fib>> fibs,
      Topology topology,
      Map<Location, LocationInfo> locationInfo);

}