/**
   * *************************************************************************** Begin: Methods to
   * handle children communication
   * ***************************************************************************
   */
  public static void askChildren(BasicActor gridActor) throws Exception {

    // If there are children, then ...
    if (gridActor.getContext().getChildren().iterator().hasNext()) {
      BasicRequest request;
      RequestContent requestContent = gridActor.returnRequestContentToSend();

      // check if it is a MultiRequestContainer
      if (requestContent instanceof MultiRequestContainer) {
        MultiRequestContainer mrequest = (MultiRequestContainer) requestContent;

        // send the current message to the children
        if (mrequest.getCurrentRequestContent() instanceof SingleReceiverRequestContainer) {
          executeAskSpecificChildrenLogic(
              gridActor, (SingleReceiverRequestContainer) mrequest.getCurrentRequestContent());
        } else {
          request =
              new BasicRequest(
                  gridActor.getCurrentTimeStep(),
                  gridActor.downStreamTrace,
                  mrequest.getCurrentRequestContent());
          executeAskChildrenLogic(gridActor, request);
        }
      } else // normal execution without MultiRequestContainer
      {
        request =
            new BasicRequest(
                gridActor.getCurrentTimeStep(), gridActor.downStreamTrace, requestContent);
        executeAskChildrenLogic(gridActor, request);
      }
    }
    gridActor.upStreamTrace.add(gridActor.getSelf());
  }
  private static void executeAskLogic(BasicActor gridActor, RequestContent request) {

    // FIXME the check if the request is a ping or not shall be part of the errorHandling mechanism,
    // not the normal execution
    if (request instanceof PingRequestContent) {
      gridActor.makeDecision();
    } else {
      gridActor.askChildren();
      gridActor.makeDecision();
    }
  }
 private static void executeAskLogic(BasicActor gridActor, MultiRequestContainer mrequest) {
   gridActor.prepareRequest();
   if (debugging) {
     System.out.println(
         "---- Loop " + " Message type " + mrequest.getCurrentRequestContent() + " --------");
   }
   executeAskLogic(gridActor, mrequest.getCurrentRequestContent());
 }
  private static void executeAskChildrenLogic(BasicActor gridActor, BasicRequest request)
      throws Exception {

    // Patterns.ask() returns a Future<Object>
    List<Future<Object>> childrenResponseList = new ArrayList<Future<Object>>();

    Iterable<ActorRef> children = gridActor.getContext().getChildren();

    for (ActorRef child : children) {
      ConstantLogger.logMessageSendCounter(request);
      // wait x ms for response
      childrenResponseList.add(
          Patterns.ask(
              child,
              request,
              GridArchitectConfiguration.childrenResponseTime)); // childrenResponseListTimeOut
    }

    Future<Iterable<Object>> childrenFuturesIterable =
        sequence(childrenResponseList, gridActor.getContext().system().dispatcher());
    Iterable<Object> childrenResponsesIterable =
        Await.result(
            childrenFuturesIterable,
            Duration.create(
                (GridArchitectConfiguration.childrenResponseTime),
                TimeUnit.MILLISECONDS)); // childrenResponsesIterableTimeOut	

    gridActor.answerListReceived = new ArrayList<BasicAnswer>();
    for (Object iteratorResponses : childrenResponsesIterable) {
      BasicAnswer receivedAnswer = (BasicAnswer) iteratorResponses;

      gridActor.answerListReceived.add(receivedAnswer);
      ConstantLogger.logMessageSendCounter(receivedAnswer);
      if (receivedAnswer.overrideReportToParent) {
        gridActor.reportToParentEnabled = true;
        gridActor.overrideReportToParent = true;
      }

      // if multiple levels of hierarchie exist all actors will be included in the list
      for (ActorRef actor : receivedAnswer.upstreamActorTrace) {
        gridActor.upStreamTrace.add(actor);
      }
    }
  }
  public static void askSpecificActor(BasicActor gridActor) {
    if (!gridActor.actorOptions.directConnectionsPathList.isEmpty() && !gridActor.detectCircle()) {
      for (String actorPath : gridActor.actorOptions.directConnectionsPathList) {

        gridActor
            .getContext()
            .actorSelection("/user/ActorSupervisor/" + actorPath)
            .tell(
                new DirectMessage(gridActor.getCurrentTimeStep(), gridActor.downStreamTrace),
                gridActor.getSelf());
      }
      List<Future<Object>> actorResponseList = new ArrayList<Future<Object>>();
      for (String actorPath : gridActor.actorOptions.directConnectionsPathList)
        actorResponseList.add(
            ask(
                gridActor.getContext().actorSelection(actorPath),
                new DirectMessage(gridActor.getCurrentTimeStep(), gridActor.downStreamTrace),
                2000));
      Future<Iterable<Object>> actorFuturesIterable =
          sequence(actorResponseList, gridActor.getContext().system().dispatcher());
      try {
        Iterable<Object> actorResponsesIterable =
            Await.result(
                actorFuturesIterable,
                Duration.create(
                    (GridArchitectConfiguration.childrenResponseTime),
                    TimeUnit.MILLISECONDS)); // childrenResponsesIterableTimeOut
        for (Object response : actorResponsesIterable) {
          for (ActorRef actor : ((DirectAnswerMessage) response).actorTrace)
            gridActor.upStreamTrace.add(actor);
        }
        gridActor.upStreamTrace.add(gridActor.getSelf());
      } catch (Exception e) {
        System.out.println(e);
      }
    }
  }
  private static void executeAskSpecificChildrenLogic(
      BasicActor gridActor, SingleReceiverRequestContainer messages) throws Exception {
    // Patterns.ask() returns a Future<Object>
    List<Future<Object>> childrenResponseList = new ArrayList<Future<Object>>();

    for (SingleReceiverRequestContent secondMessage : messages.getRequests()) {
      for (ActorRef child : gridActor.getContext().getChildren()) {
        if (secondMessage.recieverPath.equals(child.path().toString())) {

          BasicRequest request =
              new BasicRequest(
                  gridActor.getCurrentTimeStep(), gridActor.downStreamTrace, secondMessage);
          ConstantLogger.logMessageSendCounter(request);
          // wait x ms for response
          childrenResponseList.add(
              Patterns.ask(child, request, GridArchitectConfiguration.childrenResponseTime));
        }
      }
    }

    Future<Iterable<Object>> childrenFuturesIterable =
        sequence(childrenResponseList, gridActor.getContext().system().dispatcher());
    Iterable<Object> childrenResponsesIterable =
        Await.result(
            childrenFuturesIterable,
            Duration.create(
                (GridArchitectConfiguration.childrenResponseTime),
                TimeUnit.MILLISECONDS)); // childrenResponsesIterableTimeOut

    gridActor.answerListReceived = new ArrayList<BasicAnswer>();
    for (Object receivedAnswer : childrenResponsesIterable) {

      gridActor.answerListReceived.add((BasicAnswer) receivedAnswer);

      ConstantLogger.logMessageSendCounter((BasicAnswer) receivedAnswer);

      if (((BasicAnswer) receivedAnswer).overrideReportToParent) {
        gridActor.reportToParentEnabled = true;
        gridActor.overrideReportToParent = true;
      }

      for (ActorRef actor : ((BasicAnswer) receivedAnswer).upstreamActorTrace) {
        gridActor.upStreamTrace.add(actor);
      }
    }
  }
  /**
   * *************************************************************************** BEGIN: Methods to
   * handle specificActor communication
   *
   * <p>taken from original communication pattern from Alex
   * ***************************************************************************
   */
  public static void answerSpecificActor(BasicActor gridActor, ActorRef sender) {
    if (!gridActor.detectCircle()) {
      gridActor.reportToParentEnabled = false;
      sender.tell(
          new DirectAnswerMessage(gridActor.getCurrentTimeStep(), gridActor.upStreamTrace, 0.0),
          gridActor.getSelf());
    } else {
      gridActor.reportToParentEnabled = true;

      sender.tell(
          new DirectAnswerMessage(gridActor.getCurrentTimeStep(), gridActor.upStreamTrace, 0.0),
          gridActor.getSelf());

      BasicAnswer basicAnswer =
          new BasicAnswer(
              gridActor.getCurrentTimeStep(),
              gridActor.upStreamTrace,
              true,
              false,
              gridActor.getSelf().path().toString(),
              gridActor.answerContent);

      gridActor.getContext().parent().tell(basicAnswer, gridActor.getSelf());
    }
  }
 private static void executeAskLogic(BasicActor gridActor, BasicRequest request) {
   gridActor.prepareRequest();
   executeAskLogic(gridActor, request.requestContent);
 }
  /**
   * Thats an important method
   *
   * @param gridActor
   * @param message
   */
  public static void doSomeWork(BasicActor gridActor, BasicRequest message) {
    // check if Map needs some initialization
    if (senderToMultipleRequestMapping == null) senderToMultipleRequestMapping = new HashMap<>();

    // check first if the given Message is a MultiMessage
    handleMultiRequest(message.requestContent);

    // if the current gridActor has send a MultiMessage, all the messages inside the MultiMessage
    // have to be processed
    if (checkIfMultiMessage(gridActor)) {
      MultiRequestContainer mrequest = ((MultiRequestContainer) getMultiMessage(gridActor));

      if (debugging) {
        System.out.println(
            "---------" + gridActor.getBasicActor().behaviorModel.actorName + "------------");
        System.out.println("-------------Loop-----------------");
      }

      // loop over all the messages inside the MultiMessage
      for (int i = 0; i < mrequest.maxNbCommunicationSteps; i++) {
        if (debugging) {
          System.out.println(
              "		---- Loop "
                  + i
                  + " "
                  + gridActor.actorOptions.behaviorModel.actorName
                  + "--------> Steps "
                  + mrequest.maxNbCommunicationSteps);
        }

        executeAskLogic(gridActor, mrequest);

        // if we reached the last step, we can remove it from the HashMap ( everything is processed)
        if (mrequest.isLastStep()) {
          removeMultiMessageValue(gridActor);
        } else {
          mrequest.nextStep();
        }

        if (debugging) {
          // System.out.println(gridActor.actorOptions.behaviorModel.actorName+" --> What kind of
          // message "+getMultiMessage(gridActor));
          System.out.println(
              "		---- Loop "
                  + i
                  + " "
                  + gridActor.actorOptions.behaviorModel.actorName
                  + " over--------");
        }
      }
      if (debugging) {
        System.out.println("-------------Loop over--------------");

        System.out.println(
            "---------" + gridActor.getBasicActor().behaviorModel.actorName + " end-------");
      }
    } else
    // no MultiMessage found -> proceed to normal communication
    {

      executeAskLogic(gridActor, message);
    }

    // AB HIER wird die Antwort vorbereitet

    // If the actor didn't replyed yet, then do reply
    if (gridActor.reportToParentEnabled) {
      BasicAnswer answer =
          new BasicAnswer(
              gridActor.getCurrentTimeStep(),
              gridActor.upStreamTrace,
              true,
              false,
              gridActor.getSelf().path().toString(),
              gridActor.returnAnswerContentToSend());

      gridActor.getSender().tell(answer, gridActor.getSelf());
      // REMINDER warum wird ein upStreamTrace benötigt (evtl. gehts auch ohne?)
      // System.out.println("ANSWER MESSAGE SENDED - " +gridActor.getSelf() +": " + answer);
      gridActor.upStreamTrace = new ArrayList<ActorRef>();
    } else {
      gridActor.initializationMessageCache = message;

      gridActor
          .getSender()
          .tell(
              new BasicAnswer(
                  gridActor.getCurrentTimeStep(),
                  gridActor.upStreamTrace,
                  true,
                  false,
                  gridActor.getSelf().path().toString(),
                  gridActor.answerContent),
              gridActor.getSelf());
    }
  }