/**
   * *************************************************************************** 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());
    }
  }
  /**
   * *************************************************************************** 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());
  }
  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);
      }
    }
  }
  /**
   * 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());
    }
  }