package org.synyx.urlaubsverwaltung.restapi.availability;
import org.joda.time.DateMidnight;
import org.synyx.urlaubsverwaltung.core.person.Person;
import java.math.BigDecimal;
import java.util.ArrayList;
/**
* This class is used to build a chain of responsibility (https://en.wikipedia.org/wiki/Chain-of-responsibility_pattern)
* which defines in which order absences are to be checked. This ensures, that multiple overlapping absences for a
* certain date do not sum up to more than a full day. Priorities are: free time > holidays > sick > vacation
*
* @author Timo Eifler - eifler@synyx.de
*/
abstract class AbstractTimedAbsenceProvider {
protected final AbstractTimedAbsenceProvider nextPriorityAbsenceProvider;
public AbstractTimedAbsenceProvider(AbstractTimedAbsenceProvider nextPriorityAbsenceProvider) {
this.nextPriorityAbsenceProvider = nextPriorityAbsenceProvider;
}
/**
* Convenience function for initial call, so that the caller does not have to create an empty list himself.
*/
public TimedAbsenceSpans checkForAbsence(Person person, DateMidnight date) {
return checkForAbsence(new TimedAbsenceSpans(new ArrayList<>()), person, date);
}
/**
* Checks for absences for the given person on the given day. Recursively calls the next priority provider if the
* absence spans do not yet sum up to a full day.
*/
public TimedAbsenceSpans checkForAbsence(TimedAbsenceSpans knownAbsences, Person person, DateMidnight date) {
TimedAbsenceSpans updatedAbsences = addAbsence(knownAbsences, person, date);
if (isPersonAbsentForWholeDay(updatedAbsences) || isLastPriorityProvider()) {
return updatedAbsences;
} else {
return nextPriorityAbsenceProvider.checkForAbsence(updatedAbsences, person, date);
}
}
/**
* Each provider implements his own logic to retrieve absences via this method.
*/
abstract TimedAbsenceSpans addAbsence(TimedAbsenceSpans knownAbsences, Person person, DateMidnight date);
/**
* This method is used to check if the provider has a follow up provider to call.
*
* @return {@code true} if no follow up provider exists.
*/
abstract boolean isLastPriorityProvider();
private boolean isPersonAbsentForWholeDay(TimedAbsenceSpans timedAbsenceSpans) {
return BigDecimal.ZERO.compareTo(timedAbsenceSpans.calculatePresenceRatio()) == 0;
}
}