class IpsecUtil {

  public static IpsecTopology retainCompatibleTunnelEdges(
      IpsecTopology ipsecTopology, Map<String, Configuration> configurations) {
    NetworkConfigurations networkConfigurations = NetworkConfigurations.of(configurations);

    MutableValueGraph<IpsecPeerConfigId, IpsecSession> prunedIpsecTopology =
        ValueGraphBuilder.directed().allowsSelfLoops(false).build();
    ValueGraph<IpsecPeerConfigId, IpsecSession> ipsecGraph = ipsecTopology.getGraph();
    for (IpsecPeerConfigId endPointU : ipsecGraph.nodes()) {
      IpsecPeerConfig ipsecPeerU = networkConfigurations.getIpsecPeerConfig(endPointU);
      // not considering endpoints not based on Tunnel interfaces
      if (ipsecPeerU == null || ipsecPeerU.getTunnelInterface() == null) {
        continue;
      }

      for (IpsecPeerConfigId endPointV : ipsecGraph.adjacentNodes(endPointU)) {
        IpsecPeerConfig ipsecPeerV = networkConfigurations.getIpsecPeerConfig(endPointV);

        // not considering endpoints not based on Tunnel interfaces
        if (ipsecPeerV == null || ipsecPeerV.getTunnelInterface() == null) {
          continue;
        }

        // checking IPsec session and adding edge
        ipsecGraph
            .edgeValue(endPointU, endPointV)
            .filter(ipsecSession -> ipsecSession.getNegotiatedIpsecP2Proposal() != null)
            .ifPresent(
                ipsecSession ->
                    prunedIpsecTopology.putEdgeValue(endPointU, endPointV, ipsecSession));
      }
    }

    MutableValueGraph<IpsecPeerConfigId, IpsecSession> bidirCompatibleEdges =
        ValueGraphBuilder.directed().allowsSelfLoops(false).build();

    for (EndpointPair<IpsecPeerConfigId> endpointPair : prunedIpsecTopology.edges()) {
      // if reverse edge exists
      IpsecPeerConfigId nodeU = endpointPair.nodeU();
      IpsecPeerConfigId nodeV = endpointPair.nodeV();
      if (prunedIpsecTopology.hasEdgeConnecting(nodeV, nodeU)) {
        bidirCompatibleEdges.putEdgeValue(
            nodeU, nodeV, prunedIpsecTopology.edgeValue(nodeU, nodeV).get());
      }
    }

    return new IpsecTopology(bidirCompatibleEdges);
  }

}