/**
   * Process an incoming update request from an attacking agent. Using the censor component, this
   * method first checks if a secret might be revealed by the actual update handling. Based on this
   * preprocessing, it either generates a Refusal-SpeechAct or runs the actual update on the belief
   * base and generates a notification action.
   *
   * @param desire
   * @param pp
   * @param ag
   */
  public boolean processUpdate(Desire desire, PlanParameter pp, Agent ag) {
    pp.report("Generate new subgoal to process update request");

    CensorComponent cexec = ag.getComponent(CensorComponent.class);

    Update update = (Update) desire.getPerception();

    GeneralView v = ag.getComponent(ViewDataComponent.class).getView(update.getSenderId());
    SecrecyKnowledge conf = ag.getComponent(SecrecyKnowledge.class);
    GeneralHistory history = null;

    pp.report("Invoke censor to check all possible answers for meta inferences");
    if (v instanceof ViewWithCompressedHistory) {
      ViewWithCompressedHistory view = new ViewWithCompressedHistory((ViewWithCompressedHistory) v);
      history = ag.getComponent(HistoryComponent.class).getHistories().get(update.getSenderId());
      if (history == null) {
        history = new CompressedHistory();
        ag.getComponent(HistoryComponent.class).getHistories().put(update.getSenderId(), history);
      }
      // check if update would reveal a secret
      ViewWithCompressedHistory refinedView =
          view.RefineViewByUpdate(update.getProposition(), AnswerValue.AV_TRUE);
      CompressedHistory refinedHistory = new CompressedHistory((CompressedHistory) history);
      refinedHistory.putAction(update, AnswerValue.AV_TRUE);

      for (Secret s : conf.getSecrets()) {
        if (cexec.scepticalInference(refinedView, s.getInformation(), refinedHistory)) {
          this.sendRejectAnswer(ag, desire, cexec, update, s, "success");
          history.putAction(update, AnswerValue.AV_REJECT);
          ag.getComponent(HistoryComponent.class).getHistories().put(update.getSenderId(), history);
          return true;
        }
      }

      // check if the failure of the update would reveal a secret
      refinedView = view.RefineViewByUpdate(update.getProposition(), AnswerValue.AV_FALSE);
      refinedHistory = new CompressedHistory((CompressedHistory) history);
      refinedHistory.putAction(update, AnswerValue.AV_FALSE);

      for (Secret s : conf.getSecrets()) {
        if (cexec.scepticalInference(refinedView, s.getInformation(), refinedHistory)) {
          this.sendRejectAnswer(ag, desire, cexec, update, s, "failure");
          history.putAction(update, AnswerValue.AV_REJECT);
          ag.getComponent(HistoryComponent.class).getHistories().put(update.getSenderId(), history);
          return true;
        }
      }
    } else if (v instanceof ViewWithHistory) {
      ViewWithHistory view = (ViewWithHistory) v;
      history = ag.getComponent(HistoryComponent.class).getHistories().get(update.getSenderId());
      if (history == null) {
        history = new History();
        ag.getComponent(HistoryComponent.class).getHistories().put(update.getSenderId(), history);
      }
      // check if update would reveal a secret
      ViewWithHistory refinedView =
          view.RefineViewByUpdate(update.getProposition(), AnswerValue.AV_TRUE);
      for (Secret s : conf.getSecrets()) {
        if (cexec.scepticalInference(refinedView, s.getInformation())) {
          this.sendRejectAnswer(ag, desire, cexec, update, s, "success");
          history.putAction(update, AnswerValue.AV_REJECT);
          ag.getComponent(HistoryComponent.class).getHistories().put(update.getSenderId(), history);
          return true;
        }
      }

      // check if the failure of the update would reveal a secret
      refinedView = view.RefineViewByUpdate(update.getProposition(), AnswerValue.AV_FALSE);
      for (Secret s : conf.getSecrets()) {
        if (cexec.scepticalInference(refinedView, s.getInformation())) {
          this.sendRejectAnswer(ag, desire, cexec, update, s, "failure");
          history.putAction(update, AnswerValue.AV_REJECT);
          ag.getComponent(HistoryComponent.class).getHistories().put(update.getSenderId(), history);
          return true;
        }
      }
    } else if (v instanceof BetterView) {
      BetterView view = (BetterView) v;

      // check if update would reveal a secret
      BetterView refinedView =
          view.RefineViewByUpdate(update.getProposition(), AnswerValue.AV_TRUE);
      for (Secret s : conf.getSecrets()) {
        if (cexec.scepticalInference(refinedView, s.getInformation())) {
          this.sendRejectAnswer(ag, desire, cexec, update, s, "success");
          return true;
        }
      }

      // check if the failure of the update would reveal a secret
      refinedView = view.RefineViewByUpdate(update.getProposition(), AnswerValue.AV_FALSE);
      for (Secret s : conf.getSecrets()) {
        if (cexec.scepticalInference(refinedView, s.getInformation())) {
          this.sendRejectAnswer(ag, desire, cexec, update, s, "failure");
          return true;
        }
      }
    }

    // update would not breach confidentiality, continue updating beliefbase
    BaseBeliefbase bbase = ag.getBeliefs().getWorldKnowledge();

    OperatorCallWrapper changeOp = bbase.getChangeOperator();
    boolean success = false;
    if (changeOp.getImplementation() instanceof PLWithKnowledgeUpdate) {
      PLWithKnowledgeUpdate updateOp = (PLWithKnowledgeUpdate) changeOp.getImplementation();
      success =
          updateOp.simulateUpdate(
              update.getProposition(), ((PLWithKnowledgeBeliefbase) bbase).getKnowledge());
    }

    AnswerValue answerValue = AnswerValue.AV_FALSE;
    if (success) {
      pp.report(
          "Update will be successful. Send answer 'true' and add '"
              + update.getProposition().toString()
              + "' to belief base");
      answerValue = AnswerValue.AV_TRUE;
    } else {
      pp.report("Update will be not be successful. Send answer 'false'.");
      answerValue = AnswerValue.AV_FALSE;
    }

    if (history != null) {
      history.putAction(update, answerValue);
      ag.getComponent(HistoryComponent.class).getHistories().put(update.getSenderId(), history);
    }

    // send answer
    UpdateAnswer answer =
        new UpdateAnswer(ag, update.getSenderId(), update.getProposition(), answerValue);
    Subgoal answerGoal = new Subgoal(ag, desire);
    answerGoal.newStack(answer);
    ag.getPlanComponent().addPlan(answerGoal);
    pp.report(
        "Add the new action '" + UpdateAnswer.class.getSimpleName() + "' to the plan",
        ag.getPlanComponent());

    return true;
  }
  /**
   * Process an incoming query request from an attacking agent. Using the censor component, this
   * method first checks if a secret might be revealed by the actual query handling. Based on this
   * preprocessing, it either generates a Refusal-SpeechAct or starts the query handling and
   * generates an appropriate answer.
   *
   * @param desire
   * @param pp
   * @param ag
   */
  public boolean processQuery(Desire desire, PlanParameter pp, Agent ag) {
    pp.report("Generate new subgoal to process query request");

    CensorComponent cexec = ag.getComponent(CensorComponent.class);

    Query query = (Query) desire.getPerception();

    GeneralView v = ag.getComponent(ViewDataComponent.class).getView(query.getSenderId());
    SecrecyKnowledge conf = ag.getComponent(SecrecyKnowledge.class);
    GeneralHistory history = null;

    pp.report("Invoke censor to check all possible answers for meta inferences");
    if (v instanceof View) {
      View view = (View) v;
      // check for all possible answers to the query, whether this answer would
      // potentially reveal a secret and in that case, refuse to answer.
      for (Secret a : conf.getSecrets()) {
        // ans := true
        if (cexec.poss(view.RefineViewByQuery(query.getQuestion(), AnswerValue.AV_TRUE))
            && cexec.scepticalInference(
                view.RefineViewByQuery(query.getQuestion(), AnswerValue.AV_TRUE),
                a.getInformation())) {
          this.sendRejectAnswer(ag, desire, cexec, query, a, "true");
          return true;
        }
        // ans := false
        if (cexec.poss(view.RefineViewByQuery(query.getQuestion(), AnswerValue.AV_FALSE))
            && cexec.scepticalInference(
                view.RefineViewByQuery(query.getQuestion(), AnswerValue.AV_FALSE),
                a.getInformation())) {
          this.sendRejectAnswer(ag, desire, cexec, query, a, "false");
          return true;
        }
        // ans := undef
        if (cexec.poss(view.RefineViewByQuery(query.getQuestion(), AnswerValue.AV_UNKNOWN))
            && cexec.scepticalInference(
                view.RefineViewByQuery(query.getQuestion(), AnswerValue.AV_UNKNOWN),
                a.getInformation())) {
          this.sendRejectAnswer(ag, desire, cexec, query, a, "unknown");
          return true;
        }
      }
    } else if (v instanceof ViewWithCompressedHistory) {
      ViewWithCompressedHistory view = (ViewWithCompressedHistory) v;
      history = ag.getComponent(HistoryComponent.class).getHistories().get(query.getSenderId());
      if (history == null) {
        history = new CompressedHistory();
        ag.getComponent(HistoryComponent.class).getHistories().put(query.getSenderId(), history);
      }
      for (Secret a : conf.getSecrets()) {
        // ans := true
        ViewWithCompressedHistory copyView = new ViewWithCompressedHistory(view);
        CompressedHistory refinedHistory = new CompressedHistory((CompressedHistory) history);
        refinedHistory.putAction(query, AnswerValue.AV_TRUE);
        if (cexec.scepticalInference(copyView, a.getInformation(), refinedHistory)) {
          this.sendRejectAnswer(ag, desire, cexec, query, a, "true");
          history.putAction(query, AnswerValue.AV_REJECT);
          ag.getComponent(HistoryComponent.class).getHistories().put(query.getSenderId(), history);
          return true;
        }

        // ans := false
        copyView = new ViewWithCompressedHistory(view);
        refinedHistory = new CompressedHistory((CompressedHistory) history);
        refinedHistory.putAction(query, AnswerValue.AV_FALSE);
        if (cexec.scepticalInference(copyView, a.getInformation(), refinedHistory)) {
          this.sendRejectAnswer(ag, desire, cexec, query, a, "false");
          history.putAction(query, AnswerValue.AV_REJECT);
          ag.getComponent(HistoryComponent.class).getHistories().put(query.getSenderId(), history);
          return true;
        }

        // ans := undef
        copyView = new ViewWithCompressedHistory(view);
        refinedHistory = new CompressedHistory((CompressedHistory) history);
        refinedHistory.putAction(query, AnswerValue.AV_UNKNOWN);
        if (cexec.scepticalInference(copyView, a.getInformation(), refinedHistory)) {
          this.sendRejectAnswer(ag, desire, cexec, query, a, "unknown");
          history.putAction(query, AnswerValue.AV_REJECT);
          ag.getComponent(HistoryComponent.class).getHistories().put(query.getSenderId(), history);
          return true;
        }
      }
    } else if (v instanceof ViewWithHistory) {
      ViewWithHistory view = (ViewWithHistory) v;
      history = ag.getComponent(HistoryComponent.class).getHistories().get(query.getSenderId());
      if (history == null) {
        history = new History();
        ag.getComponent(HistoryComponent.class).getHistories().put(query.getSenderId(), history);
      }
      // check for all possible answers to the query, whether this answer would
      // potentially reveal a secret and in that case, refuse to answer.
      for (Secret a : conf.getSecrets()) {
        // ans := true
        if (cexec.scepticalInference(
            view.RefineViewByQuery(query.getQuestion(), AnswerValue.AV_TRUE), a.getInformation())) {
          this.sendRejectAnswer(ag, desire, cexec, query, a, "true");
          history.putAction(query, AnswerValue.AV_REJECT);
          ag.getComponent(HistoryComponent.class).getHistories().put(query.getSenderId(), history);
          return true;
        }
        // ans := false
        if (cexec.scepticalInference(
            view.RefineViewByQuery(query.getQuestion(), AnswerValue.AV_FALSE),
            a.getInformation())) {
          this.sendRejectAnswer(ag, desire, cexec, query, a, "false");
          history.putAction(query, AnswerValue.AV_REJECT);
          ag.getComponent(HistoryComponent.class).getHistories().put(query.getSenderId(), history);
          return true;
        }
        // ans := undef
        if (cexec.scepticalInference(
            view.RefineViewByQuery(query.getQuestion(), AnswerValue.AV_UNKNOWN),
            a.getInformation())) {
          this.sendRejectAnswer(ag, desire, cexec, query, a, "unknown");
          history.putAction(query, AnswerValue.AV_REJECT);
          ag.getComponent(HistoryComponent.class).getHistories().put(query.getSenderId(), history);
          return true;
        }
      }
    } else if (v instanceof BetterView) {
      BetterView view = (BetterView) v;

      // check for all possible answers to the query, whether this answer would
      // potentially reveal a secret and in that case, refuse to answer.
      for (Secret a : conf.getSecrets()) {
        // ans := true
        if (cexec.scepticalInference(
            view.MentalRefineViewByQuery(query.getQuestion(), AnswerValue.AV_TRUE),
            a.getInformation())) {
          this.sendRejectAnswer(ag, desire, cexec, query, a, "true");
          return true;
        }
        // ans := false
        if (cexec.scepticalInference(
            view.MentalRefineViewByQuery(query.getQuestion(), AnswerValue.AV_FALSE),
            a.getInformation())) {
          this.sendRejectAnswer(ag, desire, cexec, query, a, "false");
          return true;
        }
        // ans := undef
        if (cexec.scepticalInference(
            view.MentalRefineViewByQuery(query.getQuestion(), AnswerValue.AV_UNKNOWN),
            a.getInformation())) {
          this.sendRejectAnswer(ag, desire, cexec, query, a, "unknown");
          return true;
        }
      }
    }
    cexec.report(
        "No answer to query '"
            + query.getQuestion()
            + " would reveal a secret. Start actual handling.");

    // no secret will be revealed by any possible answer to the query.
    // handle the query and create an appropriate answer action.
    AngeronaAnswer answer = ag.getBeliefs().getWorldKnowledge().reason(query.getQuestion());
    if (history != null) {
      history.putAction(query, answer.getAnswerValue());
      ag.getComponent(HistoryComponent.class).getHistories().put(query.getSenderId(), history);
    }
    ag.getBeliefs()
        .getWorldKnowledge()
        .report("Actual answer to query: " + answer.getAnswerValue());
    Answer answerSpeechAct =
        new Answer(ag, query.getSenderId(), query.getQuestion(), answer.getAnswerValue());
    Subgoal answerGoal = new Subgoal(ag, desire);
    answerGoal.newStack(answerSpeechAct);
    ag.getPlanComponent().addPlan(answerGoal);

    pp.report(
        "Add the new action '" + Answer.class.getSimpleName() + "' to the plan",
        ag.getPlanComponent());
    return true;
  }