private void displayBellmanFord(
     Host src,
     HashMap<String, String> predecessors,
     HashMap<String, Integer> fwdingToSrcPorts,
     HashMap<String, Integer> distances) {
   try {
     System.out.println(
         "\nBELLMAN FORD : src : "
             + src.getName()
             + " "
             + IPv4.fromIPv4Address(src.getIPv4Address()));
     System.out.print("Predecessors : ");
     for (Entry<String, String> predMapEntry : predecessors.entrySet()) {
       System.out.print("(" + predMapEntry.getKey() + "," + predMapEntry.getValue() + ") ");
     }
     System.out.println();
     System.out.print("FwdPorts : ");
     for (Entry<String, Integer> mapEntry : fwdingToSrcPorts.entrySet()) {
       System.out.print("(" + mapEntry.getKey() + "," + mapEntry.getValue() + ") ");
     }
     System.out.println();
     System.out.print("Distances : ");
     for (Entry<String, Integer> mapEntry : distances.entrySet()) {
       System.out.print("(" + mapEntry.getKey() + "," + mapEntry.getValue() + ") ");
     }
     System.out.println();
   } catch (Exception e) {
     e.printStackTrace();
   }
 }
  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);
  }
  /**
   * Event handler called when a switch leaves the network.
   *
   * @param DPID for the switch
   */
  @Override
  public void switchRemoved(long switchId) {
    IOFSwitch sw = this.floodlightProv.getSwitch(switchId);
    log.info(String.format("Switch s%d removed", switchId));

    /** ****************************************************************** */
    /* TODO: Update routing: change routing rules for all hosts */
    // check
    for (Host host : this.getHosts()) {
      OFMatch matchCriteria = new OFMatch();

      matchCriteria.setDataLayerType(OFMatch.ETH_TYPE_IPV4);
      matchCriteria.setNetworkDestination(host.getIPv4Address());

      for (IOFSwitch currSw : this.getSwitches().values()) {
        SwitchCommands.removeRules(currSw, this.table, matchCriteria);
      }
      updateAllRouting();
    }
    /** ****************************************************************** */
  }
  /**
   * Event handler called when a host joins the network.
   *
   * @param device information about the host
   */
  @Override
  public void deviceAdded(IDevice device) {
    Host host = new Host(device, this.floodlightProv);
    // We only care about a new host if we know its IP
    if (host.getIPv4Address() != null) {
      log.info(String.format("Host %s added", host.getName()));
      this.knownHosts.put(device, host);

      /** ************************************************************** */
      /* TODO: Update routing: add rules to route to new host */
      if (host.isAttachedToSwitch() != false) {
        // TODO : adbhat : install rules to route traffic to this host

        updateAllRouting();

        // else nothing

        /** ************************************************************** */
      }
    }
  }
  /**
   * Event handler called when a host moves within the network.
   *
   * @param device information about the host
   */
  @Override
  public void deviceMoved(IDevice device) {
    Host host = this.knownHosts.get(device);
    if (null == host) {
      host = new Host(device, this.floodlightProv);
      this.knownHosts.put(device, host);
    }

    if (!host.isAttachedToSwitch()) {
      this.deviceRemoved(device);
      return;
    }
    log.info(
        String.format(
            "Host %s moved to s%d:%d", host.getName(), host.getSwitch().getId(), host.getPort()));

    /** ****************************************************************** */
    /* TODO: Update routing: change rules to route to host */
    updateAllRouting();

    /** ****************************************************************** */
  }
  /**
   * Event handler called when a host is no longer attached to a switch.
   *
   * @param device information about the host
   */
  @Override
  public void deviceRemoved(IDevice device) {
    Host host = this.knownHosts.get(device);
    if (null == host) {
      return;
    }
    this.knownHosts.remove(host);

    log.info(String.format("Host %s is no longer attached to a switch", host.getName()));

    /** ****************************************************************** */
    /* TODO: Update routing: remove rules to route to host */

    OFMatch matchCriteria = new OFMatch();
    matchCriteria.setDataLayerType(OFMatch.ETH_TYPE_IPV4);
    matchCriteria.setNetworkDestination(host.getIPv4Address());

    for (IOFSwitch currSw : this.getSwitches().values()) {
      SwitchCommands.removeRules(currSw, this.table, matchCriteria);
    }
    /** ****************************************************************** */
  }
  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;
  }
  private void installL3FwdRule(IOFSwitch currSw, Host host, int opPortTowardsSrc) {
    if (debug_level < 2)
      System.out.println(
          "L3 Install Rule :  sw - "
              + String.valueOf(currSw.getId())
              + " port "
              + opPortTowardsSrc);
    OFMatch matchCriteria = new OFMatch();
    matchCriteria.setDataLayerType(OFMatch.ETH_TYPE_IPV4);
    matchCriteria.setNetworkDestination(host.getIPv4Address());

    List<OFAction> actionOps = new LinkedList<OFAction>();
    OFActionOutput actOp = new OFActionOutput(opPortTowardsSrc);
    actionOps.add(0, actOp);
    OFInstructionApplyActions applyActions = new OFInstructionApplyActions(actionOps);
    List<OFInstruction> instructionList = new ArrayList<OFInstruction>();
    instructionList.add(applyActions);

    SwitchCommands.removeRules(currSw, this.table, matchCriteria);
    if (SwitchCommands.installRule(
            currSw, this.table, SwitchCommands.DEFAULT_PRIORITY, matchCriteria, instructionList)
        == false) {
      System.out.println(
          "L3 Rule not installed: sw "
              + String.valueOf(currSw.getId())
              + " port: "
              + opPortTowardsSrc
              + " table: "
              + this.table);
    } else {
      if (debug_level < 2)
        System.out.println(
            "L3 Rule installed : sw "
                + String.valueOf(currSw.getId())
                + " port: "
                + opPortTowardsSrc
                + " table: "
                + this.table);
    }
  }
  public void bellmanFordOld(
      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(), String.valueOf(host.getSwitch().getId()));
        fwdingToSrcPorts.put(host.getName(), host.getPort());
      }
    }
    for (long swId : this.getSwitches().keySet()) {
      String swIdName = String.valueOf(swId);
      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();

    for (int i = 0; i < allDeviceNames.size() - 1; i++) {
      // for each u
      // for (Link link : this.getLinks())
      // {
      // System.out.println("Link Src: " + link.getSrc() + "\t" + link.getDst());
      // if(distances.get(String.valueOf(link.getSrc())) + 1 <
      // distances.get(String.valueOf(link.getDst())))
      // {
      // distances.put(String.valueOf(link.getDst()), distances.get(String.valueOf(link.getSrc())) +
      // 1);
      // predecessors.put(String.valueOf(link.getDst()), String.valueOf(link.getSrc()));
      // fwdingToSrcPorts.put(String.valueOf(link.getDst()), link.getDstPort());
      // }
      // }

    }
    if (debug_level < 2) displayBellmanFord(src, predecessors, fwdingToSrcPorts, distances);
  }
  private void updateAllRouting() {
    if (debug_level < 2)
      System.out.println("\n**************Entering Update all Routing..**********************");

    this.adjMatrix = null;
    this.adjMatrix = this.createAdjMatrix();

    for (Host host : this.getHosts()) {
      // find shortest path to host - come from BF
      HashMap<String, String> predecessors = new HashMap<String, String>();
      HashMap<String, Integer> fwdingToSrcPorts = new HashMap<String, Integer>();
      HashMap<String, Integer> distances = new HashMap<String, Integer>();
      bellmanFord(adjMatrix, host, predecessors, fwdingToSrcPorts, distances);

      for (Host otherHost : this.getHosts()) {
        // foreach otherhost,
        if (debug_level < 2)
          System.out.println(
              "Tracing path from host : " + otherHost.getName() + " to " + host.getName());
        if (otherHost == host) {
          continue;
        }
        IOFSwitch currSw = otherHost.getSwitch();
        if (currSw == null) {
          if (debug_level < 2)
            System.out.println("Host " + otherHost.getName() + " not connected to any switch");
          continue;
        }

        String currSwId;
        // for each switch in the path to this host
        while (currSw != null) {
          // install rule on currSw
          if (debug_level < 1) System.out.println("currSw: " + String.valueOf(currSw.getId()));
          currSwId = String.valueOf(currSw.getId());
          if (fwdingToSrcPorts.get(currSwId) == null) {
            if (debug_level < 1)
              System.out.println(
                  "currSw "
                      + String.valueOf(currSw.getId())
                      + " has no further fwdToSrcPort entry");
            break;
          }
          int opPortTowardsSrc = fwdingToSrcPorts.get(currSwId);
          installL3FwdRule(currSw, host, opPortTowardsSrc);

          // currSw = predecessor.get(currSw);
          currSwId = predecessors.get(String.valueOf(currSw.getId()));
          if (currSwId.equals(host.getName())) {
            if (debug_level < 1)
              System.out.println(
                  "currSw "
                      + String.valueOf(currSw.getId())
                      + " has no further predecessor, directly connected to host");
            break;
          }
          currSw = this.getSwitches().get(Long.parseLong(currSwId));
          if (currSw == null) {
            if (debug_level < 1)
              System.out.println("end of path since updated currSw for" + currSwId + " is null");
          }
        }
      }
    }
    if (debug_level < 2) displayAdjMatrix();
  }