/**
* The contents of this file are subject to the OpenMRS Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://license.openmrs.org
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* Copyright (C) OpenMRS, LLC. All Rights Reserved.
*/
package org.openmrs.module.reporting.indicator.evaluator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openmrs.Cohort;
import org.openmrs.annotation.Handler;
import org.openmrs.api.context.Context;
import org.openmrs.logic.LogicCriteria;
import org.openmrs.logic.LogicException;
import org.openmrs.logic.result.Result;
import org.openmrs.module.reporting.cohort.definition.service.CohortDefinitionService;
import org.openmrs.module.reporting.data.patient.EvaluatedPatientData;
import org.openmrs.module.reporting.data.patient.service.PatientDataService;
import org.openmrs.module.reporting.evaluation.EvaluationContext;
import org.openmrs.module.reporting.evaluation.EvaluationException;
import org.openmrs.module.reporting.indicator.CohortIndicator;
import org.openmrs.module.reporting.indicator.CohortIndicatorResult;
import org.openmrs.module.reporting.indicator.Indicator;
import org.openmrs.module.reporting.indicator.IndicatorResult;
import java.util.Date;
import java.util.Map;
/**
* Evaluates a CohortIndicator and produces a result of all dimensions to Numeric results
*/
@Handler(supports={CohortIndicator.class})
public class CohortIndicatorEvaluator implements IndicatorEvaluator {
protected Log log = LogFactory.getLog(this.getClass());
/**
* Default Constructor
*/
public CohortIndicatorEvaluator() {}
/**
* @see IndicatorEvaluator#evaluate(Indicator, EvaluationContext)
*/
public IndicatorResult evaluate(Indicator indicator, EvaluationContext context) throws EvaluationException {
CohortIndicator cid = (CohortIndicator) indicator;
CohortIndicatorResult result = new CohortIndicatorResult();
result.setContext(context);
result.setIndicator(cid);
CohortDefinitionService cds = Context.getService(CohortDefinitionService.class);
// Determine Base Cohort from LocationFilter and EvaluationContext base cohort
Cohort baseCohort = context.getBaseCohort();
if (cid.getLocationFilter() != null) {
try {
Cohort locationCohort = cds.evaluate(cid.getLocationFilter(), context);
if (baseCohort == null) {
baseCohort = locationCohort;
}
else {
baseCohort = Cohort.intersect(baseCohort, locationCohort);
}
} catch (Exception ex) {
throw new EvaluationException("locationFilter", ex);
}
}
// Set Definition Denominator and further restrict base cohort
if (cid.getDenominator() != null) {
try {
Cohort denominatorCohort = cds.evaluate(cid.getDenominator(), context);
if (baseCohort != null) {
denominatorCohort = Cohort.intersect(denominatorCohort, baseCohort);
}
baseCohort = new Cohort(denominatorCohort.getMemberIds());
result.setDenominatorCohort(denominatorCohort);
} catch (Exception ex) {
throw new EvaluationException("denominator", ex);
}
}
// Definition Cohort / Numerator
Cohort cohort;
try {
cohort = cds.evaluate(cid.getCohortDefinition(), context);
if (baseCohort != null) {
cohort = Cohort.intersect(cohort, baseCohort);
}
result.setCohort(cohort);
} catch (Exception ex) {
throw new EvaluationException("numerator/cohort", ex);
}
if (cid.getDataToAggregate() != null) {
try {
PatientDataService pds = Context.getService(PatientDataService.class);
EvaluatedPatientData patientData = pds.evaluate(cid.getDataToAggregate(), context);
for (Integer pId : patientData.getData().keySet()) {
result.addLogicResult(pId, (Number) patientData.getData().get(pId));
}
}
catch (Exception e) {
throw new EvaluationException("dataToAggregate: " + cid.getDataToAggregate(), e);
}
}
// Evaluate Logic Criteria
if (cid.getLogicExpression() != null) {
try {
LogicCriteria criteria = Context.getLogicService().parse(cid.getLogicExpression());
maybeSetIndexDate(criteria, context);
Map<Integer, Result> logicResults = Context.getLogicService().eval(cohort, criteria);
for (Integer memberId : logicResults.keySet()) {
result.addLogicResult(memberId, logicResults.get(memberId).toNumber());
}
}
catch(LogicException e) {
throw new EvaluationException("logic expression: " + cid.getLogicExpression(), e);
}
}
return result;
}
/**
* If context has a parameter called (in order) any of [indexDate, date, endDate, startDate] then
* the logic criteria's index date will be set to the value of that parameter.
*
* Note that criteria should be a LogicCriteria. I'm using reflection so this code works on both 1.5
* (where LogicCriteria is a class) and 1.6+ (where it's an interface)
*
* @param criteria
* @param context
*/
private static String[] possibilities = new String[] { "indexDate", "date", "endDate", "startDate" };
private void maybeSetIndexDate(Object criteria, EvaluationContext context) {
for (String p : possibilities) {
if (context.containsParameter(p)) {
Date date = (Date) context.getParameterValue(p);
try {
criteria.getClass().getMethod("asOf", Date.class).invoke(criteria, date);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
return;
}
}
}
}