/** @see DataSetEvaluator#evaluate(DataSetDefinition, EvaluationContext) */
  @SuppressWarnings("unchecked")
  public DataSet evaluate(DataSetDefinition dataSetDefinition, EvaluationContext context)
      throws EvaluationException {

    PatientDataSetDefinition dsd = (PatientDataSetDefinition) dataSetDefinition;
    context = ObjectUtil.nvl(context, new EvaluationContext());

    SimpleDataSet dataSet = new SimpleDataSet(dsd, context);
    dataSet.setSortCriteria(dsd.getSortCriteria());

    // Construct a new EvaluationContext based on the passed filters
    Cohort c = context.getBaseCohort();
    if (dsd.getRowFilters() != null) {
      for (Mapped<? extends CohortDefinition> q : dsd.getRowFilters()) {
        Cohort s = Context.getService(CohortDefinitionService.class).evaluate(q, context);
        c = CohortUtil.intersectNonNull(c, s);
      }
    }
    if (c == null) {
      c =
          Context.getService(CohortDefinitionService.class)
              .evaluate(new AllPatientsCohortDefinition(), context);
    }

    EvaluationContext ec = context.shallowCopy();
    if (!CohortUtil.areEqual(ec.getBaseCohort(), c)) {
      ec.setBaseCohort(c);
    }

    // Evaluate each specified ColumnDefinition for all of the included rows and add these to the
    // dataset
    for (RowPerObjectColumnDefinition cd : dsd.getColumnDefinitions()) {

      if (log.isDebugEnabled()) {
        log.debug("Evaluating column: " + cd.getName());
        log.debug(
            "With Data Definition: "
                + DefinitionUtil.format(cd.getDataDefinition().getParameterizable()));
        log.debug("With Mappings: " + cd.getDataDefinition().getParameterMappings());
        log.debug("With Parameters: " + ec.getParameterValues());
      }
      StopWatch sw = new StopWatch();
      sw.start();

      MappedData<? extends PatientDataDefinition> dataDef =
          (MappedData<? extends PatientDataDefinition>) cd.getDataDefinition();
      EvaluatedPatientData data =
          Context.getService(PatientDataService.class).evaluate(dataDef, ec);

      for (Integer id : c.getMemberIds()) {
        for (DataSetColumn column : cd.getDataSetColumns()) {
          Object val = data.getData().get(id);
          val = DataUtil.convertData(val, dataDef.getConverters());
          dataSet.addColumnValue(id, column, val);
        }
      }

      sw.stop();
      if (log.isDebugEnabled()) {
        log.debug("Evaluated column. Duration: " + sw.toString());
      }
    }

    return dataSet;
  }