class PeerTable {

  public AddResult tryAdd(final DiscoveryPeer peer) {
    final Bytes id = peer.getId();
    final int distance = distanceFrom(peer);

    // Safeguard against adding ourselves to the peer table.
    if (distance == 0) {
      return AddResult.self();
    }

    final Bucket bucket = table[distance];
    // We add the peer, and two things can happen: (1) either we get an empty optional (peer was
    // added successfully,
    // or it was already there), or (2) we get a filled optional, in which case the bucket is full
    // and an eviction
    // candidate is proposed. The Bucket#add method will raise an exception if the peer already
    // existed.
    final Optional<DiscoveryPeer> res;
    try {
      res = bucket.add(peer);
    } catch (final IllegalArgumentException ex) {
      return AddResult.existed();
    }

    if (!res.isPresent()) {
      idBloom.put(id);
      distanceCache.put(id, distance);
      return AddResult.added();
    }

    return res.map(AddResult::bucketFull).get();
  }

  public  PeerTable(final Bytes nodeId, final int bucketSize);
  public  PeerTable(final Bytes nodeId);

}