/**
   * initialises the values in the tree and inits/clears the leaf list
   *
   * @see AbstractWorkflowStep#init()
   */
  public void init() {
    clearLogBuffer();
    initLeafLists();
    boolean xcl = false;
    hasAutomatedMeasurements.setBool(false);
    Iterator<Leaf> iter = selectedPlan.getTree().getRoot().getAllLeaves().iterator();
    while (iter.hasNext()) {
      Leaf l = iter.next();
      if (l.isMapped()) {
        hasAutomatedMeasurements.setBool(true);

        if (l.getMeasurementInfo().getProperty().getName().startsWith("xcl/")) {
          xcl = true;
        }
      }
    }
    if (xcl) {
      for (DigitalObject o : selectedPlan.getSampleRecordsDefinition().getRecords()) {
        if ((o.getXcdlDescription() == null) || !o.getXcdlDescription().isDataExistent()) {
          FacesMessages.instance()
              .add(
                  FacesMessage.SEVERITY_INFO,
                  "Some XCL descriptions for samples are missing, XCL comparison will not work for these samples. ");
          break;
        }
      }
      for (Alternative a : selectedPlan.getAlternativesDefinition().getAlternatives()) {
        for (DigitalObject r : a.getExperiment().getResults().values()) {
          if ((r.getXcdlDescription() == null) || !r.getXcdlDescription().isDataExistent()) {
            FacesMessages.instance()
                .add(
                    FacesMessage.SEVERITY_INFO,
                    "XCL descriptions for experiment results of "
                        + a.getName()
                        + " are missing, "
                        + "XCL comparison will not work for these objects. ");
            break;
          }
        }
      }
    }

    // TODO for now this is ALWAYS reloaded when entering,
    // but should be cached in the future.
    MiniRED.getInstance().reloadEvaluators();
    refreshMeasurableProperties();
  }
  /**
   * @param record sample object the alternative has been carried out on
   * @param alternative alternative which has been carried out on the alternative (we determine the
   *     result object from the alternative)
   */
  public void setTreeFromRecordAltern(Object record, Object alternative) {

    if (!(record instanceof SampleObject) || !(alternative instanceof Alternative)) {
      return;
    }

    Alternative a = (Alternative) alternative;
    SampleObject o = (SampleObject) record;

    o = em.merge(o);
    jhoveTree1 = characteriseJHove(o);

    // get the result
    // we have to merge the sample object back into the session to be able to access the byte stream
    DigitalObject result = em.merge(a.getExperiment().getResults().get(record));
    a.getExperiment().getResults().put(o, result);

    jhoveTree2 = characteriseJHove(result);
  }
  /**
   * evaluates the given leaves automatically. This is only possible for criteria, where information
   * on the measurement has been defined. The registered evaluators are applied one after an other,
   * if an evaluator is able to measure a criterion, its value is applied and the criterion is
   * excluded from further evaluation.
   *
   * <p>First per alternative all action related evaluators are called.
   *
   * <p>Then per alternative, for each sample object, all object/runtime related evaluators are
   * called.
   *
   * @param leaves
   */
  private void evaluateLeaves(List<Leaf> leaves) {
    clearLogBuffer();

    // we evaluate measurements and have to assign each result to the corresponding leaf: build a
    // map
    HashMap<MeasurementInfoUri, Leaf> measurementOfLeaf = new HashMap<MeasurementInfoUri, Leaf>();

    // list of measurements which shall be evaluated
    List<MeasurementInfoUri> allMeasurementsToEval = new LinkedList<MeasurementInfoUri>();

    for (Leaf l : leaves) {
      // measure this criterion automatically
      MeasurementInfoUri m = l.getMeasurementInfo().toMeasurementInfoUri();
      if ((m != null) && (m.getAsURI() != null)) {
        measurementOfLeaf.put(m, l);
        allMeasurementsToEval.add(m);
      }
    }

    try {
      // start evaluation:
      List<MeasurementInfoUri> measurementsToEval = new ArrayList<MeasurementInfoUri>();
      // first action evaluators
      List<IActionEvaluator> actionEvaluators = MiniRED.getInstance().getActionEvaluationSequence();
      for (Alternative alternative :
          selectedPlan.getAlternativesDefinition().getConsideredAlternatives()) {
        // we want to evaluate each property only once, by the evaluator with the highest priority
        measurementsToEval.clear();
        measurementsToEval.addAll(allMeasurementsToEval);
        for (IActionEvaluator evaluator : actionEvaluators) {
          Map<MeasurementInfoUri, Value> results =
              evaluator.evaluate(alternative, measurementsToEval, this);
          // apply all results
          for (MeasurementInfoUri m : results.keySet()) {
            Value value = results.get(m);
            if (value != null) {
              Leaf l = measurementOfLeaf.get(m);
              value.setScale(l.getScale());
              l.getValues(alternative.getName()).setValue(0, value);
            }
          }
          // exclude evaluated leaves from further evaluation
          measurementsToEval.removeAll(results.keySet());
        }
      }
      // then object evaluators
      List<IObjectEvaluator> objEvaluators = MiniRED.getInstance().getObjectEvaluationSequence();
      for (Alternative alternative :
          selectedPlan.getAlternativesDefinition().getConsideredAlternatives()) {
        // .. for all alternatives
        List<SampleObject> samples = selectedPlan.getSampleRecordsDefinition().getRecords();
        for (int i = 0; i < samples.size(); i++) {
          // we want to evaluate each property only once, by the evaluator with the highest priority
          measurementsToEval.clear();
          measurementsToEval.addAll(allMeasurementsToEval);

          for (IObjectEvaluator evaluator : objEvaluators) {
            DigitalObject r = alternative.getExperiment().getResults().get(samples.get(i));
            DigitalObject r2 = (r == null ? null : em.merge(r));
            try {
              Map<MeasurementInfoUri, Value> results =
                  evaluator.evaluate(
                      alternative, em.merge(samples.get(i)), r2, measurementsToEval, this);
              // apply all results
              for (MeasurementInfoUri m : results.keySet()) {
                Value value = results.get(m);
                if (value != null) {
                  Leaf l = measurementOfLeaf.get(m);
                  value.setScale(l.getScale());
                  // add evaluation result for the current result-object!
                  l.getValues(alternative.getName()).setValue(i, value);
                }
              }
              // exclude evaluated leaves from further evaluation
              measurementsToEval.removeAll(results.keySet());
            } catch (Exception e) {
              log.error("evaluator failed" + e.getMessage(), e);
              continue;
            }
          }
        }
      }
    } catch (Exception e) {
      log.error("Automated evaluation threw exception " + e.getMessage(), e);
      FacesMessages.instance()
          .add(FacesMessage.SEVERITY_ERROR, "Automated evaluation failed:" + e.getMessage());
      updateStatus("Automated evaluation threw exception " + e.getMessage());
    }
    Contexts.getEventContext().set("evaluationMessage", evaluationLogBuffer.toString());
  }