package org.ei.drishti.service;
import org.ei.drishti.common.AllConstants;
import org.ei.drishti.domain.Child;
import org.ei.drishti.domain.Mother;
import org.ei.drishti.form.domain.FormSubmission;
import org.ei.drishti.form.domain.SubFormData;
import org.ei.drishti.repository.AllChildren;
import org.ei.drishti.repository.AllMothers;
import org.ei.drishti.service.formSubmission.handler.ReportFieldsDefinition;
import org.ei.drishti.service.reporting.ChildReportingService;
import org.ei.drishti.service.scheduling.ChildSchedulesService;
import org.ei.drishti.util.SafeMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static java.util.Arrays.asList;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.ei.drishti.common.AllConstants.ANCFormFields.*;
import static org.ei.drishti.common.AllConstants.ChildImmunizationFields.*;
import static org.ei.drishti.common.AllConstants.ChildRegistrationFormFields.*;
import static org.ei.drishti.common.AllConstants.CommonFormFields.*;
import static org.ei.drishti.common.AllConstants.DeliveryOutcomeFields.DELIVERY_PLACE;
import static org.ei.drishti.common.AllConstants.DeliveryOutcomeFields.DID_BREAST_FEEDING_START;
import static org.ei.drishti.common.AllConstants.PNCVisitFormFields.URINE_STOOL_PROBLEMS;
import static org.ei.drishti.common.AllConstants.VitaminAFields.VITAMIN_A_DOSE_PREFIX;
@Service
public class ChildService {
public static final String IMMUNIZATIONS_SEPARATOR = " ";
private static Logger logger = LoggerFactory.getLogger(ChildService.class.toString());
private ChildSchedulesService childSchedulesService;
private AllMothers allMothers;
private AllChildren allChildren;
private ChildReportingService childReportingService;
private ActionService actionService;
private ReportFieldsDefinition reportFieldsDefinition;
@Autowired
public ChildService(ChildSchedulesService childSchedulesService,
AllMothers allMothers,
AllChildren allChildren,
ChildReportingService childReportingService, ActionService actionService, ReportFieldsDefinition reportFieldsDefinition) {
this.childSchedulesService = childSchedulesService;
this.allMothers = allMothers;
this.allChildren = allChildren;
this.childReportingService = childReportingService;
this.actionService = actionService;
this.reportFieldsDefinition = reportFieldsDefinition;
}
public void registerChildren(FormSubmission submission) {
Mother mother = allMothers.findByCaseId(submission.entityId());
if (mother == null) {
logger.warn("Failed to handle children registration as there is no mother registered with id: " + submission.entityId());
return;
}
SubFormData subFormData = submission.getSubFormByName(AllConstants.DeliveryOutcomeFields.CHILD_REGISTRATION_SUB_FORM_NAME);
if (handleStillBirth(submission, subFormData)) return;
String referenceDate = submission.getField(REFERENCE_DATE);
for (Map<String, String> childFields : subFormData.instances()) {
Child child = allChildren.findByCaseId(childFields.get(ID));
List<String> immunizationsGiven = getNamesOfImmunizationsGiven(childFields.get(IMMUNIZATIONS_GIVEN_FIELD_NAME));
child = child.withAnm(submission.anmId()).withDateOfBirth(referenceDate)
.withThayiCard(mother.thayiCardNumber()).setIsClosed(false)
.withImmunizations(getChildImmunizationDetails(submission, child, immunizationsGiven));
allChildren.update(child);
SafeMap reportingData = new SafeMap();
reportingData.put(ChildReportingService.CHILD_ID_FIELD, child.caseId());
reportingData.put(DELIVERY_PLACE, submission.getField(DELIVERY_PLACE));
reportingData.put(BF_POSTBIRTH, submission.getField(DID_BREAST_FEEDING_START));
reportingData.put(REGISTRATION_DATE, referenceDate);
reportingData.put(SUBMISSION_DATE_FIELD_NAME, submission.getField(SUBMISSION_DATE_FIELD_NAME));
childReportingService.registerChild(reportingData);
childSchedulesService.enrollChild(child);
}
}
private ArrayList<String> split(String immunizationsGivenField) {
return new ArrayList<>(asList(immunizationsGivenField.split(IMMUNIZATIONS_SEPARATOR)));
}
private boolean isDeliveryOutcomeStillBirth(FormSubmission submission) {
return AllConstants.DeliveryOutcomeFields.STILL_BIRTH_VALUE.equalsIgnoreCase(submission.getField(AllConstants.DeliveryOutcomeFields.DELIVERY_OUTCOME));
}
public void registerChildrenForEC(FormSubmission submission) {
if (shouldCloseMother(submission.getField(SHOULD_CLOSE_MOTHER))) {
closeMother(submission.getField(MOTHER_ID));
}
Child child = allChildren.findByCaseId(submission.getField(ChildReportingService.CHILD_ID_FIELD));
child.withAnm(submission.anmId()).withThayiCard(submission.getField(THAYI_CARD_NUMBER)).setIsClosed(false);
List<String> immunizationsGiven = getNamesOfImmunizationsGiven(submission.getField(IMMUNIZATIONS_GIVEN_FIELD_NAME));
List<String> vitaminHistory = getVitaminDoses(submission.getField("childVitaminAHistory"));
child.withImmunizations(getChildImmunizationDetails(submission, child, immunizationsGiven));
child.withVitaminADoses(getVitaminDoseDetails(submission, child, vitaminHistory));
allChildren.update(child);
childSchedulesService.enrollChild(child);
}
private void closeMother(String field) {
Mother mother = allMothers.findByCaseId(field);
mother.setIsClosed(true);
allMothers.update(mother);
}
private boolean shouldCloseMother(String shouldCloseMother) {
return isBlank(shouldCloseMother) || Boolean.parseBoolean(shouldCloseMother);
}
private Map<String, String> getVitaminDoseDetails(FormSubmission submission, Child child, List<String> vitaminHistory) {
Map<String, String> vitaminDoses = child.vitaminADoses() == null
? new HashMap<String, String>()
: child.vitaminADoses();
for (String vitamin : vitaminHistory) {
vitaminDoses.put(VITAMIN_A_DOSE_PREFIX + vitamin, getVitaminDate(submission, vitamin));
}
return vitaminDoses;
}
private ArrayList<String> getVitaminDoses(String vitaminDoses) {
return isBlank(vitaminDoses)
? new ArrayList<String>()
: split(vitaminDoses);
}
private String getVitaminDate(FormSubmission submission, String vitaminDose) {
return submission.getField(VITAMIN + vitaminDose + DATE);
}
public void registerChildrenForOA(FormSubmission submission) {
Child child = allChildren.findByCaseId(submission.getField(ID));
child.withAnm(submission.anmId()).withThayiCard(submission.getField(THAYI_CARD_NUMBER));
List<String> immunizationsGiven = getNamesOfImmunizationsGiven(submission.getField(IMMUNIZATIONS_GIVEN_FIELD_NAME));
List<String> vitaminHistory = getVitaminDoses(submission.getField(CHILD_VITAMIN_A_HISTORY));
child.withImmunizations(getChildImmunizationDetails(submission, child, immunizationsGiven));
child.withVitaminADoses(getVitaminDoseDetails(submission, child, vitaminHistory));
allChildren.update(child);
childSchedulesService.enrollChild(child);
}
public void updateChildImmunization(FormSubmission submission) {
Child child = allChildren.findByCaseId(submission.entityId());
if (child == null) {
logger.warn("Found immunization update without registered child for entity ID: " + submission.entityId());
return;
}
String previousImmunizationsField = isBlank(submission.getField(PREVIOUS_IMMUNIZATIONS_FIELD_NAME))
? "" : submission.getField(PREVIOUS_IMMUNIZATIONS_FIELD_NAME);
List<String> previousImmunizations = asList(previousImmunizationsField.split(IMMUNIZATIONS_SEPARATOR));
List<String> immunizationsGiven = getNamesOfImmunizationsGiven(submission.getField(IMMUNIZATIONS_GIVEN_FIELD_NAME));
immunizationsGiven.removeAll(previousImmunizations);
child.withImmunizations(getChildImmunizationDetails(submission, child, immunizationsGiven));
allChildren.update(child);
SafeMap reportFieldsMap = new SafeMap(submission.getFields(reportFieldsDefinition.get(submission.formName())));
childReportingService.immunizationProvided(reportFieldsMap, previousImmunizations);
childSchedulesService.updateEnrollments(submission.entityId(), previousImmunizations);
}
private Map<String, String> getChildImmunizationDetails(FormSubmission submission, Child child, List<String> immunizationsGiven) {
Map<String, String> immunizations = child.immunizations() == null
? new HashMap<String, String>()
: child.immunizations();
for (String immunization : immunizationsGiven) {
immunizations.put(immunization, getImmunizationDate(submission, immunization));
}
return immunizations;
}
private String getImmunizationDate(FormSubmission submission, String immunization) {
String immunizationDateField = immunizationDateForImmunizationFromChildRegistrationEC(submission, immunization);
//For Child OA and Child registration EC
if (immunizationDateField != null)
return immunizationDateField;
if (submission.getField(IMMUNIZATION_DATE_FIELD_NAME) != null)
return submission.getField(IMMUNIZATION_DATE_FIELD_NAME);
return submission.getField(SUBMISSION_DATE_FIELD_NAME);
}
private String immunizationDateForImmunizationFromChildRegistrationEC(FormSubmission submission, String immunization) {
String immunizationDateField = immunization.replace("_", "") + "Date";
return submission.getField(immunizationDateField);
}
private List<String> getNamesOfImmunizationsGiven(String immunizationsGiven) {
return isBlank(immunizationsGiven)
? new ArrayList<String>()
: split(immunizationsGiven);
}
public void vitaminAProvided(FormSubmission submission) {
Child child = allChildren.findByCaseId(submission.entityId());
if (child == null) {
logger.warn("Found that Vitamin A was provided to a not registered child with entity ID: " + submission.entityId());
return;
}
updateVitaminDetailsToChildEntity(submission, child);
SafeMap reportFieldsMap = new SafeMap(submission.getFields(reportFieldsDefinition.get(submission.formName())));
childReportingService.vitaminAProvided(reportFieldsMap);
}
private void updateVitaminDetailsToChildEntity(FormSubmission submission, Child child) {
String vitaminADose = submission.getField("vitaminADose");
String vitaminADate = submission.getField("vitaminADate");
Map<String, String> vitaminDoses = child.vitaminADoses() == null
? new HashMap<String, String>()
: child.vitaminADoses();
vitaminDoses.put(VITAMIN_A_DOSE_PREFIX + vitaminADose, vitaminADate);
allChildren.update(child.withVitaminADoses(vitaminDoses));
}
public void closeChild(FormSubmission submission) {
if (!allChildren.childExists(submission.entityId())) {
logger.warn("Found close child request without registered child for entity id: " + submission.entityId());
return;
}
allChildren.close(submission.entityId());
actionService.markAllAlertsAsInactive(submission.entityId());
SafeMap reportFieldsMap = new SafeMap(submission.getFields(reportFieldsDefinition.get(submission.formName())));
childReportingService.closeChild(reportFieldsMap);
childSchedulesService.unenrollChild(submission.entityId());
}
public void pncOAChildRegistration(FormSubmission submission) {
List<Mother> mothers = allMothers.findByEcCaseId(submission.entityId());
if (mothers.size() <= 0) {
logger.warn("Failed to handle PNC OA children registration as there is no mother registered with id: " + submission.entityId());
return;
}
Mother mother = mothers.get(0);
allMothers.update(mother.withAnm(submission.anmId()));
SubFormData subFormData = submission.getSubFormByName(AllConstants.Form.PNC_REGISTRATION_OA_SUB_FORM_NAME);
if (handleStillBirth(submission, subFormData)) return;
String referenceDate = submission.getField(REFERENCE_DATE);
for (Map<String, String> childFields : subFormData.instances()) {
Child child = allChildren.findByCaseId(childFields.get(ID));
List<String> immunizationsGiven = getNamesOfImmunizationsGiven(childFields.get(IMMUNIZATIONS_GIVEN_FIELD_NAME));
child = child.withAnm(submission.anmId())
.withDateOfBirth(referenceDate)
.withThayiCard(mother.thayiCardNumber())
.setIsClosed(false)
.withImmunizations(getChildImmunizationDetails(submission, child, immunizationsGiven));
allChildren.update(child);
SafeMap reportingData = new SafeMap();
reportingData.put(ChildReportingService.CHILD_ID_FIELD, child.caseId());
reportingData.put(DELIVERY_PLACE, submission.getField(DELIVERY_PLACE));
reportingData.put(BF_POSTBIRTH, childFields.get(DID_BREAST_FEEDING_START));
reportingData.put(REGISTRATION_DATE, referenceDate);
reportingData.put(SUBMISSION_DATE_FIELD_NAME, submission.getField(SUBMISSION_DATE_FIELD_NAME));
childReportingService.registerChild(reportingData);
childSchedulesService.enrollChild(child);
}
}
private boolean handleStillBirth(FormSubmission submission, SubFormData subFormData) {
if (!isDeliveryOutcomeStillBirth(submission)) {
return false;
}
if (!subFormData.instances().isEmpty()) {
String childId = subFormData.instances().get(0).get(ID);
if (childId != null) {
allChildren.remove(childId);
}
}
return true;
}
public void pncVisitHappened(FormSubmission submission) {
Map<String, String> reportFieldsMap = submission.getFields(reportFieldsDefinition.get(submission.formName()));
SubFormData subFormData = submission.getSubFormByName(AllConstants.Form.PNC_VISIT_CHILD_SUB_FORM_NAME);
if (handleStillBirth(submission, subFormData)) return;
for (Map<String, String> childFields : subFormData.instances()) {
SafeMap reportingData = new SafeMap(reportFieldsMap);
reportingData.put(ChildReportingService.CHILD_ID_FIELD, childFields.get(ID));
reportingData.put(URINE_STOOL_PROBLEMS, childFields.get(URINE_STOOL_PROBLEMS));
reportingData.put(SUBMISSION_DATE_FIELD_NAME, submission.getField(SUBMISSION_DATE_FIELD_NAME));
childReportingService.pncVisitHappened(reportingData);
}
}
public void sickVisitHappened(FormSubmission submission) {
Map<String, String> reportFieldsMap = submission.getFields(reportFieldsDefinition.get(submission.formName()));
childReportingService.sickVisitHappened(new SafeMap(reportFieldsMap));
}
}