/**
   * 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 revision request from an attacking agent. Using the censor component, this
   * method first checks if a secret might be revealed by the actual revision handling. Based on
   * this preprocessing, it either generates a Refusal-SpeechAct or runs the actual revision on the
   * belief base and generates a notification action.
   *
   * @param desire
   * @param pp
   * @param ag
   */
  public boolean processRevision(Desire desire, PlanParameter pp, Agent ag) {
    pp.report("Generate new subgoal to process revision request");
    CensorComponent cexec = ag.getComponent(CensorComponent.class);

    Revision revision = (Revision) desire.getPerception();
    View view = (View) ag.getComponent(ViewDataComponent.class).getView(revision.getSenderId());
    SecrecyKnowledge conf = ag.getComponent(SecrecyKnowledge.class);

    pp.report("Invoke censor to check all possible answers for meta inferences");

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

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

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

    // slightly hacked: we need to get the revision result from the revision operator
    OperatorCallWrapper changeOp = bbase.getChangeOperator();
    boolean success = false;
    if (changeOp.getImplementation() instanceof ConditionalRevision) {
      ConditionalRevision revisionOp = (ConditionalRevision) changeOp.getImplementation();
      OperatorCallWrapper translator = bbase.getTranslator();
      Set<FolFormula> revisionFormulas = new HashSet<FolFormula>();
      revisionFormulas.add(revision.getProposition());
      ConditionalBeliefbase newK =
          (ConditionalBeliefbase)
              translator.process(new TranslatorParameter(bbase, revisionFormulas));
      success = revisionOp.simulateRevision((ConditionalBeliefbase) bbase, newK);
    }

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

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