package rules
import org.hl7.fhir.dstu3.model.QuestionnaireResponse
import org.hl7.fhir.dstu3.model.Questionnaire
import org.hl7.fhir.dstu3.model.ProcedureRequestServiceRequest
import org.hl7.fhir.dstu3.model.QuestionnaireResponse.QuestionnaireResponseItemComponent
import com.systematic.ehealth.automatedprocessing.ClinicalImpressionDTO
import com.systematic.ehealth.automatedprocessing.TaskDTO
import com.systematic.ehealth.automatedprocessing.CommunicationDTO
import com.systematic.ehealth.automatedprocessing.CodingDTO
import java.util.ArrayList
import java.util.Collection
import java.util.List
import java.util.Collections
import java.util.HashMap
import java.util.Map
import com.systematic.ehealth.exceptions.MismatchedInputException
global com.systematic.ehealth.automatedprocessing.AutomatedProcessingDTO ruleResult
function Map<String, List<String>> getRedTriggerMap() {
Map<String, List<String>> result = new HashMap<>();
result.put("http://ehealth.sundhed.dk/DefinedQuestion/f2199b4f-f454-414f-9b27-c1ab80f5ae48", List.of("En del", "Meget")); // S5.b
result.put("http://ehealth.sundhed.dk/DefinedQuestion/002efb9b-0efc-49c7-81d5-3f4542a5658f", List.of("En del", "Meget")); // S6.b
result.put("http://ehealth.sundhed.dk/DefinedQuestion/b9610f7d-df61-4988-8566-b58c1d3b9b14", List.of("En del", "Meget")); // S7.b
result.put("http://ehealth.sundhed.dk/DefinedQuestion/cf55d29c-eabd-4909-9824-69d4690f2332", List.of("Mørkt")); // S9.a
result.put("http://ehealth.sundhed.dk/DefinedQuestion/843302ef-6623-42f1-b4e3-95fcb74e3108", List.of("En del", "Meget")); // S10.b
return result;
}
function Map<String, List<String>> getYellowTriggerMap() {
Map<String, List<String>> result = new HashMap<>();
result.put("http://ehealth.sundhed.dk/DefinedQuestion/1967378e-f98d-11ea-adc1-0242ac120002", List.of("Ja")); // S1.a
result.put("http://ehealth.sundhed.dk/DefinedQuestion/e66607e4-f99a-11ea-adc1-0242ac120002", List.of("Nej")); // S2.a
result.put("http://ehealth.sundhed.dk/DefinedQuestion/53ea7be9-0b26-41d1-aebb-5b73418d86ed", List.of("Lidt", "En del", "Meget")); // S5.a
result.put("http://ehealth.sundhed.dk/DefinedQuestion/f2199b4f-f454-414f-9b27-c1ab80f5ae48", List.of("Lidt")); // S5.b
result.put("http://ehealth.sundhed.dk/DefinedQuestion/caccac4a-9632-4eb1-9266-c4cdccfa1b57", List.of("Lidt", "En del", "Meget")); // S6.a
result.put("http://ehealth.sundhed.dk/DefinedQuestion/002efb9b-0efc-49c7-81d5-3f4542a5658f", List.of("Lidt")); // S6.b
result.put("http://ehealth.sundhed.dk/DefinedQuestion/e4ab995c-f0c6-4a86-b505-9180a27bd04b", List.of("Lidt", "En del", "Meget")); // S7.a
result.put("http://ehealth.sundhed.dk/DefinedQuestion/b9610f7d-df61-4988-8566-b58c1d3b9b14", List.of("Lidt")); // S7.b
result.put("http://ehealth.sundhed.dk/DefinedQuestion/1c18e70e-c726-4a66-bf4c-a98877179cd7", List.of("Lidt", "En del", "Meget")); // S8.a
result.put("http://ehealth.sundhed.dk/DefinedQuestion/5221408a-22ea-46f0-aaaf-4d417ef9fc2a", List.of("Lidt", "En del", "Meget")); // S10.a
result.put("http://ehealth.sundhed.dk/DefinedQuestion/843302ef-6623-42f1-b4e3-95fcb74e3108", List.of("Lidt")); // S10.b
return result;
}
function void add(Map triggeredQuestionAnswers, String itemId, String answer) {
List<String> answers = (List<String>) triggeredQuestionAnswers.get(itemId);
if (answers == null) {
triggeredQuestionAnswers.put(itemId, List.of(answer));
} else {
answers.add(answer);
}
}
function Map<String, List<String>> getTriggeredQuestionAnswers(QuestionnaireResponse.QuestionnaireResponseItemComponent item, Map triggerMap, Questionnaire q) {
Map<String, List<String>> triggers = (Map<String, List<String>>)triggerMap;
Map<String, List<String>> result = new HashMap<>();
String definition = getQuestionDefinition(q, item.getLinkId());
if (definition != null) {
definition = getVersionlessDefinition (definition);
List<String> answers = triggers.get(definition);
if (answers != null) {
for (QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent answer : item.getAnswer()) {
if (answer.hasValueBooleanType() && answers.contains(answer.getValueBooleanType().booleanValue() ? "true" : "false")) {
add(result, item.getLinkId(), answer.getValueBooleanType().booleanValue() ? "true" : "false");
} else if (answer.hasValueStringType() && answers.contains(answer.getValueStringType().getValue())) {
add(result, item.getLinkId(), answer.getValueStringType().getValue());
}
}
}
}
for (QuestionnaireResponse.QuestionnaireResponseItemComponent subItem : item.getItem()) {
result.putAll(getTriggeredQuestionAnswers(subItem, triggers, q));
}
return result;
}
function String getVersionlessDefinition(String definition) {
if (definition.contains("|")) {
return definition.substring(0,definition.indexOf("|"));
}
return definition;
}
function Map<String, List<String>> getAnswersMatchingInQuestionnaireResponse(QuestionnaireResponse qr, Map triggerMap, Questionnaire q) {
Map<String, List<String>> triggers = (Map<String, List<String>>)triggerMap;
Map<String, List<String>> result = new HashMap<>();
for (QuestionnaireResponse.QuestionnaireResponseItemComponent item : qr.getItem()) {
result.putAll(getTriggeredQuestionAnswers(item, triggers, q));
}
return result;
}
function String getQuestionTextFromItem(Questionnaire.QuestionnaireItemComponent item, String linkId) {
if (linkId.equals(item.getLinkId())) {
return item.getText();
}
for (Questionnaire.QuestionnaireItemComponent subItem : item.getItem()) {
String question = getQuestionTextFromItem(subItem, linkId);
if (question != null) {
return question;
}
}
return null;
}
function String getQuestionDefinitionFromItem(Questionnaire.QuestionnaireItemComponent item, String linkId) {
if (linkId.equals(item.getLinkId())) {
return item.getDefinition();
}
for (Questionnaire.QuestionnaireItemComponent subItem : item.getItem()) {
String definition = getQuestionDefinitionFromItem(subItem, linkId);
if (definition != null) {
return definition;
}
}
return null;
}
function String getQuestionText(Questionnaire questionnaire, String linkId) {
for (Questionnaire.QuestionnaireItemComponent item : questionnaire.getItem()) {
String question = getQuestionTextFromItem(item, linkId);
if (question != null) {
return question;
}
}
return null;
}
function String getQuestionDefinition(Questionnaire questionnaire, String linkId) {
for (Questionnaire.QuestionnaireItemComponent item : questionnaire.getItem()) {
String definition = getQuestionDefinitionFromItem(item, linkId);
if (definition != null) {
return definition;
}
}
return null;
}
function String getDescriptionFromMap( Map triggeredMap, Questionnaire questionnaire) {
Map<String, List<String>> answers = (Map<String, List<String>>)triggeredMap;
StringBuffer sb = new StringBuffer();
for (String linkId : answers.keySet()) {
if (sb.length() > 0) {
sb.append("\n");
}
sb.append(getQuestionText(questionnaire, linkId));
sb.append(": ");
List<String> answersList = answers.get(linkId);
for (int i = 0; i < answersList.size(); i++) {
if (i > 0) {
sb.append(", ");
}
sb.append(answersList.get(i));
}
}
return sb.toString();
}
function String getDescription(Map redAlarmAnswersMap, Map yellowAlarmAnswersMap, Questionnaire questionnaire) {
Map<String, List<String>> redAlarmAnswers = (Map<String, List<String>>)redAlarmAnswersMap;
StringBuffer sb = new StringBuffer();
if (!redAlarmAnswers.isEmpty()) {
sb.append("Der er rød alarm grundet følgende besvarelser af spørgsmål (givet som spørgsmål: svar)\n");
sb.append(getDescriptionFromMap(redAlarmAnswers, questionnaire));
}
Map<String, List<String>> yellowAlarmAnswers = (Map<String, List<String>>)yellowAlarmAnswersMap;
if (!yellowAlarmAnswers.isEmpty()) {
if (sb.length() > 0) {
sb.append("\n");
}
sb.append("Der er gul alarm grundet følgende besvarelser af spørgsmål (givet som spørgsmål: svar)\n");
sb.append(getDescriptionFromMap(yellowAlarmAnswers, questionnaire));
}
if (yellowAlarmAnswers.isEmpty() && redAlarmAnswers.isEmpty()) {
if (sb.length() > 0) {
sb.append("\n");
}
sb.append("Der er ingen røde eller gule alarmer.");
}
return sb.toString();
}
function List<CodingDTO> getFindings(Map redAlarmAnswersMap, Map yellowAlarmAnswersMap) {
List<CodingDTO> findings = new ArrayList<CodingDTO>();
if (!redAlarmAnswersMap.isEmpty()) {
findings.add(new CodingDTO("http://ehealth.sundhed.dk/cs/clinicalimpression-finding-codes", "red-question-answer", "Rød spørgsmål/svar-kombination fundet i spørgeskemabesvarelse"));
}
if (!yellowAlarmAnswersMap.isEmpty()) {
findings.add(new CodingDTO("http://ehealth.sundhed.dk/cs/clinicalimpression-finding-codes", "yellow-question-answer", "Gul spørgsmål/svar-kombination fundet i spørgeskemabesvarelse"));
}
if (yellowAlarmAnswersMap.isEmpty() && redAlarmAnswersMap.isEmpty()) {
findings.add(new CodingDTO("http://ehealth.sundhed.dk/cs/clinicalimpression-finding-codes", "green-question-answer", "Grøn spørgsmål/svar-kombination fundet i spørgeskemabesvarelse. Når anført som opsummering for hel spørgeskemabesvarelse er der ikke fundet røde eller gule spørgsmål/svar-kombinationer."));
}
return findings;
}
function TaskDTO createRoutineTask() {
CodingDTO taskCategory = new CodingDTO("http://ehealth.sundhed.dk/cs/task-category", "MeasurementForAssessment", "Need assessment of measurement");
String taskDescription = "Spørgeskemabesvarelse til evaluering";
String priority = "routine";
CodingDTO restrictionCategory = new CodingDTO("http://ehealth.sundhed.dk/cs/restriction-category", "measurement-monitoring", "Monitoring of measurement(s)");
return new TaskDTO(taskCategory, taskDescription, priority, List.of(restrictionCategory), Collections.emptyList());
}
function ClinicalImpressionDTO createClinicalImpression(String description, List findings, String priority) {
CodingDTO clinicalImpressionCode = new CodingDTO("http://ehealth.sundhed.dk/cs/clinicalimpression-codes", "TriagingResult", "Result of triaging");
ClinicalImpressionDTO clinicalImpressionDTO = new ClinicalImpressionDTO(clinicalImpressionCode, description, findings, List.of());
CodingDTO taskCategory = new CodingDTO("http://ehealth.sundhed.dk/cs/task-category", "MeasurementForAssessment", "Need assessment of measurement");
CodingDTO restrictionCategory = new CodingDTO("http://ehealth.sundhed.dk/cs/restriction-category", "measurement-monitoring", "Monitoring of measurement(s)");
clinicalImpressionDTO.setTasks(List.of(new TaskDTO(taskCategory, description, priority, List.of(restrictionCategory), Collections.emptyList())));
return clinicalImpressionDTO;
}
function String determinePriority(Map redAlarmAnswers, Map yellowAlarmAnswers) {
if (!redAlarmAnswers.isEmpty()) {
return "asap";
}
if (!yellowAlarmAnswers.isEmpty()) {
return "urgent";
}
return "routine";
}
function void throwMismatchedInputException(String ruleDescription, String focus) {
throw new MismatchedInputException(ruleDescription, focus);
}
rule "COPDQuestionnaireFUTTriageRule"
dialect "java"
when
$qrs : Collection()
$listQrs : ArrayList() from collect (QuestionnaireResponse() from $qrs)
$questionnaire : Questionnaire()
$procedureRequest$serviceRequest : ProcedureRequestServiceRequest()
then
if ($listQrs.isEmpty()) {
throwMismatchedInputException("Manglende input. Forventede én spørgeskemabesvarelse", $procedureRequest$serviceRequest.getId());
}
if ($listQrs.size() > 1) {
throwMismatchedInputException("Flere input. Forventede én spørgeskemabesvarelse", $procedureRequest$serviceRequest.getId());
}
QuestionnaireResponse qr = (QuestionnaireResponse)$listQrs.get(0);
Map<String, List<String>> redAlarmAnswers = getAnswersMatchingInQuestionnaireResponse(qr, getRedTriggerMap(), $questionnaire);
Map<String, List<String>> yellowAlarmAnswers = getAnswersMatchingInQuestionnaireResponse(qr, getYellowTriggerMap(), $questionnaire);
String taskPriority = determinePriority(redAlarmAnswers, yellowAlarmAnswers);
String description = getDescription(redAlarmAnswers, yellowAlarmAnswers, $questionnaire);
List<CodingDTO> findings = getFindings(redAlarmAnswers, yellowAlarmAnswers);
ruleResult.setClinicalImpressions(List.of(createClinicalImpression(description, findings, taskPriority)));
end; |