@Override
  protected void addColumns(CohortReportDescriptor report, PatientDataSetDefinition dsd) {
    PatientIdentifierType upn =
        MetadataUtils.existing(
            PatientIdentifierType.class, HivMetadata._PatientIdentifierType.UNIQUE_PATIENT_NUMBER);
    DataDefinition identifierDefUpn =
        new ConvertedPatientDataDefinition(
            "identifier",
            new PatientIdentifierDataDefinition(upn.getName(), upn),
            new IdentifierConverter());

    PatientIdentifierType districtNo =
        MetadataUtils.existing(
            PatientIdentifierType.class, TbMetadata._PatientIdentifierType.DISTRICT_REG_NUMBER);
    DataDefinition identifierDefDn =
        new ConvertedPatientDataDefinition(
            "identifier",
            new PatientIdentifierDataDefinition(upn.getName(), districtNo),
            new IdentifierConverter());

    addStandardColumns(report, dsd);
    dsd.addColumn("Unique Patient Number", identifierDefUpn, "");
    dsd.addColumn("District Registration Number", identifierDefDn, "");
    dsd.addColumn(
        "Due date",
        new CalculationDataDefinition("Date Eligible", new NeedsTbSputumTestDateCalculation()),
        "",
        new CalculationResultConverter());
  }
  @Override
  protected void addColumns(CohortReportDescriptor report, PatientDataSetDefinition dsd) {
    PatientIdentifierType upn =
        MetadataUtils.existing(
            PatientIdentifierType.class, HivMetadata._PatientIdentifierType.UNIQUE_PATIENT_NUMBER);
    DataDefinition identifierDef =
        new ConvertedPatientDataDefinition(
            "identifier",
            new PatientIdentifierDataDefinition(upn.getName(), upn),
            new IdentifierConverter());

    addStandardColumns(report, dsd);
    dsd.addColumn("UPN", identifierDef, "");
    dsd.addColumn(
        "Death date",
        new CalculationDataDefinition("Death date", new DateOfDeathCalculation()),
        "",
        new CalculationResultConverter());
  }
  @RequestMapping(method = RequestMethod.POST)
  public void process(
      final @RequestParam(required = false, value = "cohort") Integer cohortId,
      final @RequestParam(required = true, value = "template") MultipartFile template,
      final HttpServletResponse response)
      throws IOException, EvaluationException {

    EvaluationContext context = new EvaluationContext();
    context.addParameterValue("currentDate", new Date());
    if (cohortId != null) {
      context.setBaseCohort(Context.getCohortService().getCohort(cohortId));
    }

    PatientDataSetDefinition definition = new PatientDataSetDefinition();

    definition.addColumn(
        "id", new PatientIdDataDefinition(), StringUtils.EMPTY, new ObjectFormatter());

    ListConverter listConverter = new ListConverter();
    listConverter.setMaxNumberOfItems(1);

    PatientIdentifierDataDefinition preferredIdentifier = new PatientIdentifierDataDefinition();
    preferredIdentifier.addType(Context.getPatientService().getPatientIdentifierType(1));
    definition.addColumn("identifier", preferredIdentifier, StringUtils.EMPTY, listConverter);

    definition.addColumn(
        "name",
        new PreferredNameDataDefinition(),
        StringUtils.EMPTY,
        new ObjectFormatter("{familyName}, {givenName}"));

    AgeDataDefinition ageOnDate = new AgeDataDefinition();
    ageOnDate.addParameter(new Parameter("effectiveDate", "effective date", Date.class));
    definition.addColumn("age", ageOnDate, "effectiveDate=${currentDate}", new AgeConverter());

    definition.addColumn(
        "birthdate",
        new BirthdateDataDefinition(),
        StringUtils.EMPTY,
        new BirthdateConverter("dd-MMM-yyyy"));
    definition.addColumn(
        "gender", new GenderDataDefinition(), StringUtils.EMPTY, new ObjectFormatter());

    ReportDefinition reportDefinition = new ReportDefinition();
    reportDefinition.setName("Test Report");
    reportDefinition.addDataSetDefinition("PatientDataSetDefinition", definition, null);

    final ReportDesign design = new ReportDesign();
    design.setName("Test Report Design With Excel Template Renderer");
    design.setReportDefinition(reportDefinition);
    design.setRendererType(ExcelTemplateRenderer.class);

    Properties properties = new Properties();
    properties.put("repeatingSections", "sheet:1,dataset:PatientDataSetDefinition");
    design.setProperties(properties);

    ReportDesignResource resource = new ReportDesignResource();
    resource.setName("excel-template.xls");
    InputStream inputStream = template.getInputStream();
    resource.setContents(IOUtils.toByteArray(inputStream));
    IOUtils.closeQuietly(inputStream);
    design.addResource(resource);

    ExcelTemplateRenderer renderer =
        new ExcelTemplateRenderer() {
          public ReportDesign getDesign(String argument) {
            return design;
          }
        };

    ReportDefinitionService rs = Context.getService(ReportDefinitionService.class);
    ReportData data = rs.evaluate(reportDefinition, context);

    CsvReportRenderer csvReportRenderer = new CsvReportRenderer();
    csvReportRenderer.render(data, "output:csv", System.out);

    File file = File.createTempFile("excel", "summary");
    BufferedOutputStream bufferedOutputStream =
        new BufferedOutputStream(new FileOutputStream(file));
    renderer.render(data, "output:xls", bufferedOutputStream);
    bufferedOutputStream.close();

    response.setHeader("Content-Disposition", "attachment; filename=patient-summary.xls");
    response.setContentType("application/vnd.ms-excel");
    response.setContentLength((int) file.length());

    FileCopyUtils.copy(new FileInputStream(file), response.getOutputStream());
    if (file.delete()) log.info("Temporary file deleted!");
  }
  /** @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;
  }
  /**
   * @see
   *     org.openmrs.module.kenyacore.report.builder.AbstractCohortReportBuilder#addColumns(CohortReportDescriptor,
   *     PatientDataSetDefinition)
   */
  @Override
  protected void addColumns(HybridReportDescriptor report, PatientDataSetDefinition dsd) {

    PatientIdentifierType upn =
        MetadataUtils.existing(
            PatientIdentifierType.class, HivMetadata._PatientIdentifierType.UNIQUE_PATIENT_NUMBER);
    DataDefinition identifierDef =
        new ConvertedPatientDataDefinition(
            "identifier",
            new PatientIdentifierDataDefinition(upn.getName(), upn),
            new IdentifierConverter());
    DataConverter nameFormatter = new ObjectFormatter("{familyName}, {givenName}");
    DataDefinition nameDef =
        new ConvertedPersonDataDefinition("name", new PreferredNameDataDefinition(), nameFormatter);

    dsd.setName("artCohortAnalysis");
    dsd.addColumn("id", new PatientIdDataDefinition(), "");
    dsd.addColumn("Name", nameDef, "");
    dsd.addColumn("UPN", identifierDef, "");
    dsd.addColumn(
        "Enrollment into care date",
        hivProgramEnrollment(),
        "onDate=${endDate}",
        new CalculationResultConverter());
    dsd.addColumn("DOB", new BirthdateDataDefinition(), "", new BirthdateConverter());
    dsd.addColumn(
        "DOB approx",
        new CalculationDataDefinition("DOB approx", new IsBirthDateApproximatedCalculation()),
        "",
        new CalculationResultConverter());
    dsd.addColumn(
        "Age at ART initiation",
        new CalculationDataDefinition("Age at ART initiation", new AgeAtARTInitiationCalculation()),
        "",
        new CalculationResultConverter());
    dsd.addColumn("Sex", new GenderDataDefinition(), "");
    dsd.addColumn("TI", ti(), "", new TransferInAndDateConverter("state"));
    dsd.addColumn("Date TI", ti(), "", new TransferInAndDateConverter("date"));
    dsd.addColumn("TO", to(report), "onDate=${endDate}", new TransferInAndDateConverter("state"));
    dsd.addColumn(
        "Date TO", to(report), "onDate=${endDate}", new TransferInAndDateConverter("date"));
    dsd.addColumn(
        "ARV Start Date",
        new CalculationDataDefinition("ARV Start Date", new DateARV1Calculation()),
        "",
        new CalculationResultConverter());
    dsd.addColumn(
        "Days from enrollment in care to ART Initiation",
        new CalculationDataDefinition(
            "Days from enrollment in care to ART Initiation",
            new DaysFromEnrollmentToArtInitiationCalculation()),
        "",
        new CalculationResultConverter());
    dsd.addColumn(
        "Days from ART eligibility to ART Initiation",
        fromEligibilityToArtStart(report),
        "onDate=${endDate}",
        new CalculationResultConverter());
    dsd.addColumn(
        "Date first medically eligible for ART",
        dateAndReasonFirstMedicallyEligibleForArtCalculation(report),
        "onDate=${endDate}",
        new MedicallyEligibleConverter("date"));
    dsd.addColumn(
        "Reason first medically eligible For ART",
        dateAndReasonFirstMedicallyEligibleForArtCalculation(report),
        "onDate=${endDate}",
        new MedicallyEligibleConverter("reason"));
    dsd.addColumn(
        "ART baseline CD4 count",
        baselineCd4(report),
        "onDate=${endDate}",
        new Cd4ValueAndDateConverter("value"));
    dsd.addColumn(
        "Date of ART baseline CD4 count",
        baselineCd4(report),
        "onDate=${endDate}",
        new Cd4ValueAndDateConverter("date"));
    dsd.addColumn(
        "Initial ART regimen",
        new CalculationDataDefinition("First ART regimen", new InitialArtRegimenCalculation()),
        "",
        new RegimenConverter());
    dsd.addColumn(
        "Current ART regimen",
        currentARTRegimen(report),
        "onDate=${endDate}",
        new ArtCohortRegimenConverter());
    dsd.addColumn(
        "Current ART line",
        currentARTRegimen(report),
        "onDate=${endDate}",
        new RegimenLineConverter());
    dsd.addColumn(
        "CD4 at end of follow up",
        currentCd4Count(report),
        "onDate=${endDate}",
        new CurrentCd4Converter("value"));
    dsd.addColumn(
        "CD4 at end of follow up date",
        currentCd4Count(report),
        "onDate=${endDate}",
        new CurrentCd4Converter("date"));
    dsd.addColumn(
        "Change in cd4 count",
        changeInCd4Count(report),
        "onDate=${endDate}",
        new ChangeInCd4Converter());
    dsd.addColumn(
        "Viral load at end of follow up",
        viralLoad(report),
        "onDate=${endDate}",
        new CurrentCd4Converter("value"));
    dsd.addColumn(
        "Date viral load at end of follow up",
        viralLoad(report),
        "onDate=${endDate}",
        new CurrentCd4Converter("date"));
    dsd.addColumn(
        "Viral suppression",
        viralSuppression(report),
        "onDate=${endDate}",
        new CalculationResultConverter());
    dsd.addColumn(
        "Date of Last visit",
        lastSeen(report),
        "onDate=${endDate}",
        new CalculationResultConverter());
    dsd.addColumn(
        "Date of expected next visit",
        nextAppointmentDate(report),
        "onDate=${endDate}",
        new CalculationResultConverter());
    dsd.addColumn(
        "Date of death", death(report), "onDate=${endDate}", new CalculationResultConverter());
    dsd.addColumn(
        "ART Outcomes",
        patientOutComes(report),
        "onDate=${endDate}",
        new CalculationResultConverter());
  }
  @Override
  public ReportDefinition getReportDefinition() {

    String nullString = null;
    ObjectFormatter nullStringConverter = new ObjectFormatter();
    MohCoreService service = Context.getService(MohCoreService.class);

    ReportDefinition report = new PeriodIndicatorReportDefinition();
    report.setName("MOH 361A Report");

    // set up the DSD
    PatientDataSetDefinition dsd = new PatientDataSetDefinition();
    dsd.setName("allPatients");

    // set up parameters
    Parameter facility = new Parameter();
    facility.setName("facility");
    facility.setType(MOHFacility.class);

    // add to report and data set definition
    report.addParameter(facility);
    dsd.addParameter(facility);

    // sort by serial number, then by date
    dsd.addSortCriteria("Transfer Status", SortCriteria.SortDirection.ASC);
    dsd.addSortCriteria("Date Chronic HIV Care Started", SortCriteria.SortDirection.ASC);
    dsd.addSortCriteria("Serial Number", SortCriteria.SortDirection.ASC);

    // set up the columns ...

    // patient id ... until we get this thing working proper
    dsd.addColumn("Person ID", new PersonIdDataDefinition(), nullString);

    // a. serial number
    dsd.addColumn("Serial Number", new SerialNumberDataDefinition(), "facility=${facility}");

    // b. date chronic HIV+ care started
    EnrollmentDateDataDefinition enrollmentDate = new EnrollmentDateDataDefinition();
    dsd.addColumn("Date Chronic HIV Care Started", enrollmentDate, nullString);

    // extra column to help understand reason for including in this cohort
    dsd.addColumn(
        "First Encounter Date At Facility",
        new FirstEncounterAtFacilityDataDefinition(),
        "facility=${facility}",
        new EncounterDatetimeConverter());

    // c. Unique Patient Number
    PatientIdentifierType pit = service.getCCCNumberIdentifierType();
    CohortRestrictedPatientIdentifierDataDefinition cccColumn =
        new CohortRestrictedPatientIdentifierDataDefinition("CCC", pit);
    cccColumn.setIncludeFirstNonNullOnly(true);
    dsd.addColumn("Unique Patient Number", cccColumn, nullString);

    // AMRS Universal ID
    CohortRestrictedPatientIdentifierDataDefinition uidColumn =
        new CohortRestrictedPatientIdentifierDataDefinition(
            "AMRS Universal ID", Context.getPatientService().getPatientIdentifierType(8));
    uidColumn.setIncludeFirstNonNullOnly(true);
    dsd.addColumn("AMRS Universal ID", uidColumn, nullString);

    // AMRS Medical Record Number
    CohortRestrictedPatientIdentifierDataDefinition mrnColumn =
        new CohortRestrictedPatientIdentifierDataDefinition(
            "AMRS Medical Record Number", Context.getPatientService().getPatientIdentifierType(3));
    mrnColumn.setIncludeFirstNonNullOnly(true);
    dsd.addColumn("AMRS Medical Record Number", mrnColumn, nullString);

    // d. Patient's Name
    dsd.addColumn("Name", new CohortRestrictedPreferredNameDataDefinition(), nullString);

    // e1. Date of Birth
    dsd.addColumn(
        "Date of Birth",
        new CohortRestrictedBirthdateDataDefinition(),
        nullString,
        new BirthdateConverter(MOHReportUtil.DATE_FORMAT));

    // e2. Age at Enrollment

    MappedData<EnrollmentDateDataDefinition> mappedDef =
        new MappedData<EnrollmentDateDataDefinition>();
    mappedDef.setParameterizable(enrollmentDate);
    mappedDef.addConverter(new DateConverter());
    CohortRestrictedAgeAtDateOfOtherDataDefinition ageAtEnrollment =
        new CohortRestrictedAgeAtDateOfOtherDataDefinition();
    ageAtEnrollment.setEffectiveDateDefinition(mappedDef);
    dsd.addColumn("Age at Enrollment", ageAtEnrollment, nullString, new DecimalAgeConverter(2));

    // f. Sex
    dsd.addColumn("Sex", new CohortRestrictedGenderDataDefinition(), nullString);

    // g. Entry point: From where?
    PersonAttributeType pat =
        Context.getPersonService()
            .getPersonAttributeTypeByName(MohEvaluableNameConstants.POINT_OF_HIV_TESTING);
    dsd.addColumn(
        "Entry Point",
        new CohortRestrictedPersonAttributeDataDefinition("entryPoint", pat),
        nullString,
        new EntryPointConverter());

    // h. Confirmed HIV+ Date
    dsd.addColumn("Confirmed HIV Date", enrollmentDate, nullString);

    //		// i. PEP Start / Stop Date
    //		LogicDataDefinition columnI = new LogicDataDefinition();
    //		columnI.setLogicQuery("\"MOH PEP Start Stop Date\"");
    //		dsd.addColumn("PEP Start / Stop Date", columnI, nullString);
    //
    //		// j. Reasons for PEP use:
    //		LogicDataDefinition columnJ = new LogicDataDefinition();
    //		columnJ.setLogicQuery("\"MOH Reasons For PEP\"");
    //		dsd.addColumn("Reasons for PEP Use", columnJ, nullString);

    // k. CTX startdate and stopdate:
    dsd.addColumn("CTX Start Stop Date", new CtxStartStopDataDefinition(), nullString);

    // l. Fluconazole startdate and stopdate
    dsd.addColumn(
        "Fluconazole Start Stop Date", new FluconazoleStartStopDataDefinition(), nullString);

    // m. TB treatment startdate and stopdate
    dsd.addColumn("TB Treatment Start Stop Date", new TbStartStopDataDefinition(), nullString);

    // n. Pregnancy Yes?, Due date, PMTCT refer
    dsd.addColumn(
        "Pregnancy EDD and Referral",
        new PmtctPregnancyDataDefinition(),
        nullString,
        new PMTCTDatesConverter());

    // o. LTFU / TO / Dead and date when the event occurred
    dsd.addColumn("LTFU TO DEAD", new LTFUTODeadDataDefinition(), nullString, nullStringConverter);

    // p. WHO clinical Stage and date
    dsd.addColumn(
        "WHO Clinical Stage",
        new FirstWHOStageDataDefinition(),
        nullString,
        new WHOStageAndDateConverter());

    // q. Date medically eligible for ART
    EligibilityForARTDataDefinition eligibility = new EligibilityForARTDataDefinition();
    dsd.addColumn(
        "Date Medically Eligible for ART",
        eligibility,
        nullString,
        new ARVPatientSnapshotDateConverter());

    // r. Reason Medically Eligible for ART
    dsd.addColumn(
        "Reason Medically Eligible for ART",
        eligibility,
        nullString,
        new ARVPatientSnapshotReasonConverter());

    // s. Date ART started (Transfer to ART register)
    dsd.addColumn("Date ART Started", new DateARTStartedDataDefinition(), nullString);

    // additional columns for troubleshooting
    LastHIVEncounterDataDefinition lastHIVEncounter = new LastHIVEncounterDataDefinition();
    dsd.addColumn(
        "Last HIV Encounter Date", lastHIVEncounter, nullString, new EncounterDatetimeConverter());
    dsd.addColumn(
        "Last HIV Encounter Location",
        lastHIVEncounter,
        nullString,
        new EncounterLocationConverter());

    // informative column for the destination clinics
    dsd.addColumn(
        "Last Return to Clinic Date",
        new LastRTCDateDataDefinition(),
        nullString,
        new ObsValueDatetimeConverter());

    // transfer status column (used for sorting, not needed in output)
    dsd.addColumn("Transfer Status", new TransferStatusDataDefinition(), nullString);

    Map<String, Object> mappings = new HashMap<String, Object>();
    mappings.put("facility", "${facility}");
    report.addDataSetDefinition(dsd, mappings);

    return report;
  }