package edu.northwestern.bioinformatics.studycalendar.service;

import edu.northwestern.bioinformatics.studycalendar.domain.ScheduledActivity;
import edu.northwestern.bioinformatics.studycalendar.domain.ScheduledActivityMode;
import edu.northwestern.bioinformatics.studycalendar.domain.delta.Revision;
import edu.northwestern.bioinformatics.studycalendar.domain.scheduledactivitystate.ScheduledActivityState;
import org.springframework.beans.factory.annotation.Required;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Calendar;

import gov.nih.nci.cabig.ctms.lang.StringTools;

/**
 * @author Rhett Sutphin
 */
public class ScheduleService {
    private final Logger log = LoggerFactory.getLogger(getClass());
    private SubjectService subjectService;

    /**
     * Shifts the given event by the given number of days, if the event is outstanding.
     * If the new date is a blackout date, it shifts it again until it's not.
     *
     * TODO: might should update idealDate, too
     *
     * @param event
     * @param amount
     * @param source
     */
    public void reviseDate(ScheduledActivity event, int amount, Revision source) {
        if (!event.getCurrentState().getMode().isOutstanding()) return;
        Calendar newDate = Calendar.getInstance();
        ScheduledActivityState currentState = event.getCurrentState();
        newDate.setTime(currentState.getDate());
        newDate.add(Calendar.DAY_OF_YEAR, amount);
        ScheduledActivityState newState;
        if (amount == 0 && event.isConditionalEvent()) {
            newState = ScheduledActivityMode.CONDITIONAL.createStateInstance();
            newState.setReason(createReason(source));
        } else {
            newState = currentState.getMode().createStateInstance();
            newState.setReason(createShiftReason(amount, source));
        }
        newState.setDate(newDate.getTime());
        event.changeState(newState);
        subjectService.avoidBlackoutDates(event);
    }

    private String createShiftReason(int amount, Revision source) {
        return new StringBuilder("Shifted ")
            .append(amount < 0 ? "back" : "forward")
            .append(' ').append(StringTools.createCountString(Math.abs(amount), "day"))
            .append(" in revision ").append(source.getDisplayName())
            .toString();
    }

    private String createReason(Revision source) {
        return new StringBuilder("State change").append(" in revision ").append(source.getDisplayName()).toString();
    }

    ////// CONFIGURATION

    @Required
    public void setSubjectService(SubjectService subjectService) {
        this.subjectService = subjectService;
    }
}

@@ -378,38 +378,17 @@
 tystate.
-ScheduledActivityState
+*
 ;%0Aimport
@@ -499,16 +499,60 @@
 Factory;
+%0Aimport org.apache.commons.lang.StringUtils;
 %0A%0Aimport
@@ -571,16 +571,39 @@
 alendar;
+%0Aimport java.util.Date;
 %0A%0Aimport
@@ -819,16 +819,362 @@
 Service;
+%0A    private static final String MISSED = %22missed%22;%0A    private static final String SCHEDULED = %22scheduled%22;%0A    private static final String OCCURRED = %22occurred%22;%0A    private static final String CANCELED = %22canceled%22;%0A    private static final String CONDITIONAL = %22conditional%22;%0A    private static final String NOT_APPLICABLE = %22not-applicable%22;
 %0A%0A    /*
@@ -2782,32 +2782,32 @@
 ision source) %7B%0A
-
         return n
@@ -2910,24 +2910,1211 @@
 g();%0A    %7D%0A%0A
+    public ScheduledActivityState createScheduledActivityState(String state, Date date, String reason)%7B%0A        ScheduledActivityState scheduledActivityState = null;%0A        if (state == null %7C%7C StringUtils.isEmpty(state)) %7B%0A            return null;%0A        %7D else if (state.equals(CONDITIONAL)) %7B%0A            scheduledActivityState = new Conditional();%0A        %7D else if (state.equals(OCCURRED)) %7B%0A            scheduledActivityState = new Occurred();%0A        %7D else if (state.equals(SCHEDULED)) %7B%0A            scheduledActivityState = new Scheduled();%0A        %7D else if (state.equals(MISSED)) %7B%0A            scheduledActivityState = new Missed();%0A        %7D else if (state.equals(NOT_APPLICABLE)) %7B%0A            scheduledActivityState = new NotApplicable();%0A        %7D else if (state.equals(CANCELED)) %7B%0A            scheduledActivityState = new Canceled();%0A        %7D else %7B%0A            return scheduledActivityState;%0A        %7D%0A%0A        if (date != null) %7B%0A            scheduledActivityState.setDate(date);%0A        %7D%0A        if (reason != null && StringUtils.isNotEmpty(reason)) %7B%0A            scheduledActivityState.setReason(reason);%0A        %7D%0A%0A        return scheduledActivityState;%0A    %7D%0A%0A
     ////// C

Add method for creating scheduled activity state depending on state, date and reason. Related to #648