@Override
  protected void refreshFingertable(Host fromNode) {
    AbstractChordRoutingTable crt =
        ((AbstractChordNode) fromNode.getOverlay(AbstractChordNode.class)).getChordRoutingTable();
    if (crt == null) {
      return;
    }
    AbstractChordContact[] ft = crt.copyFingerTable();
    LinkedHashSet<AbstractChordContact> ft_set =
        new LinkedHashSet<AbstractChordContact>(Arrays.asList(ft));
    if (ft_set.contains(null)) {
      ft_set.remove(null);
    }

    if (ft != null) {

      Map<NetID, EdgeHandle> edgeHandles = fingerEdges.get(netID(fromNode));
      if (edgeHandles == null) {
        edgeHandles = new LinkedHashMap<NetID, EdgeHandle>();
        fingerEdges.put(netID(fromNode), edgeHandles);
      }

      Set<NetID> vis_ft = fingertables.get(netID(fromNode));
      if (vis_ft == null) {
        vis_ft = new LinkedHashSet<NetID>();
        fingertables.put(netID(fromNode), vis_ft);
      }
      boolean ft_changed = false;
      // add new edges
      for (AbstractChordContact con : ft_set) {
        NetID newNetID = con.getTransInfo().getNetId();
        if (con != null && !vis_ft.contains(newNetID)) {
          EdgeHandle h = this.addEdge(netID(fromNode), newNetID, Color.LIGHT_GRAY, "finger");
          edgeHandles.put(newNetID, h);
          vis_ft.add(newNetID);
          ft_changed = true;
        }
      }
      // remove unused edges:
      if (vis_ft != null) {
        for (NetID nId : vis_ft) {
          boolean inUse = false;
          for (AbstractChordContact con : ft_set) {
            if (con.getTransInfo().getNetId().toString().equals(nId.toString())) {
              inUse = true;
              break;
            }
          }
          if (!inUse && edgeHandles.containsKey(nId)) {
            // remove edge.
            edgeHandles.get(nId).remove();
            edgeHandles.remove(nId);
          }
        }
      }
      if (ft_changed) {
        this.getTranslator()
            .nodeAttributeChanged(fromNode.getNetLayer().getNetID(), "ft_hosts", ft_set.size());
      }
    }
  }
  private void refreshVirtualNodes(Host host, LinkedList<ChordRoutingTable> deleted) {
    if (host != null) {
      for (AbstractChordRoutingTable rt :
          ((ChordNode) host.getOverlay(AbstractChordNode.class)).getVirtualNodes()) {
        // check if this virtual node does not exist:
        if (!virtualNodes.containsKey(((ChordRoutingTable) rt).getChordId())) {
          // create node!

          // TODO: this is quite sick hacked together!

          NetID n =
              new NetID() {
                @Override
                public long getTransmissionSize() {
                  return 0;
                }
              };

          // create attributes
          Map<String, Serializable> attributes = new LinkedHashMap<String, Serializable>();
          attributes.put("ChordID", ((ChordRoutingTable) rt).getChordId());

          // compute position on ring:
          double div = 0.0;
          BigInteger MAX_KEY_SIZE =
              new BigInteger("1461501637330902918203684832716283019655932542975");

          div =
              ((ChordRoutingTable) rt).getChordId().getValue().doubleValue()
                  / MAX_KEY_SIZE.doubleValue();

          float x = 0.5f + 0.4f * (float) Math.sin(2 * Math.PI * div);
          float y = 0.5f + 0.4f * (float) Math.cos(2 * Math.PI * div);

          // add virtual node to visualisation
          getTranslator()
              .overlayNodeAdded(n, "vNode", new PositionInfo(new Coords(x, y)), attributes);
          virtualNodes.put(((ChordRoutingTable) rt).getChordId(), n);

          // add edge from real node to virtual node:
          EdgeHandle h =
              this.addEdge(
                  rt.getMasterNode().getHost().getNetLayer().getNetID(),
                  n,
                  Color.BLUE,
                  "virtualNodeEdge");

          virtualNodeEdges.put(((ChordRoutingTable) rt).getChordId(), h);
        }
      }

      // remove thoses who have been deleted:
      if (deleted != null) {
        for (AbstractChordRoutingTable rt : deleted) {
          if (virtualNodeEdges.containsKey(((ChordRoutingTable) rt).getChordId())) {
            virtualNodeEdges.get(((ChordRoutingTable) rt).getChordId()).remove();
          }

          if (virtualNodes.containsKey(((ChordRoutingTable) rt).getChordId())) {
            getTranslator()
                .overlayNodeRemoved(virtualNodes.get(((ChordRoutingTable) rt).getChordId()));
          }
        }
      }
    }
  }