public void removeLink(Link link) {
    boolean flag1 = false, flag2 = false;

    flag1 = removeLinkFromStructure(directLinks, link);
    flag2 = removeLinkFromStructure(tunnelLinks, link);

    linksUpdated = true;
    dtLinksUpdated = flag1 || flag2;

    removeLinkFromStructure(portBroadcastDomainLinks, link);
    removeLinkFromStructure(switchPortLinks, link);

    NodePortTuple srcNpt = new NodePortTuple(link.getSrc(), link.getSrcPort());
    NodePortTuple dstNpt = new NodePortTuple(link.getDst(), link.getDstPort());

    // Remove switch ports if there are no links through those switch ports
    if (switchPortLinks.get(srcNpt) == null) {
      if (switchPorts.get(srcNpt.getNodeId()) != null)
        switchPorts.get(srcNpt.getNodeId()).remove(srcNpt.getPortId());
    }
    if (switchPortLinks.get(dstNpt) == null) {
      if (switchPorts.get(dstNpt.getNodeId()) != null)
        switchPorts.get(dstNpt.getNodeId()).remove(dstNpt.getPortId());
    }

    // Remove the node if no ports are present
    if (switchPorts.get(srcNpt.getNodeId()) != null
        && switchPorts.get(srcNpt.getNodeId()).isEmpty()) {
      switchPorts.remove(srcNpt.getNodeId());
    }
    if (switchPorts.get(dstNpt.getNodeId()) != null
        && switchPorts.get(dstNpt.getNodeId()).isEmpty()) {
      switchPorts.remove(dstNpt.getNodeId());
    }
  }
  public void bellmanFord(
      HashMap<String, HashMap<String, Integer>> adjMatrix,
      Host src,
      HashMap<String, String> predecessors,
      HashMap<String, Integer> fwdingToSrcPorts,
      HashMap<String, Integer> distances) {
    if (src.getSwitch() == null) return;
    for (Host host : this.getHosts()) {
      distances.put(host.getName(), this.INFINITY);
      if (host.getSwitch() != null) {
        // predecessors.put(host.getName(), host.getSwitch().getStringId());
        // fwdingToSrcPorts.put(host.getName(), host.getPort());
      }
    }
    for (IOFSwitch sw : this.getSwitches().values()) {
      String swIdName = String.valueOf(sw.getId());
      distances.put(swIdName, this.INFINITY);
    }
    distances.put(src.getName(), 0);
    predecessors.put(src.getName(), String.valueOf(src.getSwitch().getId()));
    // fwdingToSrcPorts.put(src.getName(), src.getPort());

    Set<String> allDeviceNames = this.adjMatrix.keySet();
    if (debug_level < 1) {
      System.out.println("BF : adjMetrix keyset size : " + allDeviceNames.size());
      System.out.println("Num Links : " + this.getLinks().size());
    }
    for (int i = 0; i < allDeviceNames.size(); i++) {
      // for each u, v
      for (String device : allDeviceNames) {
        for (Map.Entry<String, Integer> adjEntry : adjMatrix.get(device).entrySet()) {
          // for each v adjacent to u
          if (adjEntry.getValue() == 1) // 1 only if it is an edge
          {
            if ((distances.get(device) + 1) < distances.get(adjEntry.getKey())) {
              distances.put(adjEntry.getKey(), (distances.get(device) + 1));
              predecessors.put(adjEntry.getKey(), device);

              // fwding ports need to be populated only if it is a switch
              // case 1 : this switch's predecessor is the src
              if (device.equals(src.getName())) {
                fwdingToSrcPorts.put(adjEntry.getKey(), src.getPort());
              }
              // case 2 : this switch's predecessor is another switch
              else {
                for (Link link : this.getLinks()) {
                  if (String.valueOf(link.getDst()).equals(device)) {
                    if (String.valueOf(link.getSrc()).equals(adjEntry.getKey())) {
                      fwdingToSrcPorts.put(adjEntry.getKey(), link.getSrcPort());
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    if (debug_level < 2) displayBellmanFord(src, predecessors, fwdingToSrcPorts, distances);
  }
  public HashMap<String, HashMap<String, Integer>> createAdjMatrix() {
    HashMap<String, HashMap<String, Integer>> adjMatrix =
        new HashMap<String, HashMap<String, Integer>>();

    List<String> allDeviceNames = new ArrayList<String>();

    for (Host host : this.getHosts()) {
      allDeviceNames.add(host.getName());
    }
    for (IOFSwitch sw : this.getSwitches().values()) {
      allDeviceNames.add(String.valueOf(sw.getId()));
    }

    // use list of both switch names and host names to create table
    for (String hostName : allDeviceNames) {
      adjMatrix.put(hostName, new HashMap<String, Integer>());
    }

    for (HashMap<String, Integer> internalMap : adjMatrix.values()) {
      for (String hostName : allDeviceNames) {
        internalMap.put(hostName, 0);
      }
    }

    // Insert real values of 1s

    for (Host host : this.getHosts()) {
      if (host.getSwitch() != null) {
        String switchName = String.valueOf(host.getSwitch().getId());
        Map<String, Integer> internalMap;

        internalMap = adjMatrix.get(host.getName());
        internalMap.put(switchName, 1);

        internalMap = adjMatrix.get(switchName);
        internalMap.put(host.getName(), 1);
      }
    }

    for (Link link : this.getLinks()) {
      if (debug_level < 2)
        System.out.println("Link src: " + link.getSrc() + " dest: " + link.getDst());
      String switchId1 = String.valueOf(link.getSrc());
      String switchId2 = String.valueOf(link.getDst());
      if (adjMatrix.get(switchId1) != null) {
        adjMatrix.get(switchId1).put(switchId2, 1);
      } else {
        System.out.println("Looks like s" + switchId1 + " is no longer up");
      }
      if (adjMatrix.get(switchId2) != null) adjMatrix.get(switchId2).put(switchId1, 1);
      else System.out.println("Looks like s" + switchId2 + " is no longer up");
    }
    return adjMatrix;
  }
  /**
   * Delete the given link from the data strucure. Returns true if the link was deleted.
   *
   * @param s
   * @param l
   * @return
   */
  private boolean removeLinkFromStructure(Map<NodePortTuple, Set<Link>> s, Link l) {

    boolean result1 = false, result2 = false;
    NodePortTuple n1 = new NodePortTuple(l.getSrc(), l.getSrcPort());
    NodePortTuple n2 = new NodePortTuple(l.getDst(), l.getDstPort());

    if (s.get(n1) != null) {
      result1 = s.get(n1).remove(l);
      if (s.get(n1).isEmpty()) s.remove(n1);
    }
    if (s.get(n2) != null) {
      result2 = s.get(n2).remove(l);
      if (s.get(n2).isEmpty()) s.remove(n2);
    }
    return result1 || result2;
  }
  /**
   * Add the given link to the data structure. Returns true if a link was added.
   *
   * @param s
   * @param l
   * @return
   */
  private boolean addLinkToStructure(Map<NodePortTuple, Set<Link>> s, Link l) {
    boolean result1 = false, result2 = false;

    NodePortTuple n1 = new NodePortTuple(l.getSrc(), l.getSrcPort());
    NodePortTuple n2 = new NodePortTuple(l.getDst(), l.getDstPort());

    if (s.get(n1) == null) {
      s.put(n1, new HashSet<Link>());
    }
    if (s.get(n2) == null) {
      s.put(n2, new HashSet<Link>());
    }
    result1 = s.get(n1).add(l);
    result2 = s.get(n2).add(l);

    return (result1 || result2);
  }
  /** Calculates the node ports that are used by the overall spanning tree. */
  protected void calculateBroadcastNodePorts() {
    calculateBroadcastTree();

    Set<NodePortTuple> nptSet = new HashSet<NodePortTuple>();
    if (broadcastTree == null) return;
    Map<Long, Link> links = broadcastTree.getLinks();
    if (links == null) return;
    for (long nodeId : links.keySet()) {
      Link l = links.get(nodeId);
      if (l == null) continue;
      NodePortTuple npt1 = new NodePortTuple(l.getSrc(), l.getSrcPort());
      NodePortTuple npt2 = new NodePortTuple(l.getDst(), l.getDstPort());
      nptSet.add(npt1);
      nptSet.add(npt2);
    }
    topologyBroadcastNodePorts.addAll(nptSet);
  }