/**
   * This method is the access point to the planning procedure. Initially, it adds all variables
   * from axioms to the set of found vars, then does the linear planning. If lp does not solve the
   * problem and there are subtasks, goal-driven recursive planning with backtracking is invoked.
   * Planning is performed until no new variables are introduced into the algorithm.
   */
  public EvaluationAlgorithm invokePlaning(Problem problem, boolean _computeAll) {
    long startTime = System.currentTimeMillis();

    computeAll = _computeAll;
    EvaluationAlgorithm algorithm = new EvaluationAlgorithm();

    PlanningContext context = problem.getCurrentContext();

    // add all axioms at the beginning of an algorithm
    Collection<Var> flattened = new HashSet<Var>();
    for (Iterator<Rel> axiomIter = problem.getAxioms().iterator(); axiomIter.hasNext(); ) {
      Rel rel = axiomIter.next();

      unfoldVarsToSet(rel.getOutputs(), flattened);

      // do not overwrite values of variables that come via args of compute() or as inputs of
      // independent subtasks
      if (!problem.getAssumptions().containsAll(flattened)
      // do not overwrite values of already known variables.
      // typically this is the case when a value of a variable
      // is given in a scheme via a properties window
      //                    && !problem.getKnownVars().containsAll( flattened )
      ) {
        algorithm.addRel(rel);
      }
      axiomIter.remove();
      context.getKnownVars().addAll(flattened);
      flattened.clear();
    }

    context.getFoundVars().addAll(context.getKnownVars());

    // remove all known vars with no relations
    for (Iterator<Var> varIter = context.getKnownVars().iterator(); varIter.hasNext(); ) {
      if (varIter.next().getRels().isEmpty()) {
        varIter.remove();
      }
    }

    // start planning
    if (problem.getRelsWithSubtasks().isEmpty()
        && linearForwardSearch(context, algorithm, computeAll)) {
      if (isLinearLoggingOn()) logger.debug("Problem solved without subtasks");
    } else if (!problem.getRelsWithSubtasks().isEmpty() && subtaskPlanning(problem, algorithm)) {
      if (isLinearLoggingOn()) logger.debug("Problem solved with subtasks");
    } else if (!computeAll) {
      if (isLinearLoggingOn()) logger.debug("Problem not solved");
    }

    if (!nested) {
      logger.info("Planning time: " + (System.currentTimeMillis() - startTime) + "ms.");
    }
    return algorithm;
  }
  private boolean subtaskPlanning(Problem problem, EvaluationAlgorithm algorithm) {

    if (isSubtaskLoggingOn())
      logger.debug("!!!--------- Starting Planning With Subtasks ---------!!!");

    final int maxDepthBackup = maxDepth;
    if (isSubtaskLoggingOn())
      logger.debug(
          "maxDepthBackup:" + maxDepthBackup + " sbt: " + problem.getRelsWithSubtasks().size());
    PlanningContext context = problem.getCurrentContext();

    try {

      Set<Rel> relsWithSubtasks = new LinkedHashSet<Rel>(problem.getRelsWithSubtasks());

      if (isIncremental) {
        int incrementalDepth = 0;

        while (incrementalDepth
            <= (isSubtaskRepetitionAllowed
                ? maxDepthBackup
                : problem.getRelsWithSubtasks().size() - 1)) {
          if (isSubtaskLoggingOn())
            logger.debug(
                "Incremental dfs, with max depth "
                    + (incrementalDepth + 1)
                    + " and "
                    + problem.getRelsWithSubtasks().size()
                    + " subtasks to solve");

          maxDepth = incrementalDepth++;

          // if we need to compute some specific goals, after reaching a certain depth, but not the
          // maximal depth,
          // the problem may be solved and there is no need to go any deeper.
          if (subtaskPlanningImpl(context, relsWithSubtasks, algorithm, new LinkedList<Rel>(), 0)) {
            if (isSubtaskLoggingOn())
              logger.debug("The problem was solved during idfs after some intermediate MLB");
            return true;
          }

          if (isSubtaskLoggingOn())
            logger.debug("Unsolved subtask left: " + problem.getRelsWithSubtasks().size());
        }

        if (isSubtaskLoggingOn()) logger.debug("Fininshed incremental dfs");

      } else {
        if (!isSubtaskRepetitionAllowed) {
          maxDepth = problem.getRelsWithSubtasks().size() - 1;
        }

        if (isSubtaskLoggingOn())
          logger.debug("Starting subtask dfs with maxDepth: " + (maxDepth + 1));

        if (subtaskPlanningImpl(context, relsWithSubtasks, algorithm, new LinkedList<Rel>(), 0)) {
          if (isSubtaskLoggingOn())
            logger.debug("The problem was solved during dfs after some intermediate MLB");
          return true;
        }
      }

    } finally {
      if (isSubtaskLoggingOn()) logger.debug("Fininshed dfs");

      maxDepth = maxDepthBackup;
      indSubtasks.clear();
    }

    if (isSubtaskLoggingOn()) logger.debug("Invoking final linear planning");

    return linearForwardSearch(context, algorithm, computeAll);
  }