package org.ei.drishti.service.scheduling; import org.ei.drishti.contract.Schedule; import org.ei.drishti.domain.Child; import org.ei.drishti.repository.AllChildren; import org.ei.drishti.service.ActionService; import org.joda.time.LocalDate; import org.motechproject.scheduletracking.api.service.EnrollmentRecord; import org.motechproject.scheduletracking.api.service.EnrollmentsQuery; import org.motechproject.scheduletracking.api.service.ScheduleTrackingService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.*; import static java.text.MessageFormat.format; import static java.util.Arrays.asList; import static java.util.Collections.unmodifiableList; import static java.util.Collections.unmodifiableMap; import static org.ei.drishti.common.AllConstants.ChildImmunizationFields.*; import static org.ei.drishti.scheduler.DrishtiScheduleConstants.ChildScheduleConstants.*; import static org.motechproject.scheduletracking.api.domain.EnrollmentStatus.ACTIVE; @Service public class ChildSchedulesService { private static Logger logger = LoggerFactory.getLogger(ChildSchedulesService.class.toString()); private final ScheduleTrackingService scheduleTrackingService; private final AllChildren allChildren; private final ScheduleService scheduleService; private ActionService actionService; private Map<String, Schedule> childSchedules; @Autowired public ChildSchedulesService(ScheduleTrackingService scheduleTrackingService, AllChildren allChildren, ScheduleService scheduleService, ActionService actionService) { this.scheduleTrackingService = scheduleTrackingService; this.allChildren = allChildren; this.scheduleService = scheduleService; this.actionService = actionService; initializeSchedules(); } public void enrollChild(Child child) { enrollNonDependentModules(child.caseId(), LocalDate.parse(child.dateOfBirth())); enrollDependentModulesIfRequired(child.caseId(), Collections.<String>emptyList(), child.immunizationsGiven(), child.dateOfBirth()); updateMilestonesForEnrolledSchedules(child.caseId(), child.anmIdentifier(), child.immunizationsGiven(), child.dateOfBirth()); } public void updateEnrollments(String entityId, List<String> previousImmunizations) { Child child = allChildren.findByCaseId(entityId); enrollDependentModulesIfRequired(child.caseId(), previousImmunizations, child.immunizationsGiven(), child.immunizationDate()); updateMilestonesForEnrolledSchedules(child.caseId(), child.anmIdentifier(), child.immunizationsGiven(), child.immunizationDate()); } //#TODO: Remove this duplicated code public void unenrollChild(String id) { List<EnrollmentRecord> openEnrollments = scheduleTrackingService.search(new EnrollmentsQuery().havingExternalId(id).havingState(ACTIVE)); for (EnrollmentRecord enrollment : openEnrollments) { logger.info(format("Un-enrolling child from schedule: {0}, entityId: {1}", enrollment.getScheduleName(), id)); scheduleTrackingService.unenroll(id, Arrays.asList(enrollment.getScheduleName())); } } private void enrollNonDependentModules(String id, LocalDate dateOfBirth) { for (Schedule schedule : childSchedules.values()) { if (!schedule.hasDependency()) { logger.info(format("Enrolling child to schedule: {0}, entityId: {1}, referenceDate: {2}", schedule.name(), id, dateOfBirth)); scheduleService.enroll(id, schedule.name(), dateOfBirth.toString()); } } } private void enrollDependentModulesIfRequired(String id, List<String> previousImmunizations, List<String> immunizationsGiven, String immunizationDate) { for (Schedule schedule : childSchedules.values()) { if (schedule.hasDependency() && !isImmunizationAlreadyProvided(schedule, previousImmunizations)) { Schedule dependsOn = schedule.getDependencySchedule(); if (immunizationsGiven.contains(dependsOn.getLastMilestone()) && isNotEnrolled(id, schedule.name())) { logger.info(format("Enrolling child to schedule: {0}, entityId: {1}, referenceDate: {2}", schedule.name(), id, immunizationDate)); scheduleService.enroll(id, schedule.name(), immunizationDate); } } } } private boolean isImmunizationAlreadyProvided(Schedule schedule, List<String> previousImmunizations) { List<String> mileStones = schedule.getMileStones(); for (String mileStone : mileStones) { if (!previousImmunizations.contains(mileStone)) return false; } return true; } private void updateMilestonesForEnrolledSchedules(String id, String anmIdentifier, List<String> immunizationsGiven, String immunizationDate) { for (Schedule schedule : childSchedules.values()) { for (String mileStoneName : schedule.getMileStones()) { EnrollmentRecord record = scheduleTrackingService.getEnrollment(id, schedule.name()); if (record == null) break; String currentMilestoneName = record.getCurrentMilestoneName(); boolean isProvided = immunizationsGiven.contains(mileStoneName); if (isProvided && currentMilestoneName.equals(mileStoneName)) { logger.info(format("Fulfilling current milestone of schedule: {0}, milestone: {1}, entityId: {2}, completionDate: {3}", schedule.name(), mileStoneName, id, immunizationDate)); scheduleTrackingService.fulfillCurrentMilestone(id, schedule.name(), LocalDate.parse(immunizationDate)); actionService.markAlertAsClosed(id, anmIdentifier, mileStoneName, immunizationDate); } } } } private boolean isNotEnrolled(String entityId, String scheduleName) { return scheduleTrackingService.getEnrollment(entityId, scheduleName) == null; } private void initializeSchedules() { List<String> bcgMileStones = unmodifiableList(asList(BCG_VALUE)); final Schedule bcg = new Schedule(CHILD_SCHEDULE_BCG, bcgMileStones); List<String> dptBooster1MileStones = unmodifiableList(asList(DPT_BOOSTER_1_VALUE)); final Schedule dptBooster1 = new Schedule(CHILD_SCHEDULE_DPT_BOOSTER1, dptBooster1MileStones); List<String> dptBooster2MileStones = unmodifiableList(asList(DPT_BOOSTER_2_VALUE)); final Schedule dptBooster2 = new Schedule(CHILD_SCHEDULE_DPT_BOOSTER2, dptBooster2MileStones).withDependencyOn(dptBooster1); List<String> measlesMileStones = unmodifiableList(asList(MEASLES_VALUE)); final Schedule measles = new Schedule(CHILD_SCHEDULE_MEASLES, measlesMileStones); List<String> measlesBoosterMileStones = unmodifiableList(asList(MEASLES_BOOSTER_VALUE)); final Schedule measlesBooster = new Schedule(CHILD_SCHEDULE_MEASLES_BOOSTER, measlesBoosterMileStones).withDependencyOn(measles); List<String> opv0And1MileStones = unmodifiableList(asList( OPV_0_VALUE, OPV_1_VALUE )); final Schedule opv0And1 = new Schedule(CHILD_SCHEDULE_OPV_0_AND_1, opv0And1MileStones); List<String> opv2MileStone = unmodifiableList(asList(OPV_2_VALUE)); final Schedule opv2 = new Schedule(CHILD_SCHEDULE_OPV_2, opv2MileStone).withDependencyOn(opv0And1); List<String> opv3MileStone = unmodifiableList(asList(OPV_3_VALUE)); final Schedule opv3 = new Schedule(CHILD_SCHEDULE_OPV_3, opv3MileStone).withDependencyOn(opv2); List<String> opvBoosterMileStone = unmodifiableList(asList(OPV_BOOSTER_VALUE)); final Schedule opvBooster = new Schedule(CHILD_SCHEDULE_OPV_BOOSTER, opvBoosterMileStone).withDependencyOn(opv3); List<String> pentavalent1Milestone = unmodifiableList(asList(PENTAVALENT_1_VALUE)); final Schedule pentavalent1 = new Schedule(CHILD_SCHEDULE_PENTAVALENT_1, pentavalent1Milestone); List<String> pentavalent2Milestone = unmodifiableList(asList(PENTAVALENT_2_VALUE)); final Schedule pentavalent2 = new Schedule(CHILD_SCHEDULE_PENTAVALENT_2, pentavalent2Milestone).withDependencyOn(pentavalent1); List<String> pentavalent3Milestone = unmodifiableList(asList(PENTAVALENT_3_VALUE)); final Schedule pentavalent3 = new Schedule(CHILD_SCHEDULE_PENTAVALENT_3, pentavalent3Milestone).withDependencyOn(pentavalent2); childSchedules = unmodifiableMap(new HashMap<String, Schedule>() {{ put(CHILD_SCHEDULE_BCG, bcg); put(CHILD_SCHEDULE_DPT_BOOSTER1, dptBooster1); put(CHILD_SCHEDULE_DPT_BOOSTER2, dptBooster2); put(CHILD_SCHEDULE_MEASLES, measles); put(CHILD_SCHEDULE_MEASLES_BOOSTER, measlesBooster); put(CHILD_SCHEDULE_OPV_0_AND_1, opv0And1); put(CHILD_SCHEDULE_OPV_2, opv2); put(CHILD_SCHEDULE_OPV_3, opv3); put(CHILD_SCHEDULE_OPV_BOOSTER, opvBooster); put(CHILD_SCHEDULE_PENTAVALENT_1, pentavalent1); put(CHILD_SCHEDULE_PENTAVALENT_2, pentavalent2); put(CHILD_SCHEDULE_PENTAVALENT_3, pentavalent3); }}); } }