package org.ei.drishti.service;
import org.apache.commons.lang3.StringUtils;
import org.ei.drishti.common.AllConstants;
import org.ei.drishti.common.util.EasyMap;
import org.ei.drishti.domain.EligibleCouple;
import org.ei.drishti.domain.Mother;
import org.ei.drishti.domain.PNCVisit;
import org.ei.drishti.domain.register.*;
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.AllEligibleCouples;
import org.ei.drishti.repository.AllMothers;
import org.ei.drishti.service.formSubmission.handler.ReportFieldsDefinition;
import org.ei.drishti.service.reporting.MotherReportingService;
import org.ei.drishti.service.scheduling.PNCSchedulesService;
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.text.MessageFormat.format;
import static org.ei.drishti.common.AllConstants.ANCVisitFormFields.WEIGHT;
import static org.ei.drishti.common.AllConstants.ChildImmunizationFields.IMMUNIZATIONS_GIVEN_FIELD_NAME;
import static org.ei.drishti.common.AllConstants.CommonChildFormFields.GENDER;
import static org.ei.drishti.common.AllConstants.CommonFormFields.ID;
import static org.ei.drishti.common.AllConstants.CommonFormFields.REFERENCE_DATE;
import static org.ei.drishti.common.AllConstants.DeliveryOutcomeFields.*;
import static org.ei.drishti.common.AllConstants.EntityCloseFormFields.CLOSE_REASON_FIELD_NAME;
import static org.ei.drishti.common.AllConstants.FamilyPlanningFormFields.*;
import static org.ei.drishti.common.AllConstants.Form.*;
import static org.ei.drishti.common.AllConstants.PNCCloseFields.DEATH_OF_MOTHER_VALUE;
import static org.ei.drishti.common.AllConstants.PNCCloseFields.PERMANENT_RELOCATION_VALUE;
import static org.ei.drishti.common.AllConstants.PNCVisitFormFields.*;
import static org.ei.drishti.common.AllConstants.ReportDataParameters.QUANTITY;
import static org.ei.drishti.common.AllConstants.ReportDataParameters.SERVICE_PROVIDED_DATE;
import static org.ei.drishti.common.util.EasyMap.create;
@Service
public class PNCService {
private static Logger logger = LoggerFactory.getLogger(PNCService.class.toString());
private ActionService actionService;
private PNCSchedulesService pncSchedulesService;
private AllEligibleCouples allEligibleCouples;
private AllMothers allMothers;
private AllChildren allChildren;
private MotherReportingService motherReportingService;
private ReportFieldsDefinition reportFieldsDefinition;
@Autowired
public PNCService(ActionService actionService,
PNCSchedulesService pncSchedulesService,
AllEligibleCouples allEligibleCouples,
AllMothers allMothers,
AllChildren allChildren,
MotherReportingService motherReportingService,
ReportFieldsDefinition reportFieldsDefinition) {
this.actionService = actionService;
this.pncSchedulesService = pncSchedulesService;
this.allEligibleCouples = allEligibleCouples;
this.allMothers = allMothers;
this.allChildren = allChildren;
this.motherReportingService = motherReportingService;
this.reportFieldsDefinition = reportFieldsDefinition;
}
public void deliveryOutcome(FormSubmission submission) {
Mother mother = allMothers.findByCaseId(submission.entityId());
if (mother == null) {
logger.warn(format("Failed to handle delivery outcome as there is no mother registered with ID: {0}", submission.entityId()));
return;
}
if (BOOLEAN_FALSE_VALUE.equals(submission.getField(DID_WOMAN_SURVIVE))
|| BOOLEAN_FALSE_VALUE.equals(submission.getField(DID_MOTHER_SURVIVE))) {
logger.info("Closing Mother as the mother died during delivery. Mother Id: " + mother.caseId());
closeMother(mother);
} else if (BOOLEAN_TRUE_VALUE.equals(submission.getField(DID_WOMAN_SURVIVE))
|| BOOLEAN_TRUE_VALUE.equals(submission.getField(DID_MOTHER_SURVIVE))) {
pncSchedulesService.deliveryOutcome(submission.entityId(), submission.getField(REFERENCE_DATE));
}
SubFormData subFormData = submission.getSubFormByName(CHILD_REGISTRATION_SUB_FORM_NAME);
addChildrenDetailsToMother(submission, subFormData, mother);
allMothers.update(mother);
}
private void addChildrenDetailsToMother(FormSubmission submission, SubFormData subFormData, Mother mother) {
List<Map<String, String>> childrenDetails = new ArrayList<>(mother.childrenDetails());
if (!handleStillBirth(submission, subFormData)) {
for (Map<String, String> childFields : subFormData.instances()) {
Map<String, String> child = create(ID, childFields.get(ID))
.put(GENDER, childFields.get(GENDER))
.put(WEIGHT, childFields.get(WEIGHT))
.put(IMMUNIZATIONS_AT_BIRTH, childFields.get(IMMUNIZATIONS_GIVEN_FIELD_NAME))
.map();
childrenDetails.add(child);
}
}
mother.withChildrenDetails(childrenDetails);
}
private void closeMother(Mother mother) {
mother.setIsClosed(true);
actionService.markAllAlertsAsInactive(mother.caseId());
pncSchedulesService.unEnrollFromSchedules(mother.caseId());
EligibleCouple eligibleCouple = allEligibleCouples.findByCaseId(mother.ecCaseId());
logger.info("Closing EC case along with PNC case. Ec Id: " + eligibleCouple.caseId());
eligibleCouple.setIsClosed(true);
allEligibleCouples.update(eligibleCouple);
}
public void pncRegistrationOA(FormSubmission submission) {
List<Mother> mothers = allMothers.findByEcCaseId(submission.entityId());
if (mothers.size() <= 0) {
logger.warn("Failed to handle PNC registration as there is no mother registered with ec id: " + submission.entityId());
return;
}
Mother mother = mothers.get(0);
mother.withAnm(submission.anmId());
addChildrenDetailsToMother(submission, submission.getSubFormByName(CHILD_REGISTRATION_OA), mother);
allMothers.update(mother);
updateEligibleCouple(submission, mother);
if (BOOLEAN_TRUE_VALUE.equals(submission.getField(DID_WOMAN_SURVIVE))) {
pncSchedulesService.deliveryOutcome(mother.caseId(), submission.getField(REFERENCE_DATE));
}
List<String> reportFields = reportFieldsDefinition.get(submission.formName());
motherReportingService.pncRegistrationOA(new SafeMap(submission.getFields(reportFields)));
}
private void updateEligibleCouple(FormSubmission submission, Mother mother) {
EligibleCouple eligibleCouple = allEligibleCouples.findByCaseId(mother.ecCaseId());
eligibleCouple.withANMIdentifier(submission.anmId());
allEligibleCouples.update(eligibleCouple);
}
public void close(FormSubmission submission) {
Mother mother = allMothers.findByCaseId(submission.entityId());
if (mother == null) {
logger.warn(format("Failed to close PNC as there is no mother registered with ID: {0}", submission.entityId()));
return;
}
logger.info("Closing PNC case. Entity Id: " + submission.entityId());
allMothers.close(submission.entityId());
actionService.markAllAlertsAsInactive(submission.entityId());
pncSchedulesService.unEnrollFromSchedules(submission.entityId());
List<String> reportFields = reportFieldsDefinition.get(submission.formName());
motherReportingService.closePNC(new SafeMap(submission.getFields(reportFields)));
if (DEATH_OF_MOTHER_VALUE.equalsIgnoreCase(submission.getField(CLOSE_REASON_FIELD_NAME))
|| PERMANENT_RELOCATION_VALUE.equalsIgnoreCase(submission.getField(CLOSE_REASON_FIELD_NAME))) {
logger.info("Closing EC case along with PNC case. Submission: " + submission);
allEligibleCouples.close(mother.ecCaseId());
}
}
public void autoClosePNCCase(String entityId) {
Mother mother = allMothers.findByCaseId(entityId);
if (mother == null) {
logger.warn(format("Failed to auto close PNC as there is no mother registered with ID: {0}", entityId));
return;
}
logger.info(format("Auto closing mother case with entity id {0} as the Post-pregnancy period has elapsed.", entityId));
allMothers.close(entityId);
pncSchedulesService.fulfillPNCAutoCloseMilestone(entityId, mother.anmIdentifier());
actionService.markAllAlertsAsInactive(entityId);
actionService.closeMother(entityId, mother.anmIdentifier(), AllConstants.AUTO_CLOSE_PNC_CLOSE_REASON);
}
public void pncVisitHappened(FormSubmission submission) {
Mother mother = allMothers.findByCaseId(submission.entityId());
if (mother == null) {
logger.warn("Found PNC visit without registered mother for entity ID: " + submission.entityId());
return;
}
updatePNCVisitDatesOfMother(submission, mother);
updatePNCVisitDetails(submission, mother);
allMothers.update(mother);
List<String> reportFields = reportFieldsDefinition.get(submission.formName());
motherReportingService.pncVisitHappened(new SafeMap(submission.getFields(reportFields)));
}
private void updatePNCVisitDetails(FormSubmission submission, Mother mother) {
mother.addPNCVisit(new PNCVisit()
.withDate(submission.getField(VISIT_DATE_FIELD_NAME))
.withPerson(submission.getField(VISIT_PERSON_FIELD_NAME))
.withPlace(submission.getField(VISIT_PLACE_FIELD_NAME))
.withDifficulties(submission.getField(DIFFICULTIES_FIELD_NAME))
.withAbdominalProblems(submission.getField(ABDOMINAL_PROBLEMS_FIELD_NAME))
.withVaginalProblems(submission.getField(VAGINAL_PROBLEMS_FIELD_NAME))
.withUrinalProblems(submission.getField(URINAL_PROBLEMS_FIELD_NAME))
.withBreastProblems(submission.getField(BREAST_PROBLEMS))
.withChildrenDetails(getChildVisitDetails(submission.getSubFormByName(PNC_VISIT_CHILD_SUB_FORM_NAME))));
}
private List<Map<String, String>> getChildVisitDetails(SubFormData subFormData) {
List<Map<String, String>> childVisitDetails = new ArrayList<>();
for (Map<String, String> childFields : subFormData.instances()) {
Map<String, String> child = EasyMap.create(ID, childFields.get(ID))
.put(ID, childFields.get(ID))
.put(URINE_STOOL_PROBLEMS, childFields.get(URINE_STOOL_PROBLEMS))
.put(ACTIVITY_PROBLEMS, childFields.get(ACTIVITY_PROBLEMS))
.put(BREATHING_PROBLEMS, childFields.get(BREATHING_PROBLEMS))
.put(SKIN_PROBLEMS, childFields.get(SKIN_PROBLEMS))
.map();
childVisitDetails.add(child);
}
return childVisitDetails;
}
private void updatePNCVisitDatesOfMother(FormSubmission submission, Mother mother) {
String visitDate = submission.getField(VISIT_DATE_FIELD_NAME);
String pncVisitDates = mother.getDetail(VISIT_DATES_FIELD_NAME) == null
? visitDate
: mother.getDetail(VISIT_DATES_FIELD_NAME) + " " + visitDate;
mother.details().put(VISIT_DATES_FIELD_NAME, pncVisitDates);
}
public void reportPPFamilyPlanning(FormSubmission submission) {
Mother mother = allMothers.findByCaseId(submission.entityId());
EligibleCouple eligibleCouple = allEligibleCouples.findByCaseId(mother.ecCaseId());
EligibleCouple updatedEligibleCouple = updateECWithFPMethod(submission, eligibleCouple);
allEligibleCouples.update(updatedEligibleCouple);
}
private EligibleCouple updateECWithFPMethod(FormSubmission submission, EligibleCouple eligibleCouple) {
String fpMethod = submission.getField(CURRENT_FP_METHOD_FIELD_NAME);
String date = submission.getField(FP_METHOD_CHANGE_DATE_FIELD_NAME);
if (FEMALE_STERILIZATION_FP_METHOD_VALUE.equalsIgnoreCase(fpMethod)) {
String type = submission.getField(FEMALE_STERILIZATION_TYPE);
eligibleCouple = updateECWithFemaleSterilizationFPDetails(eligibleCouple, type, date);
return eligibleCouple;
}
if (IUD_FP_METHOD_VALUE.equalsIgnoreCase(fpMethod)) {
String place = submission.getField(IUD_PLACE);
eligibleCouple = updateECWithIUDFPDetails(eligibleCouple, place, date);
return eligibleCouple;
}
if (MALE_STERILIZATION_FP_METHOD_VALUE.equalsIgnoreCase(fpMethod)) {
String type = submission.getField(MALE_STERILIZATION_TYPE);
List<MaleSterilizationFPDetails> maleSterilizationFPDetails = eligibleCouple.maleSterilizationFPDetails();
maleSterilizationFPDetails.add(new MaleSterilizationFPDetails(type, date));
return eligibleCouple.withMaleSterilizationFPDetails(maleSterilizationFPDetails);
}
if (OCP_FP_METHOD_VALUE.equalsIgnoreCase(fpMethod)) {
List<OCPFPDetails> ocpFPDetails = eligibleCouple.ocpFPDetails();
ocpFPDetails.add(getOCPFPDetails(submission, date));
eligibleCouple.withOCPFPDetails(ocpFPDetails);
}
if (CONDOM_FP_METHOD_VALUE.equalsIgnoreCase(fpMethod)) {
List<CondomFPDetails> condomFPDetails = eligibleCouple.condomFPDetails();
condomFPDetails.add(getCondomFPDetails(submission, date));
eligibleCouple.withCondomFPDetails(condomFPDetails);
}
return eligibleCouple;
}
private EligibleCouple updateECWithIUDFPDetails(EligibleCouple eligibleCouple, String place, String date) {
List<IUDFPDetails> iudFPDetails = eligibleCouple.iudFPDetails();
iudFPDetails.add(new IUDFPDetails(date, place, null, null));
return eligibleCouple.withIUDFPDetails(iudFPDetails);
}
private EligibleCouple updateECWithFemaleSterilizationFPDetails(EligibleCouple eligibleCouple, String type, String date) {
List<FemaleSterilizationFPDetails> femaleSterilizationFPDetails = eligibleCouple.femaleSterilizationFPDetails();
femaleSterilizationFPDetails.add(new FemaleSterilizationFPDetails(type, date));
return eligibleCouple.withFemaleSterilizationFPDetails(femaleSterilizationFPDetails);
}
private OCPFPDetails getOCPFPDetails(FormSubmission submission, String fpAcceptanceDate) {
Map<String, String> refill = new HashMap<>();
refill.put(SERVICE_PROVIDED_DATE, fpAcceptanceDate);
refill.put(QUANTITY, submission.getField(NUMBER_OF_OCP_STRIPS_SUPPLIED_FIELD_NAME));
List<Map<String, String>> refills = new ArrayList<>();
refills.add(refill);
return new OCPFPDetails(fpAcceptanceDate, refills, null, null);
}
private CondomFPDetails getCondomFPDetails(FormSubmission submission, String fpAcceptanceDate) {
Map<String, String> refill = new HashMap<>();
refill.put(SERVICE_PROVIDED_DATE, fpAcceptanceDate);
refill.put(QUANTITY, submission.getField(NUMBER_OF_CONDOMS_SUPPLIED_FIELD_NAME));
List<Map<String, String>> refills = new ArrayList<>();
refills.add(refill);
return new CondomFPDetails(fpAcceptanceDate, refills);
}
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(!StringUtils.isEmpty(childId)){
allChildren.remove(childId);
}
}
return true;
}
private boolean isDeliveryOutcomeStillBirth(FormSubmission submission) {
return AllConstants.DeliveryOutcomeFields.STILL_BIRTH_VALUE.equalsIgnoreCase(submission.getField(AllConstants.DeliveryOutcomeFields.DELIVERY_OUTCOME));
}
}