/**
   * @see org.openmrs.calculation.patient.PatientCalculation#evaluate(java.util.Collection,
   *     java.util.Map, org.openmrs.calculation.patient.PatientCalculationContext)
   */
  @Override
  public CalculationResultMap evaluate(
      Collection<Integer> cohort,
      Map<String, Object> parameterValues,
      PatientCalculationContext context) {

    Program mchcsProgram = MetadataUtils.getProgram(MchMetadata._Program.MCHCS);

    // Get all patients who are alive and in MCH-CS program
    Set<Integer> alive = Filters.alive(cohort, context);
    Set<Integer> inMchcsProgram = Filters.inProgram(mchcsProgram, alive, context);

    // get wheather the child is HIV Exposed
    CalculationResultMap lastChildHivStatus =
        Calculations.lastObs(
            Dictionary.getConcept(Dictionary.CHILDS_CURRENT_HIV_STATUS), inMchcsProgram, context);
    CalculationResultMap medOrdersObss =
        Calculations.allObs(Dictionary.getConcept(Dictionary.MEDICATION_ORDERS), cohort, context);

    // Get concepts for  medication prophylaxis
    Concept nvp = Dictionary.getConcept(Dictionary.NEVIRAPINE);
    Concept nvpazt3tc = Dictionary.getConcept(Dictionary.LAMIVUDINE_NEVIRAPINE_ZIDOVUDINE);
    Concept hivExposed = Dictionary.getConcept(Dictionary.EXPOSURE_TO_HIV);

    CalculationResultMap ret = new CalculationResultMap();

    for (Integer ptId : cohort) {
      boolean notOnPcp = false;

      // checking wheather the infant is in mchcs program, alive and HEI
      Obs hivStatusObs = EmrCalculationUtils.obsResultForPatient(lastChildHivStatus, ptId);
      if (inMchcsProgram.contains(ptId)
          && lastChildHivStatus != null
          && hivStatusObs != null
          && (hivStatusObs.getValueCoded().equals(hivExposed))) {
        notOnPcp = true;
        ListResult patientMedOrders = (ListResult) medOrdersObss.get(ptId);
        if (patientMedOrders != null) {
          // Look through list of medication order obs for any  CTX
          List<Obs> medOrderObsList = CalculationUtils.extractResultValues(patientMedOrders);
          for (Obs medOrderObs : medOrderObsList) {
            if (medOrderObs.getValueCoded().equals(nvp)
                || medOrderObs.getValueCoded().equals(nvpazt3tc)) {
              notOnPcp = false;
              break;
            }
          }
        }
      }
      ret.put(ptId, new BooleanResult(notOnPcp, this, context));
    }

    return ret;
  }
  /**
   * Patients who transferred in between ${onOrAfter} and ${onOrBefore}
   *
   * @return the cohort definition
   */
  public CohortDefinition transferredOut() {
    Concept reasonForDiscontinue =
        Dictionary.getConcept(Dictionary.REASON_FOR_PROGRAM_DISCONTINUATION);
    Concept transferredOut = Dictionary.getConcept(Dictionary.TRANSFERRED_OUT);

    CodedObsCohortDefinition cd = new CodedObsCohortDefinition();
    cd.addParameter(new Parameter("onOrBefore", "Before Date", Date.class));
    cd.addParameter(new Parameter("onOrAfter", "After Date", Date.class));
    cd.setName("transferred out between dates");
    cd.setTimeModifier(PatientSetService.TimeModifier.ANY);
    cd.setQuestion(reasonForDiscontinue);
    cd.setOperator(SetComparator.IN);
    cd.setValueList(Collections.singletonList(transferredOut));
    return cd;
  }
  /**
   * Evaluates the calculation
   *
   * @should calculate false for deceased patients
   * @should calculate false for patients not in HIV program
   * @should calculate false for patients with an encounter in last LOST_TO_FOLLOW_UP_THRESHOLD_DAYS
   *     days days since appointment date
   * @should calculate true for patient with no encounter in last LOST_TO_FOLLOW_UP_THRESHOLD_DAYS
   *     days days since appointment date
   */
  @Override
  public CalculationResultMap evaluate(
      Collection<Integer> cohort, Map<String, Object> arg1, PatientCalculationContext context) {

    Program hivProgram = MetadataUtils.existing(Program.class, HivMetadata._Program.HIV);
    Concept reasonForDiscontinuation =
        Dictionary.getConcept(Dictionary.REASON_FOR_PROGRAM_DISCONTINUATION);
    Concept transferout = Dictionary.getConcept(Dictionary.TRANSFERRED_OUT);

    Set<Integer> alive = Filters.alive(cohort, context);
    Set<Integer> inHivProgram = Filters.inProgram(hivProgram, alive, context);

    // CalculationResultMap lastEncounters = Calculations.lastEncounter(null, inHivProgram,
    // context);
    CalculationResultMap lastReturnDateObss =
        Calculations.lastObs(
            Dictionary.getConcept(Dictionary.RETURN_VISIT_DATE), inHivProgram, context);
    CalculationResultMap lastProgramDiscontinuation =
        Calculations.lastObs(reasonForDiscontinuation, cohort, context);

    CalculationResultMap ret = new CalculationResultMap();
    for (Integer ptId : cohort) {
      boolean lost = false;

      // Is patient alive and in the HIV program
      if (alive.contains(ptId)) {

        // Patient is lost if no encounters in last X days
        // Encounter lastEncounter = EmrCalculationUtils.encounterResultForPatient(lastEncounters,
        // ptId);
        Date lastScheduledReturnDate =
            EmrCalculationUtils.datetimeObsResultForPatient(lastReturnDateObss, ptId);
        Obs discontuation =
            EmrCalculationUtils.obsResultForPatient(lastProgramDiscontinuation, ptId);
        if (lastScheduledReturnDate != null) {
          if (daysSince(lastScheduledReturnDate, context)
              > HivConstants.LOST_TO_FOLLOW_UP_THRESHOLD_DAYS) {
            lost = true;
          }
          if (discontuation != null && discontuation.getValueCoded().equals(transferout)) {
            lost = false;
          }
        }
      }
      ret.put(ptId, new SimpleResult(lost, this, context));
    }
    return ret;
  }
  /**
   * Patients who transferred in between ${onOrAfter} and ${onOrBefore}
   *
   * @return the cohort definition
   */
  public CohortDefinition transferredIn() {
    Concept transferInDate = Dictionary.getConcept(Dictionary.TRANSFER_IN_DATE);

    DateObsValueBetweenCohortDefinition cd = new DateObsValueBetweenCohortDefinition();
    cd.setName("transferred in between dates");
    cd.setQuestion(transferInDate);
    cd.addParameter(new Parameter("onOrAfter", "After Date", Date.class));
    cd.addParameter(new Parameter("onOrBefore", "Before Date", Date.class));
    return cd;
  }
 /**
  * Patients who were dispensed the given medications between ${onOrAfter} and ${onOrBefore}
  *
  * @param concepts the drug concepts
  * @return the cohort definition
  */
 public CohortDefinition medicationDispensed(Concept... concepts) {
   CodedObsCohortDefinition cd = new CodedObsCohortDefinition();
   cd.setName("dispensed medication between");
   cd.addParameter(new Parameter("onOrAfter", "After Date", Date.class));
   cd.addParameter(new Parameter("onOrBefore", "Before Date", Date.class));
   cd.setTimeModifier(PatientSetService.TimeModifier.ANY);
   cd.setQuestion(Dictionary.getConcept(Dictionary.MEDICATION_ORDERS));
   cd.setValueList(Arrays.asList(concepts));
   cd.setOperator(SetComparator.IN);
   return cd;
 }
 Obs getLatestVlOrder(List<Obs> lstObs) {
   Obs latestObs = null;
   for (Obs o : lstObs) {
     if (o.getValueCoded() == Dictionary.getConcept(Dictionary.HIV_VIRAL_LOAD)) {
       if (latestObs == null) {
         latestObs = o;
       } else {
         if (o.getObsDatetime().after(latestObs.getObsDatetime())) {
           latestObs = o;
         }
       }
     }
   }
   return latestObs;
 }
  @Override
  public CalculationResultMap evaluate(
      Collection<Integer> cohort,
      Map<String, Object> parameterValues,
      PatientCalculationContext context) {
    //		Date date = (Date) parameterValues.get("date");
    //		if (date == null) {
    //			date = new Date();
    //		}

    if (parameterValues != null) {
      logger.info("Parameter Values is NOT null");
      logger.info(parameterValues.toString());
    } else {

      logger.info("Parameter Values is null");
    }
    Date date = new Date();

    Date startOfDay = DateUtil.getStartOfDay(date);
    Date endOfDay = DateUtil.getEndOfDay(date);
    Concept returnVisitDate = Dictionary.getConcept(Dictionary.RETURN_VISIT_DATE);
    // EncounterType tbFollowup = MetadataUtils.existing(EncounterType.class,
    // TbMetadata._EncounterType.TB_CONSULTATION);

    DateObsCohortDefinition cd = new DateObsCohortDefinition();
    cd.setTimeModifier(TimeModifier.ANY);
    cd.setQuestion(returnVisitDate);
    cd.setOperator1(RangeComparator.GREATER_EQUAL);
    cd.setValue1(startOfDay);
    cd.setOperator2(RangeComparator.LESS_EQUAL);
    cd.setValue2(endOfDay);
    // cd.setEncounterTypeList(Collections.singletonList(tbFollowup));

    EvaluatedCohort withScheduledVisit =
        CalculationUtils.evaluateWithReporting(cd, cohort, null, context);

    CalculationResultMap ret = new CalculationResultMap();

    for (Integer ptId : cohort) {
      ret.put(ptId, new BooleanResult(withScheduledVisit.contains(ptId), this));
    }

    return ret;
  }
  /**
   * @see DecliningCd4Calculation#evaluate(java.util.Collection, java.util.Map,
   *     org.openmrs.calculation.patient.PatientCalculationContext)
   * @verifies determine whether patients have a decline in CD4
   */
  @Test
  public void evaluate_shouldDetermineWhetherPatientsHasDeclinedCD4() throws Exception {

    // Get HIV Program
    Program hivProgram = Metadata.getProgram(Metadata.HIV_PROGRAM);

    // Enroll patients #6, #7 and #8 in the HIV Program
    PatientService ps = Context.getPatientService();
    for (int i = 6; i <= 8; ++i) {
      TestUtils.enrollInProgram(ps.getPatient(i), hivProgram, new Date());
    }

    // Give patients #7 and #8 a CD4 count 180 days ago
    Concept cd4 = Dictionary.getConcept(Dictionary.CD4_COUNT);
    Calendar calendar = Calendar.getInstance();
    calendar.add(Calendar.DATE, -180);
    TestUtils.saveObs(ps.getPatient(7), cd4, 123d, calendar.getTime());
    TestUtils.saveObs(ps.getPatient(8), cd4, 123d, calendar.getTime());

    // Give patient #7 a lower CD4 count today
    TestUtils.saveObs(ps.getPatient(7), cd4, 120d, new Date());

    // Give patient #8 a higher CD4 count today
    TestUtils.saveObs(ps.getPatient(8), cd4, 126d, new Date());

    Context.flushSession();

    List<Integer> ptIds = Arrays.asList(6, 7, 8, 999);

    CalculationResultMap resultMap =
        Context.getService(PatientCalculationService.class)
            .evaluate(ptIds, new DecliningCd4Calculation());
    Assert.assertFalse(
        (Boolean) resultMap.get(6).getValue()); // in Hiv program but without cd4 i.e needs cd4
    Assert.assertTrue((Boolean) resultMap.get(7).getValue()); // has decline in CD4
    Assert.assertFalse((Boolean) resultMap.get(8).getValue()); // has increase in CD4
    Assert.assertFalse((Boolean) resultMap.get(999).getValue()); // not in HIV Program
  }
  /**
   * @see EligibleForArtTriggerCalculation#evaluate(java.util.Collection, java.util.Map,
   *     org.openmrs.calculation.patient.PatientCalculationContext)
   * @verifies calculate the obs which triggered a patient to become eligible for ART
   * @verifies return null for patients who have never been eligible for ART
   */
  @Test
  public void evaluate_shouldCalculateEligibilityTrigger() throws Exception {

    PatientService ps = Context.getPatientService();

    // Confirm patient #6 HIV+ when they're 1 year old and give them very low CD4 soon after
    TestUtils.saveObs(
        ps.getPatient(6),
        Dictionary.getConcept(Dictionary.DATE_OF_HIV_DIAGNOSIS),
        TestUtils.date(2008, 05, 27),
        TestUtils.date(2010, 1, 1));
    TestUtils.saveObs(
        ps.getPatient(6),
        Dictionary.getConcept(Dictionary.CD4_COUNT),
        300.0,
        TestUtils.date(2009, 1, 1));

    // Give patient #7 low CD4 when they're 3 years old and very low CD4 after
    TestUtils.saveObs(
        ps.getPatient(7),
        Dictionary.getConcept(Dictionary.CD4_COUNT),
        900.0,
        TestUtils.date(1979, 8, 25));
    TestUtils.saveObs(
        ps.getPatient(7),
        Dictionary.getConcept(Dictionary.CD4_COUNT),
        300.0,
        TestUtils.date(2009, 1, 1));

    // Give patient #8 WHO stage of 3
    TestUtils.saveObs(
        ps.getPatient(8),
        Dictionary.getConcept(Dictionary.CURRENT_WHO_STAGE),
        Dictionary.getConcept(Dictionary.WHO_STAGE_3_PEDS),
        TestUtils.date(2009, 1, 1));

    Context.flushSession();

    List<Integer> cohort = Arrays.asList(6, 7, 8, 999);

    CalculationResultMap resultMap =
        new EligibleForArtTriggerCalculation()
            .evaluate(
                cohort,
                null,
                Context.getService(PatientCalculationService.class).createCalculationContext());

    Obs patient6Trigger = (Obs) resultMap.get(6).getValue(); // Eligible through HIV confirmation
    Assert.assertEquals(Dictionary.DATE_OF_HIV_DIAGNOSIS, patient6Trigger.getConcept().getUuid());
    Assert.assertEquals(TestUtils.date(2008, 05, 27), patient6Trigger.getValueDate());

    Obs patient7Trigger = (Obs) resultMap.get(7).getValue(); // Eligible through CD4 count
    Assert.assertEquals(Dictionary.CD4_COUNT, patient7Trigger.getConcept().getUuid());
    Assert.assertEquals(TestUtils.date(1979, 8, 25), patient7Trigger.getObsDatetime());

    Obs patient8Trigger = (Obs) resultMap.get(8).getValue(); // Eligible through WHO stage
    Assert.assertEquals(Dictionary.CURRENT_WHO_STAGE, patient8Trigger.getConcept().getUuid());
    Assert.assertEquals(TestUtils.date(2009, 1, 1), patient8Trigger.getObsDatetime());

    Assert.assertNull(resultMap.get(999)); // Was never eligible for ART
  }
  /**
   * Creates the ART data set
   *
   * @return the data set
   */
  private DataSetDefinition createArtDataSet() {
    CohortIndicatorDataSetDefinition dsd = new CohortIndicatorDataSetDefinition();
    dsd.setName("K");
    dsd.setDescription("ART");
    dsd.addParameter(new Parameter("startDate", "Start Date", Date.class));
    dsd.addParameter(new Parameter("endDate", "End Date", Date.class));
    dsd.addDimension(
        "age", ReportUtils.map(commonDimensions.standardAgeGroups(), "onDate=${endDate}"));
    dsd.addDimension("gender", ReportUtils.map(commonDimensions.gender()));

    ColumnParameters colFPeds =
        new ColumnParameters("FP", "0-14 years, female", "gender=F|age=<15");
    ColumnParameters colMPeds = new ColumnParameters("MP", "0-14 years, male", "gender=M|age=<15");
    ColumnParameters colFAdults =
        new ColumnParameters("FA", ">14 years, female", "gender=F|age=15+");
    ColumnParameters colMAdults = new ColumnParameters("MA", ">14 years, male", "gender=M|age=15+");
    ColumnParameters colFTotal = new ColumnParameters("F", "totals, female", "gender=F");
    ColumnParameters colMTotal = new ColumnParameters("M", "totals, male", "gender=M");
    ColumnParameters colTotal = new ColumnParameters("T", "grand total", "");

    Concept pmtct = Dictionary.getConcept(Dictionary.PMTCT_PROGRAM);
    Concept vct = Dictionary.getConcept(Dictionary.VCT_PROGRAM);
    Concept tb = Dictionary.getConcept(Dictionary.TUBERCULOSIS_TREATMENT_PROGRAM);
    Concept[] inpatient = {
      Dictionary.getConcept(Dictionary.PEDIATRIC_INPATIENT_SERVICE),
      Dictionary.getConcept(Dictionary.ADULT_INPATIENT_SERVICE)
    };
    Concept cwc = Dictionary.getConcept(Dictionary.UNDER_FIVE_CLINIC);
    Concept[] all = {pmtct, vct, tb, inpatient[0], inpatient[1], cwc};

    List<ColumnParameters> allColumns =
        Arrays.asList(colFPeds, colMPeds, colFAdults, colMAdults, colFTotal, colMTotal, colTotal);
    List<ColumnParameters> femaleColumns = Arrays.asList(colFPeds, colFAdults, colFTotal, colTotal);
    List<ColumnParameters> pedsColumns =
        Arrays.asList(colFPeds, colMPeds, colFTotal, colMTotal, colTotal);

    String indParams = "startDate=${startDate},endDate=${endDate}";

    EmrReportingUtils.addRow(
        dsd,
        "K1-1",
        "New enrollments - PMTCT",
        ReportUtils.map(artIndicators.enrolledExcludingTransfersAndReferredFrom(pmtct), indParams),
        femaleColumns);
    EmrReportingUtils.addRow(
        dsd,
        "K1-2",
        "New enrollments - VCT",
        ReportUtils.map(artIndicators.enrolledExcludingTransfersAndReferredFrom(vct), indParams),
        allColumns);
    EmrReportingUtils.addRow(
        dsd,
        "K1-3",
        "New enrollments - TB",
        ReportUtils.map(artIndicators.enrolledExcludingTransfersAndReferredFrom(tb), indParams),
        allColumns);
    EmrReportingUtils.addRow(
        dsd,
        "K1-4",
        "New enrollments - In Patient",
        ReportUtils.map(
            artIndicators.enrolledExcludingTransfersAndReferredFrom(inpatient), indParams),
        allColumns);
    EmrReportingUtils.addRow(
        dsd,
        "K1-5",
        "New enrollments - CWC",
        ReportUtils.map(artIndicators.enrolledExcludingTransfersAndReferredFrom(cwc), indParams),
        pedsColumns);
    EmrReportingUtils.addRow(
        dsd,
        "K1-6",
        "New enrollments - All others",
        ReportUtils.map(artIndicators.enrolledExcludingTransfersAndNotReferredFrom(all), indParams),
        allColumns);
    EmrReportingUtils.addRow(
        dsd,
        "K1-7",
        "New enrollments - Sub-total",
        ReportUtils.map(artIndicators.enrolledExcludingTransfers(), indParams),
        allColumns);
    EmrReportingUtils.addRow(
        dsd,
        "K2",
        "Cumulative enrolled",
        ReportUtils.map(artIndicators.enrolledCumulative(), indParams),
        allColumns);
    EmrReportingUtils.addRow(
        dsd,
        "K3-1",
        "Starting ARVs - WHO stage 1",
        ReportUtils.map(artIndicators.startedArtWithWhoStage(1), indParams),
        allColumns);
    EmrReportingUtils.addRow(
        dsd,
        "K3-2",
        "Starting ARVs - WHO stage 2",
        ReportUtils.map(artIndicators.startedArtWithWhoStage(2), indParams),
        allColumns);
    EmrReportingUtils.addRow(
        dsd,
        "K3-3",
        "Starting ARVs - WHO stage 3",
        ReportUtils.map(artIndicators.startedArtWithWhoStage(3), indParams),
        allColumns);
    EmrReportingUtils.addRow(
        dsd,
        "K3-4",
        "Starting ARVs - WHO stage 4",
        ReportUtils.map(artIndicators.startedArtWithWhoStage(4), indParams),
        allColumns);
    EmrReportingUtils.addRow(
        dsd,
        "K3-5",
        "Starting ARVs - Sub-total",
        ReportUtils.map(artIndicators.startedArt(), indParams),
        allColumns);
    EmrReportingUtils.addRow(
        dsd,
        "K4",
        "Cumulative started ARV",
        ReportUtils.map(artIndicators.startedArtCumulative(), indParams),
        allColumns);
    EmrReportingUtils.addRow(
        dsd,
        "K5-1",
        "Currently on ARVs - Pregnant women",
        ReportUtils.map(artIndicators.onArtAndPregnant(), indParams),
        femaleColumns);
    EmrReportingUtils.addRow(
        dsd,
        "K5-2",
        "Currently on ARVs - All others",
        ReportUtils.map(artIndicators.onArtAndNotPregnant(), indParams),
        allColumns);
    EmrReportingUtils.addRow(
        dsd,
        "K5-3",
        "Currently on ARVs - Sub-total",
        ReportUtils.map(artIndicators.onArt(), indParams),
        allColumns);
    EmrReportingUtils.addRow(
        dsd,
        "K6",
        "Eligible for ART",
        ReportUtils.map(artIndicators.eligibleForArt(), indParams),
        allColumns);
    // EmrReportingUtils.addRow(dsd, "K7-1", "Post-exposure prophylaxis..", map(???, indParams),
    // allColumns);
    // EmrReportingUtils.addRow(dsd, "K7-2", "Post-exposure prophylaxis..", map(???, indParams),
    // allColumns);
    // EmrReportingUtils.addRow(dsd, "K7-3", "Post-exposure prophylaxis..", map(???, indParams),
    // allColumns);
    // EmrReportingUtils.addRow(dsd, "K7-4", "Post-exposure prophylaxis..", map(???, indParams),
    // allColumns);
    EmrReportingUtils.addRow(
        dsd,
        "K8-1",
        "On prophylaxis - Cotrimoxazole",
        ReportUtils.map(artIndicators.onCotrimoxazoleProphylaxis(), indParams),
        allColumns);
    EmrReportingUtils.addRow(
        dsd,
        "K8-2",
        "On prophylaxis - Fluconazole",
        ReportUtils.map(artIndicators.onFluconazoleProphylaxis(), indParams),
        allColumns);
    EmrReportingUtils.addRow(
        dsd,
        "K8-3",
        "On prophylaxis - Sub-total",
        ReportUtils.map(artIndicators.onProphylaxis(), indParams),
        allColumns);

    return dsd;
  }
  @Override
  public CalculationResultMap evaluate(
      Collection<Integer> cohort,
      Map<String, Object> parameterValues,
      PatientCalculationContext context) {
    Program hivProgram = MetadataUtils.existing(Program.class, HivMetadata._Program.HIV);

    Set<Integer> alive = Filters.alive(cohort, context);
    Set<Integer> inHivProgram = Filters.inProgram(hivProgram, alive, context);

    Set<Integer> aliveAndFemale = Filters.female(Filters.alive(cohort, context), context);

    CalculationResultMap ret = new CalculationResultMap();

    // need to exclude those on ART already
    Set<Integer> onArt =
        CalculationUtils.patientsThatPass(calculate(new OnArtCalculation(), cohort, context));
    // find the observation for viral load recorded
    CalculationResultMap viralLoad =
        Calculations.lastObs(Dictionary.getConcept(Dictionary.HIV_VIRAL_LOAD), cohort, context);
    // get a list of all the viral load
    CalculationResultMap viralLoadList =
        Calculations.allObs(Dictionary.getConcept(Dictionary.HIV_VIRAL_LOAD), cohort, context);
    // check for non detectables
    CalculationResultMap ldlViralLoad =
        Calculations.allObs(
            Dictionary.getConcept(Dictionary.HIV_VIRAL_LOAD_QUALITATIVE), cohort, context);

    // check for test orders
    CalculationResultMap testOrders =
        Calculations.allObs(Dictionary.getConcept(Dictionary.TESTS_ORDERED), cohort, context);

    // check for last ldl
    CalculationResultMap ldlLast =
        Calculations.lastObs(
            Dictionary.getConcept(Dictionary.HIV_VIRAL_LOAD_QUALITATIVE), cohort, context);

    // find for prgnant females

    CalculationResultMap pregStatusObss =
        Calculations.lastObs(
            Dictionary.getConcept(Dictionary.PREGNANCY_STATUS), aliveAndFemale, context);

    // get the initial art start date
    CalculationResultMap artStartDate =
        calculate(new InitialArtStartDateCalculation(), cohort, context);

    for (Integer ptId : cohort) {
      boolean needsViralLoadTest = false;
      Obs viralLoadObs = EmrCalculationUtils.obsResultForPatient(viralLoad, ptId);
      Date dateInitiated = EmrCalculationUtils.datetimeResultForPatient(artStartDate, ptId);
      ListResult listResult = (ListResult) viralLoadList.get(ptId);
      ListResult testOrdersList = (ListResult) testOrders.get(ptId);
      List<Obs> testObsList = CalculationUtils.extractResultValues(testOrdersList);
      List<Obs> listObsViralLoads = CalculationUtils.extractResultValues(listResult);
      ListResult ldlList = (ListResult) ldlViralLoad.get(ptId);
      List<List> listLdl = CalculationUtils.extractResultValues(ldlList);
      Obs lastLdlObs = EmrCalculationUtils.obsResultForPatient(ldlLast, ptId);
      // find pregnancy obs
      Obs pregnantEdd = EmrCalculationUtils.obsResultForPatient(pregStatusObss, ptId);

      // Find latest viral load test order
      Obs lastVlTestOrder = getLatestVlOrder(testObsList);

      if (inHivProgram.contains(ptId) && onArt.contains(ptId)) {
        if (listObsViralLoads.size() == 0
            && listLdl.size() == 0
            && dateInitiated != null
            && (daysSince(dateInitiated, context) >= 180)) {
          needsViralLoadTest = true;
        }
        // need to check here if patient has had any viral load
        /*if(dateInitiated != null && (daysSince(dateInitiated, context) >= 360)) {
            needsViralLoadTest = true;
        }*/

        // those continuing should receive one VL every year
        // pick the date of the last viral load numeric values
        if (viralLoadObs != null && (daysSince(viralLoadObs.getObsDatetime(), context) >= 360)) {
          needsViralLoadTest = true;
        }
        // pick the date of the ldl
        if (lastLdlObs != null && (daysSince(lastLdlObs.getObsDatetime(), context) >= 360)) {
          needsViralLoadTest = true;
        }

        // if vl more than
        if (viralLoadObs != null
            && viralLoadObs.getValueNumeric() > 1000
            && (daysSince(viralLoadObs.getObsDatetime(), context) > 90)) {
          needsViralLoadTest = true;

          if (lastLdlObs != null && (daysSince(lastLdlObs.getObsDatetime(), context) < 360)) {
            needsViralLoadTest = false;
          }
        }

        // check for pregnancy
        if (pregnantEdd != null
            && pregnantEdd.getValueCoded().equals(Dictionary.getConcept(Dictionary.YES))
            && dateInitiated != null) {
          Date whenVLWillBeDue =
              DateUtil.adjustDate(
                  DateUtil.adjustDate(dateInitiated, 6, DurationUnit.MONTHS),
                  -1,
                  DurationUnit.DAYS);
          // if last vl is 6 months older then the patient is due for vl
          if (viralLoadObs == null && lastLdlObs == null) {
            needsViralLoadTest = true;
          }
          if (viralLoadObs == null
              && lastLdlObs == null
              && (context.getNow().after(whenVLWillBeDue))) {
            needsViralLoadTest = true;
          }
          if (viralLoadObs != null
              && viralLoadObs.getValueNumeric() > 1000
              && (monthsBetween(viralLoadObs.getObsDatetime(), context.getNow()) >= 3)) {
            needsViralLoadTest = true;
            if (lastLdlObs != null && (daysSince(lastLdlObs.getObsDatetime(), context) < 360)) {
              needsViralLoadTest = false;
            }
          }
          if (viralLoadObs != null && daysSince(viralLoadObs.getObsDatetime(), context) >= 180) {
            needsViralLoadTest = true;
          }
          if (lastLdlObs != null && daysSince(lastLdlObs.getObsDatetime(), context) >= 180) {
            needsViralLoadTest = true;
          }
        }

        // check if has vl test order within 6 months
        if (lastVlTestOrder != null
            && daysSince(lastVlTestOrder.getObsDatetime(), context) >= 180) {
          needsViralLoadTest = true;
        }

        if (lastVlTestOrder != null && daysSince(lastVlTestOrder.getObsDatetime(), context) < 180) {
          needsViralLoadTest = false;
        }
      }

      ret.put(ptId, new BooleanResult(needsViralLoadTest, this));
    }
    return ret;
  }