package org.synyx.urlaubsverwaltung.availability.api;

import org.synyx.urlaubsverwaltung.person.Person;

import java.math.BigDecimal;
import java.time.LocalDate;
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 > public holidays > sick > vacation
 */
abstract class AbstractTimedAbsenceProvider {

    private 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.
     */
    TimedAbsenceSpans checkForAbsence(Person person, LocalDate 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.
     */
    TimedAbsenceSpans checkForAbsence(TimedAbsenceSpans knownAbsences, Person person, LocalDate 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, LocalDate 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;
    }
}

@@ -103,37 +103,8 @@
 n;%0A%0A
-import java.math.BigDecimal;%0A
 impo
@@ -156,16 +156,57 @@
 yList;%0A%0A
+import static java.math.BigDecimal.ZERO;%0A
 %0A/**%0A * 
@@ -688,21 +688,24 @@
 ;%0A%0A    p
-ublic
+rotected
  Abstrac
@@ -782,25 +782,24 @@
 Provider) %7B%0A
-%0A
         this
@@ -1056,33 +1056,32 @@
 calDate date) %7B%0A
-%0A
         return c
@@ -1151,33 +1151,32 @@
 , date);%0A    %7D%0A%0A
-%0A
     /**%0A     * C
@@ -1456,24 +1456,30 @@
  %7B%0A%0A        
+final 
 TimedAbsence
@@ -1795,17 +1795,16 @@
 %0A    %7D%0A%0A
-%0A
     /**%0A
@@ -1999,25 +1999,24 @@
 ate date);%0A%0A
-%0A
     /**%0A    
@@ -2221,17 +2221,16 @@
 der();%0A%0A
-%0A
     priv
@@ -2302,25 +2302,24 @@
 nceSpans) %7B%0A
-%0A
         retu
@@ -2321,27 +2321,16 @@
  return 
-BigDecimal.
 ZERO.com

Change visibility of AbstractTimedAbsenceProvider constructor to protected