/** @should return patient data for each obs in the passed context */
  @Override
  public EvaluatedObsData evaluate(
      ObsDataDefinition definition, EvaluationContext obsEvaluationContext)
      throws EvaluationException {

    DataSetQueryService dqs = Context.getService(DataSetQueryService.class);
    EvaluatedObsData c = new EvaluatedObsData(definition, obsEvaluationContext);

    // create a map of obs ids -> patient ids (note assumption that personId = patientId)
    Set<Integer> obsIds = ObsDataUtil.getObsIdsForContext(obsEvaluationContext, true);
    Map<Integer, Integer> convertedIds =
        dqs.convertData(Person.class, "personId", null, Obs.class, "person.personId", obsIds);

    // create a new (patient) evaluation context using the retrieved ids
    EvaluationContext patientEvaluationContext = new EvaluationContext();
    patientEvaluationContext.setBaseCohort(new Cohort(convertedIds.values()));

    // evaluate the joined definition via this patient context
    PatientToObsDataDefinition def = (PatientToObsDataDefinition) definition;
    EvaluatedPatientData pd =
        Context.getService(PatientDataService.class)
            .evaluate(def.getJoinedDefinition(), patientEvaluationContext);

    // now create the result set by mapping the results in the patient data set to obs ids
    for (Integer obsId : obsIds) {
      c.addData(obsId, pd.getData().get(convertedIds.get(obsId)));
    }
    return c;
  }
  @Override
  public EvaluatedPersonData evaluate(PersonDataDefinition definition, EvaluationContext context)
      throws EvaluationException {

    FirstEncounterAtFacilityDataDefinition def =
        (FirstEncounterAtFacilityDataDefinition) definition;
    EvaluatedPersonData c = new EvaluatedPersonData(def, context);

    if (context.getBaseCohort() == null || context.getBaseCohort().isEmpty()) {
      return c;
    }

    // find the facility number
    MOHFacility facility = (MOHFacility) context.getParameterValue("facility");

    // fail quickly if the facility does not exist
    if (facility == null) {
      log.warn("No facility provided; returning empty data.");
      return c;
    }

    // use HQL to do our bidding
    String hql =
        "from Encounter"
            + " where voided=false"
            + " and patientId in (:patientIds)"
            + " and location in (:locationList)"
            + " and encounterDatetime <= :onOrBefore"
            + " order by encounterDatetime asc";

    Map<String, Object> m = new HashMap<String, Object>();
    m.put("patientIds", context.getBaseCohort());
    m.put("locationList", facility.getLocations());
    m.put("onOrBefore", context.getEvaluationDate());

    DataSetQueryService qs = Context.getService(DataSetQueryService.class);
    List<Object> queryResult = qs.executeHqlQuery(hql, m);

    ListMap<Integer, Encounter> encForPatients = new ListMap<Integer, Encounter>();
    for (Object o : queryResult) {
      Encounter enc = (Encounter) o;
      encForPatients.putInList(enc.getPatientId(), enc);
    }

    for (Integer pId : encForPatients.keySet()) {
      List<Encounter> l = encForPatients.get(pId);
      c.addData(pId, l.get(0));
    }

    return c;
  }