@DocumentedDefinition(value = "exclude test patients")
  public CohortDefinition getExcludeTestPatients() {
    PersonAttributeCohortDefinition personAttributeCohortDefinition =
        new PersonAttributeCohortDefinition();
    personAttributeCohortDefinition.setAttributeType(
        emrApiProperties.getTestPatientPersonAttributeType());
    // the method add value has a bug, using set values for now
    personAttributeCohortDefinition.setValues(Arrays.asList("true"));

    CompositionCohortDefinition excludeTestPatientsCohortDefinition =
        new CompositionCohortDefinition();
    excludeTestPatientsCohortDefinition.addSearch(
        "test", map((CohortDefinition) personAttributeCohortDefinition, ""));
    excludeTestPatientsCohortDefinition.setCompositionString("NOT test");
    return excludeTestPatientsCohortDefinition;
  }
 /**
  * Patients who were enrolled on the given programs (excluding transfers) between ${onOrAfter} and
  * ${onOrBefore}
  *
  * @param programs the programs
  * @return the cohort definition
  */
 public CohortDefinition enrolledExcludingTransfers(Program... programs) {
   CompositionCohortDefinition cd = new CompositionCohortDefinition();
   cd.setName("enrolled excluding transfers in program between dates");
   cd.addParameter(new Parameter("onOrAfter", "After Date", Date.class));
   cd.addParameter(new Parameter("onOrBefore", "Before Date", Date.class));
   cd.addSearch(
       "enrolled",
       ReportUtils.map(
           enrolled(programs), "enrolledOnOrAfter=${onOrAfter},enrolledOnOrBefore=${onOrBefore}"));
   cd.addSearch("transferIn", ReportUtils.map(transferredIn(), "onOrBefore=${onOrBefore}"));
   cd.addSearch(
       "completeProgram", ReportUtils.map(compltedProgram(), "completedOnOrBefore=${onOrBefore}"));
   cd.setCompositionString("enrolled AND NOT (transferIn OR completeProgram)");
   return cd;
 }
 /**
  * Patients who were enrolled on the given programs (excluding transfers) on ${onOrBefore}
  *
  * @param programs the programs
  * @return the cohort definition
  */
 public CohortDefinition enrolledExcludingTransfersOnDate(Program... programs) {
   CompositionCohortDefinition cd = new CompositionCohortDefinition();
   cd.setName("enrolled excluding transfers in program on date in this facility");
   cd.addParameter(new Parameter("onOrBefore", "Before Date", Date.class));
   cd.addSearch(
       "enrolled", ReportUtils.map(enrolled(programs), "enrolledOnOrBefore=${onOrBefore}"));
   cd.addSearch("transferIn", ReportUtils.map(transferredIn(), "onOrBefore=${onOrBefore}"));
   cd.setCompositionString("enrolled AND NOT transferIn");
   return cd;
 }
 /**
  * Patients who are female and at least 18 years old on ${effectiveDate}
  *
  * @return the cohort definition
  */
 public CohortDefinition femalesAgedAtLeast18() {
   CompositionCohortDefinition cd = new CompositionCohortDefinition();
   cd.setName("females aged at least 18");
   cd.addParameter(new Parameter("effectiveDate", "Effective Date", Date.class));
   cd.addSearch("females", ReportUtils.map(females()));
   cd.addSearch(
       "agedAtLeast18", ReportUtils.map(agedAtLeast(18), "effectiveDate=${effectiveDate}"));
   cd.setCompositionString("females AND agedAtLeast18");
   return cd;
 }
  public EvaluatedCohort evaluate(
      final CohortDefinition cohortDefinition, final EvaluationContext evaluationContext)
      throws EvaluationException {

    MohCohortDefinition mohCohortDefinition = (MohCohortDefinition) cohortDefinition;

    EncounterService service = Context.getEncounterService();
    ConceptService conceptService = Context.getConceptService();
    CohortDefinitionService definitionService = Context.getService(CohortDefinitionService.class);

    // limit to people with adult initial or return encounters
    EncounterCohortDefinition encounterCohortDefinition = new EncounterCohortDefinition();
    encounterCohortDefinition.addEncounterType(
        service.getEncounterType(ENCOUNTER_TYPE_ADULT_INITIAL));
    encounterCohortDefinition.addEncounterType(
        service.getEncounterType(ENCOUNTER_TYPE_ADULT_RETURN));
    encounterCohortDefinition.setLocationList(mohCohortDefinition.getLocationList());

    // find people who had adult encounters at this location
    Cohort encounterCohort =
        definitionService.evaluate(encounterCohortDefinition, evaluationContext);

    // TODO set these with GPs and a settings page
    Concept firstRapidConcept = conceptService.getConcept(FIRST_HIV_RAPID_TEST_QUALITATIVE_CONCEPT);
    Concept secondRapidConcept =
        conceptService.getConcept(SECOND_HIV_RAPID_TEST_QUALITATIVE_CONCEPT);
    Concept positiveConcept = conceptService.getConcept(POSITIVE_CONCEPT);

    // define search for all people who have rapid test positive results
    CodedObsCohortDefinition firstRapidCohortDefinition = new CodedObsCohortDefinition();
    firstRapidCohortDefinition.setTimeModifier(PatientSetService.TimeModifier.ANY);
    firstRapidCohortDefinition.setLocationList(mohCohortDefinition.getLocationList());
    firstRapidCohortDefinition.setQuestion(firstRapidConcept);
    firstRapidCohortDefinition.setOperator(SetComparator.IN);
    firstRapidCohortDefinition.setValueList(Arrays.asList(positiveConcept));

    // define search all people who have rapid test 2 positive results
    CodedObsCohortDefinition secondRapidCohortDefinition = new CodedObsCohortDefinition();
    secondRapidCohortDefinition.setTimeModifier(PatientSetService.TimeModifier.ANY);
    secondRapidCohortDefinition.setLocationList(mohCohortDefinition.getLocationList());
    secondRapidCohortDefinition.setQuestion(secondRapidConcept);
    secondRapidCohortDefinition.setOperator(SetComparator.IN);
    secondRapidCohortDefinition.setValueList(Arrays.asList(positiveConcept));

    // combine rapid test definitions
    CompositionCohortDefinition rapidCompositionCohortDefinition =
        new CompositionCohortDefinition();
    rapidCompositionCohortDefinition.addSearch(
        "PositiveFirstRapid", firstRapidCohortDefinition, null);
    rapidCompositionCohortDefinition.addSearch(
        "PositiveSecondRapid", secondRapidCohortDefinition, null);
    rapidCompositionCohortDefinition.setCompositionString(
        "PositiveFirstRapid OR PositiveSecondRapid");
    Cohort rapidCompositionCohort =
        definitionService.evaluate(rapidCompositionCohortDefinition, evaluationContext);

    // set age limits
    AgeCohortDefinition ageCohortDefinition = new AgeCohortDefinition();
    ageCohortDefinition.setMinAge(18);
    ageCohortDefinition.setMinAgeUnit(DurationUnit.MONTHS);
    ageCohortDefinition.setMaxAge(14);
    ageCohortDefinition.setMaxAgeUnit(DurationUnit.YEARS);

    // TODO set this concept with a GP and settings page
    Concept elisaConcept = conceptService.getConcept(HIV_ENZYME_IMMUNOASSAY_QUALITATIVE_CONCEPT);

    // define search for all people with a positive elisa evaluation
    CodedObsCohortDefinition elisaCohortDefinition = new CodedObsCohortDefinition();
    elisaCohortDefinition.setTimeModifier(PatientSetService.TimeModifier.ANY);
    elisaCohortDefinition.setLocationList(mohCohortDefinition.getLocationList());
    elisaCohortDefinition.setQuestion(elisaConcept);
    elisaCohortDefinition.setOperator(SetComparator.IN);
    elisaCohortDefinition.setValueList(Arrays.asList(positiveConcept));

    // find patients within age limits who had elisa positive results
    CompositionCohortDefinition elisaCompositionCohortDefinition =
        new CompositionCohortDefinition();
    elisaCompositionCohortDefinition.addSearch("PaediatricAge", ageCohortDefinition, null);
    elisaCompositionCohortDefinition.addSearch("PositiveElisa", elisaCohortDefinition, null);
    elisaCompositionCohortDefinition.setCompositionString("PaediatricAge AND PositiveElisa");
    Cohort elisaCompositionCohort =
        definitionService.evaluate(elisaCompositionCohortDefinition, evaluationContext);

    // Check for the elisa to make sure the elisa happened after 18 months
    PersonAttributeCohortDefinition personAttributeCohortDefinition =
        new PersonAttributeCohortDefinition();
    personAttributeCohortDefinition.setAttributeType(
        Context.getPersonService().getPersonAttributeTypeByName("Health Center"));
    personAttributeCohortDefinition.setValueLocations(mohCohortDefinition.getLocationList());

    // TODO use GPs and a settings page to configure these concepts
    Concept transferConcept = conceptService.getConcept("TRANSFER CARE TO OTHER CENTER");
    Concept withinConcept = conceptService.getConcept("AMPATH");
    Concept missedVisitConcept = conceptService.getConcept("REASON FOR MISSED VISIT");
    Concept transferVisitConcept = conceptService.getConcept("AMPATH CLINIC TRANSFER");

    // define transfer specifications
    CodedObsCohortDefinition transferCohortDefinition = new CodedObsCohortDefinition();
    transferCohortDefinition.setTimeModifier(PatientSetService.TimeModifier.ANY);
    transferCohortDefinition.setLocationList(mohCohortDefinition.getLocationList());
    transferCohortDefinition.setQuestion(transferConcept);
    transferCohortDefinition.setOperator(SetComparator.IN);
    transferCohortDefinition.setValueList(Arrays.asList(withinConcept));

    // find all people with proper health center location and a transfer
    CompositionCohortDefinition transferCompositionCohortDefinition =
        new CompositionCohortDefinition();
    transferCompositionCohortDefinition.addSearch(
        "HealthCenterAttribute", personAttributeCohortDefinition, null);
    transferCompositionCohortDefinition.addSearch(
        "TransferWithinAmpath", transferCohortDefinition, null);
    transferCompositionCohortDefinition.setCompositionString(
        "HealthCenterAttribute AND TransferWithinAmpath");
    Cohort transferCompositionCohort =
        definitionService.evaluate(transferCompositionCohortDefinition, evaluationContext);

    // define missed visits at this location
    CodedObsCohortDefinition missedVisitCohortDefinition = new CodedObsCohortDefinition();
    missedVisitCohortDefinition.setTimeModifier(PatientSetService.TimeModifier.ANY);
    missedVisitCohortDefinition.setLocationList(mohCohortDefinition.getLocationList());
    missedVisitCohortDefinition.setQuestion(missedVisitConcept);
    missedVisitCohortDefinition.setOperator(SetComparator.IN);
    missedVisitCohortDefinition.setValueList(Arrays.asList(transferVisitConcept));

    // find all people with defined health center and a missed visit
    CompositionCohortDefinition missedVisitCompositionCohortDefinition =
        new CompositionCohortDefinition();
    missedVisitCompositionCohortDefinition.addSearch(
        "HealthCenterAttribute", personAttributeCohortDefinition, null);
    missedVisitCompositionCohortDefinition.addSearch(
        "MissedVisitTransfer", missedVisitCohortDefinition, null);
    missedVisitCompositionCohortDefinition.setCompositionString(
        "HealthCenterAttribute AND MissedVisitTransfer");
    Cohort missedVisitCompositionCohort =
        definitionService.evaluate(missedVisitCompositionCohortDefinition, evaluationContext);

    // build the patientIds by combining all found patients
    Set<Integer> patientIds = new HashSet<Integer>();
    patientIds.addAll(encounterCohort.getMemberIds());
    patientIds.addAll(rapidCompositionCohort.getMemberIds());
    patientIds.addAll(elisaCompositionCohort.getMemberIds());
    patientIds.addAll(transferCompositionCohort.getMemberIds());
    patientIds.addAll(missedVisitCompositionCohort.getMemberIds());

    // find fake patients
    PersonAttributeCohortDefinition fakePatientCohortDefinition =
        new PersonAttributeCohortDefinition();
    fakePatientCohortDefinition.setAttributeType(
        Context.getPersonService().getPersonAttributeType(28));
    fakePatientCohortDefinition.setValues(Collections.singletonList("true"));
    Cohort fakePatientCohort =
        definitionService.evaluate(fakePatientCohortDefinition, evaluationContext);

    // remove fake patients from the list
    patientIds.removeAll(fakePatientCohort.getMemberIds());

    // build the cohort from the resulting list of patient ids
    return new EvaluatedCohort(new Cohort(patientIds), cohortDefinition, evaluationContext);
  }