org.motechproject.server.event.impl.ExpectedCareMessageProgram.java Source code

Java tutorial

Introduction

Here is the source code for org.motechproject.server.event.impl.ExpectedCareMessageProgram.java

Source

/**
 * MOTECH PLATFORM OPENSOURCE LICENSE AGREEMENT
 *
 * Copyright (c) 2010-11 The Trustees of Columbia University in the City of
 * New York and Grameen Foundation USA.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. Neither the name of Grameen Foundation USA, Columbia University, or
 * their respective contributors may be used to endorse or promote products
 * derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY GRAMEEN FOUNDATION USA, COLUMBIA UNIVERSITY
 * AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GRAMEEN FOUNDATION
 * USA, COLUMBIA UNIVERSITY OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.motechproject.server.event.impl;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.motechproject.server.model.*;
import org.motechproject.server.svc.RegistrarBean;
import org.motechproject.server.time.TimePeriod;
import org.openmrs.Patient;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

public class ExpectedCareMessageProgram implements MessageProgram {

    private static Log log = LogFactory.getLog(ExpectedCareMessageProgram.class);

    private List<ExpectedCareMessageDetails> careMessageDetails = new ArrayList<ExpectedCareMessageDetails>();
    private RegistrarBean registrarBean;
    private String name;

    public MessageProgramState determineState(MessageProgramEnrollment enrollment, Date currentDate) {

        // Calculate date 1 day in future to use for message dates calculated in
        // past
        Date nextDate = calculateDateBasedOnTimePeriodAndTimeValue(currentDate, 1, TimePeriod.day);

        Integer maxPatientReminders = registrarBean.getMaxPatientCareReminders();

        // Get patient from enrollment person Id
        Patient patient = registrarBean.getPatientById(enrollment.getPersonId());
        if (patient == null) {
            log.debug("Person of enrollment is not a patient: " + enrollment.getPersonId());
            return null;
        }

        // Get all active expected care for patient (obs and encounter)
        List<ExpectedEncounter> expectedEncounters = registrarBean.getExpectedEncounters(patient);
        List<ExpectedObs> expectedObservations = registrarBean.getExpectedObs(patient);
        // Get all messages for enrollment (includes sent and not sent)
        List<ScheduledMessage> scheduledMessages = registrarBean.getScheduledMessages(enrollment);

        // Create predicates for expected care (by group) and scheduled messages
        // (by key)
        ExpectedEncounterPredicate expectedEncounterPredicate = new ExpectedEncounterPredicate();
        ExpectedObsPredicate expectedObsPredicate = new ExpectedObsPredicate();
        ScheduledMessagePredicate scheduledMessagePredicate = new ScheduledMessagePredicate();

        for (ExpectedCareMessageDetails careDetails : careMessageDetails) {

            // Set predicates for care details
            expectedEncounterPredicate.setGroup(careDetails.getName());
            expectedObsPredicate.setGroup(careDetails.getName());
            scheduledMessagePredicate.resetKeys(careDetails.getUpcomingMessageKey(),
                    careDetails.getOverdueMessageKey());

            // Get scheduled messages for care, removing from enrollment list
            List<ScheduledMessage> careScheduledMessages = getScheduledMessages(scheduledMessages,
                    scheduledMessagePredicate);
            scheduledMessages.removeAll(careScheduledMessages);

            // Get expected obs and encounters for care details
            List<ExpectedEncounter> careExpectedEncounters = getExpectedEncounters(expectedEncounters,
                    expectedEncounterPredicate);
            List<ExpectedObs> careExpectedObs = getExpectedObs(expectedObservations, expectedObsPredicate);

            List<ScheduledMessage> verifiedScheduledMessages = new ArrayList<ScheduledMessage>();

            // Schedule messages for expected care (encounters and obs) and add
            // message to verified list
            for (ExpectedEncounter expectedEncounter : careExpectedEncounters) {
                Date dueDate = expectedEncounter.getDueEncounterDatetime();
                Date lateDate = expectedEncounter.getLateEncounterDatetime();
                String care = expectedEncounter.getName();

                // Create new scheduled message or return existing matching
                ScheduledMessage message = scheduleCareMessage(currentDate, dueDate, lateDate, careDetails, care,
                        enrollment, careScheduledMessages, maxPatientReminders, registrarBean);
                if (message != null) {
                    verifiedScheduledMessages.add(message);
                }
            }
            for (ExpectedObs expectedObs : careExpectedObs) {
                Date dueDate = expectedObs.getDueObsDatetime();
                Date lateDate = expectedObs.getLateObsDatetime();
                String care = expectedObs.getName();

                // Create new scheduled message or return existing matching
                ScheduledMessage message = scheduleCareMessage(currentDate, dueDate, lateDate, careDetails, care,
                        enrollment, careScheduledMessages, maxPatientReminders, registrarBean);
                if (message != null) {
                    verifiedScheduledMessages.add(message);
                }
            }

            // Cancel unsent messages for care (not matching the newly
            // scheduled)
            careScheduledMessages.removeAll(verifiedScheduledMessages);
            if (!careScheduledMessages.isEmpty()) {
                registrarBean.removeUnsentMessages(careScheduledMessages);
            }
        }

        // Cancel any unsent messages for enrollment (for unhandled care)
        if (!scheduledMessages.isEmpty()) {
            registrarBean.removeUnsentMessages(scheduledMessages);
        }

        return null;
    }

    @SuppressWarnings("unchecked")
    protected List<ExpectedEncounter> getExpectedEncounters(List<ExpectedEncounter> expectedEncounterList,
            ExpectedEncounterPredicate expectedEncounterPredicate) {
        return (List<ExpectedEncounter>) CollectionUtils.select(expectedEncounterList, expectedEncounterPredicate);
    }

    @SuppressWarnings("unchecked")
    protected List<ExpectedObs> getExpectedObs(List<ExpectedObs> expectedObsList,
            ExpectedObsPredicate expectedObsPredicate) {
        return (List<ExpectedObs>) CollectionUtils.select(expectedObsList, expectedObsPredicate);
    }

    @SuppressWarnings("unchecked")
    protected List<ScheduledMessage> getScheduledMessages(List<ScheduledMessage> scheduledMessagesList,
            ScheduledMessagePredicate scheduledMessagePredicate) {
        return (List<ScheduledMessage>) CollectionUtils.select(scheduledMessagesList, scheduledMessagePredicate);
    }

    protected ScheduledMessage getMatchingScheduledMessage(List<ScheduledMessage> scheduledMessagesList,
            ScheduledMessagePredicate scheduledMessagePredicate) {
        return (ScheduledMessage) CollectionUtils.find(scheduledMessagesList, scheduledMessagePredicate);
    }

    protected boolean isUpcoming(Date currentDate, Date expectedCareDate, ExpectedCareMessageDetails careDetails,
            String care) {
        // Upcoming care is considered twice the value for the care
        Date endDate = calculateDateBasedOnTimePeriodAndTimeValue(currentDate, 2 * careDetails.getTimeValue(care),
                careDetails.getTimePeriod());
        return currentDate.before(expectedCareDate) && endDate.after(expectedCareDate);
    }

    protected boolean isOverdue(Date currentDate, Date expectedCareDate) {
        return currentDate.after(expectedCareDate);
    }

    private ScheduledMessage scheduleCareMessage(Date currentDate, Date dueDate, Date lateDate,
            ExpectedCareMessageDetails careDetails, String care, MessageProgramEnrollment enrollment,
            List<ScheduledMessage> careScheduledMessages, Integer maxPatientReminders,
            RegistrarBean registrarBean) {

        if (isUpcoming(currentDate, dueDate, careDetails, care)) {
            // Schedule reminder value/period before care due date
            Date messageDate = calculateDateBasedOnTimePeriodAndTimeValue(dueDate,
                    (-1 * careDetails.getTimeValue(care)), careDetails.getTimePeriod());

            // Set predicate and get upcoming scheduled message if exists
            ScheduledMessagePredicate scheduledMessagePredicate = new ScheduledMessagePredicate();
            scheduledMessagePredicate.resetKeys(careDetails.getUpcomingMessageKey());
            scheduledMessagePredicate.setCare(care);
            scheduledMessagePredicate.setDate(messageDate);
            ScheduledMessage upcomingMessage = getMatchingScheduledMessage(careScheduledMessages,
                    scheduledMessagePredicate);

            // Create new scheduled message only if not already exist
            if (upcomingMessage == null) {
                return registrarBean.scheduleCareMessage(careDetails.getUpcomingMessageKey(), enrollment,
                        messageDate, careDetails.getUserPreferenceBased(), care, currentDate);
            } else {
                // Check if unsent message attempt date needs adjusting for
                // blackout or preference changes
                registrarBean.verifyMessageAttemptDate(upcomingMessage, careDetails.getUserPreferenceBased(),
                        currentDate);
                return upcomingMessage;
            }

        } else if (isOverdue(currentDate, lateDate)) {
            // Schedule reminder value/period after care late date
            Date reminderDate = calculateDateBasedOnTimePeriodAndTimeValue(lateDate, careDetails.getTimeValue(care),
                    careDetails.getTimePeriod());

            // Set predicate and get previous reminder scheduled message if
            // exists
            ScheduledMessagePredicate scheduledMessagePredicate = new ScheduledMessagePredicate();
            scheduledMessagePredicate.resetKeys(careDetails.getOverdueMessageKey());
            scheduledMessagePredicate.setCare(care);
            scheduledMessagePredicate.setDate(reminderDate);
            ScheduledMessage reminderMessage = getMatchingScheduledMessage(careScheduledMessages,
                    scheduledMessagePredicate);

            if (reminderMessage == null) {
                // Schedule reminder if no previous reminders
                return registrarBean.scheduleCareMessage(careDetails.getOverdueMessageKey(), enrollment,
                        reminderDate, careDetails.getUserPreferenceBased(), care, currentDate);
            } else {
                // Check if unsent message attempt date needs adjusting for
                // blackout or preference changes
                registrarBean.verifyMessageAttemptDate(reminderMessage, careDetails.getUserPreferenceBased(),
                        currentDate);

                // Determine last reminder date
                List<Message> attempts = reminderMessage.getMessageAttempts();
                Date previousReminderDate = null;
                if (!attempts.isEmpty()) {
                    previousReminderDate = attempts.get(0).getAttemptDate();
                } else {
                    previousReminderDate = lateDate;
                }

                // Schedule reminder value/period after most recent reminder
                // if number of previous reminders less than max property
                if (attempts.size() < maxPatientReminders) {
                    Date newReminderDate = calculateDateBasedOnTimePeriodAndTimeValue(previousReminderDate,
                            careDetails.getTimeValue(care), careDetails.getTimePeriod());
                    Date maxReminderDate = calculateDateBasedOnTimePeriodAndTimeValue(currentDate,
                            careDetails.getTimeValue(care), careDetails.getTimePeriod());

                    if (!newReminderDate.after(maxReminderDate)) {
                        registrarBean.addMessageAttempt(reminderMessage, newReminderDate, maxReminderDate,
                                careDetails.getUserPreferenceBased(), currentDate);
                    }
                }
                return reminderMessage;
            }
        }
        return null;
    }

    protected Date calculateDateBasedOnTimePeriodAndTimeValue(Date date, Integer value, TimePeriod period) {
        if (date == null || value == null || period == null) {
            return null;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);

        if (period.equals(TimePeriod.week))
            calendar.add(period.getCalendarPeriod(), value * 7);
        else
            calendar.add(period.getCalendarPeriod(), value);

        return calendar.getTime();
    }

    public MessageProgramState getEndState() {
        return null;
    }

    public MessageProgramState getStartState() {
        return null;
    }

    public List<ExpectedCareMessageDetails> getCareMessageDetails() {
        return careMessageDetails;
    }

    public void setCareMessageDetails(List<ExpectedCareMessageDetails> careMessageDetails) {
        this.careMessageDetails = careMessageDetails;
    }

    public Boolean hasMessageCareDetails() {
        return !careMessageDetails.isEmpty();
    }

    public RegistrarBean getRegistrarBean() {
        return registrarBean;
    }

    public void setRegistrarBean(RegistrarBean registrarBean) {
        this.registrarBean = registrarBean;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}