void lookupOperationSucceeded(Operation<OverlayContact<OverlayID<?>>> op) {
    LookupResult result = treeHandlerDelegator.lookupOperationSucceeded(op);
    parentCoordinator =
        new SkyNetNodeInfoImpl(
            result.getSkyNetID(),
            coordinatorKey,
            DefaultTransInfo.getTransInfo(
                result.getContact().getTransInfo().getNetId(), skyNetNode.getPort()),
            level);
    log.info(
        parentCoordinator.toString()
            + " is parentCoordinator of "
            + skyNetNode.getSkyNetNodeInfo().toString());

    skyNetNode.getMetricUpdateStrategy().sendNextDataUpdate();
  }
  private void lookupParentCoordinator() {
    if (((AbstractOverlayNode<?, ?>) skyNetNode.getOverlayNode())
        .getPeerStatus()
        .equals(PeerStatus.PRESENT)) {
      log.debug(
          SkyNetUtilities.getTimeAndNetID(skyNetNode)
              + "starts a lookup for the key "
              + coordinatorKey.getPlainSkyNetID());
      treeHandlerDelegator.lookupParentCoordinator(
          coordinatorKey,
          new OperationCallback<OverlayContact<OverlayID<?>>>() {

            @Override
            public void calledOperationFailed(Operation<OverlayContact<OverlayID<?>>> op) {
              lookupOperationFailed(op);
            }

            @Override
            public void calledOperationSucceeded(Operation<OverlayContact<OverlayID<?>>> op) {
              lookupOperationSucceeded(op);
            }
          });
    } else {
      log.warn("SkyNetNode cannot lookup ParentCoordinator" + ", because he is not PRESENT");
    }
  }
  private void calculateNextLevel(
      SkyNetID ownID, SkyNetID skyNetCoKey, BigDecimal left, BigDecimal right, int iter) {
    if (iter == 0) {
      coordinatorKey = skyNetCoKey;
      level = iter;
    } else {
      coordinatorKey = skyNetCoKey;
      level = iter;
    }
    if (iter < 100) {
      // call processNextLevel(...), but before split the interval
      // defined by left and right in k subintervals as defined by
      // branchingFactor.
      BigDecimal interval = right.subtract(left);
      BigDecimal intervalStep = interval.divide(new BigDecimal(String.valueOf(branchingFactor)));
      BigDecimal tempLeft = left;
      BigDecimal tempRight = left.add(new BigDecimal(String.valueOf(intervalStep)));
      log.info(
          SkyNetUtilities.getTimeAndNetID(skyNetNode)
              + "is actually in the interval between "
              + left.toPlainString()
              + " and "
              + right.toPlainString()
              + ". The size of the interval is"
              + interval);
      int correctnessCounter = 0;
      while (ownID.getID().compareTo(tempRight) > -1) {
        tempLeft = tempRight;
        tempRight = tempRight.add(new BigDecimal(String.valueOf(intervalStep)));
        if (correctnessCounter < branchingFactor) {
          correctnessCounter++;
        } else {
          log.fatal(
              "There are actually "
                  + (correctnessCounter + 1)
                  + " intervals instead of "
                  + branchingFactor);
        }
      }
      processNextLevel(ownID, tempLeft, tempRight, iter + 1);

    } else {
      skyNetNode.getMetricUpdateStrategy().scheduleNextUpdateEvent();
      parentCoordinator = null;
      if (isRoot) {
        log.warn(SkyNetUtilities.getTimeAndNetID(skyNetNode) + "lost the root-position");
      }
      isRoot = false;
      log.error(
          SkyNetUtilities.getTimeAndNetID(skyNetNode)
              + "is to deep in the tree."
              + "Probably no predecessor in the overlay can be found"
              + " to calculate the 'isRootOf'-method");
    }
  }
  private void checkResponsibility(
      SkyNetID ownID, SkyNetID skyNetCoKey, BigDecimal left, BigDecimal right, int iter) {
    skyNetNode.getSkyNetNodeInfo().setCoordinatorKey(skyNetCoKey);
    log.info(
        " The client "
            + skyNetNode.getSkyNetNodeInfo().toString()
            + " is responsible for the CoordinatorKey "
            + skyNetCoKey.getPlainSkyNetID()
            + " in the interval["
            + left.toPlainString()
            + ";"
            + right.toPlainString()
            + "] @ level "
            + iter);

    ISkyNetMonitor monitor = (ISkyNetMonitor) Simulator.getMonitor();
    ChurnStatisticsAnalyzer csAnalyzer =
        (ChurnStatisticsAnalyzer) monitor.getConnectivityAnalyzer(ChurnStatisticsAnalyzer.class);

    if (iter > 0) {
      // complete the parentSkyNetNode Info
      if (isRoot) {
        log.warn(SkyNetUtilities.getTimeAndNetID(skyNetNode) + "lost the root-position");
        csAnalyzer.lostRootPosition(skyNetNode);
        skyNetNode.getMetricUpdateStrategy().setLastMetricSync(0);
      }
      skyNetNode.getSkyNetNodeInfo().setLevel(iter);
      isRoot = false;
      lookupParentCoordinator();
    } else {
      if (!isRoot) {
        log.warn(SkyNetUtilities.getTimeAndNetID(skyNetNode) + "got the root-position");
        csAnalyzer.gotRootPosition(skyNetNode);
        skyNetNode.getMetricUpdateStrategy().setLastMetricSync(0);
      }
      skyNetNode.getSkyNetNodeInfo().setLevel(iter);

      // Also set the observed level at this point
      skyNetNode.getSkyNetNodeInfo().setObservedLevelFromRoot(0);

      isRoot = true;
      skyNetNode.getAttributeUpdateStrategy().resetOnlyAttributeUpdateStrategy();
      skyNetNode.getMetricUpdateStrategy().sendNextDataUpdate();
    }
  }
  public TreeHandler(SkyNetNodeInterface node, TreeHandlerDelegator treeHandlerDelegator) {
    branchingFactor =
        SkyNetPropertiesReader.getInstance().getIntProperty("SkyNetTreeBranchingFactor");

    this.skyNetNode = node;
    this.treeHandlerDelegator = treeHandlerDelegator;
    this.treeHandlerDelegator.setSkyNetNode(skyNetNode);
    this.treeHandlerDelegator.setOwnOverlayNode(skyNetNode.getOverlayNode());
    isRoot = false;
    parentCoordinator = new SkyNetNodeInfoImpl(null, null, null, -1);
    coordinatorKey = null;
    level = 0;
  }
  /**
   * If it is possible to calculate the responsibility interval of a peer on the current overlay,
   * this method calculates the corresponding responsibility interval of the node in the ID-space of
   * SkyNet. In this context, the responsibility interval is used to test, if a SkyNet-node is
   * responsible for a Coordinator.
   *
   * @param id contains the ID of this SkyNet-node
   */
  public void calculateResponsibilityInterval(SkyNetID id) {
    if (((AbstractOverlayNode<?, ?>) skyNetNode.getOverlayNode())
        .getPeerStatus()
        .equals(PeerStatus.PRESENT)) {
      // execute getPredecessor-method
      final SkyNetID ownID = id;
      treeHandlerDelegator.calculateResponsibilityInterval(
          ownID,
          new OperationCallback<OverlayContact<OverlayID<?>>>() {

            @Override
            public void calledOperationFailed(Operation<OverlayContact<OverlayID<?>>> op) {
              calculateResponsibilityIntervalOperationFailed(op);
            }

            @Override
            public void calledOperationSucceeded(Operation<OverlayContact<OverlayID<?>>> op) {
              calculateResponsibilityIntervalOperationSucceeded(op, ownID);
            }
          });
    } else {
      log.warn("SkyNetNode cannot get Predecessor" + ", because he is not PRESENT");
    }
  }
 void lookupOperationFailed(Operation<OverlayContact<OverlayID<?>>> op) {
   treeHandlerDelegator.lookupOperationFailed(op);
   skyNetNode.getMetricUpdateStrategy().scheduleNextUpdateEvent();
 }
 void processNextLevelOperationFailed(Operation<?> op) {
   treeHandlerDelegator.processNextLevelOperationFailed(op);
   skyNetNode.getMetricUpdateStrategy().scheduleNextUpdateEvent();
 }
 void calculateResponsibilityIntervalOperationFailed(Operation<OverlayContact<OverlayID<?>>> op) {
   treeHandlerDelegator.calculateResponsibilityIntervalOperationFailed(op);
   skyNetNode.getMetricUpdateStrategy().scheduleNextUpdateEvent();
 }