package org.synyx.urlaubsverwaltung.application.statistics;

import org.synyx.urlaubsverwaltung.application.vacationtype.VacationType;
import org.synyx.urlaubsverwaltung.person.Person;
import org.synyx.urlaubsverwaltung.person.basedata.PersonBasedata;

import java.math.BigDecimal;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import static java.math.BigDecimal.ZERO;

/**
 * Encapsulates information about a person and the corresponding vacation days information (how many applications for
 * leave are waiting, how many are allowed, how many vacation days has the person left for using).
 */
public class ApplicationForLeaveStatistics {

    private final Person person;
    private PersonBasedata personBasedata;

    private final Map<VacationType, BigDecimal> waitingVacationDays = new HashMap<>();
    private final Map<VacationType, BigDecimal> allowedVacationDays = new HashMap<>();

    private BigDecimal leftVacationDays = ZERO;
    private BigDecimal leftRemainingVacationDays = ZERO;
    private BigDecimal leftPeriodVacationDays = ZERO;
    private BigDecimal leftRemainingPeriodVacationDays = ZERO;
    private Duration leftOvertime = Duration.ZERO;

    ApplicationForLeaveStatistics(Person person) {
        this.person = person;
    }

    public Person getPerson() {
        return person;
    }

    void setPersonBasedata(PersonBasedata personBasedata) {
        this.personBasedata = personBasedata;
    }

    public Optional<PersonBasedata> getPersonBasedata() {
        return Optional.ofNullable(personBasedata);
    }

    public Map<VacationType, BigDecimal> getWaitingVacationDays() {
        return waitingVacationDays;
    }

    public Map<VacationType, BigDecimal> getAllowedVacationDays() {
        return allowedVacationDays;
    }

    public BigDecimal getLeftVacationDays() {
        return leftVacationDays;
    }

    public void setLeftVacationDays(BigDecimal leftVacationDays) {
        this.leftVacationDays = leftVacationDays;
    }

    public BigDecimal getLeftRemainingVacationDays() {
        return leftRemainingVacationDays;
    }

    public void setLeftRemainingVacationDays(BigDecimal leftRemainingVacationDays) {
        this.leftRemainingVacationDays = leftRemainingVacationDays;
    }

    public BigDecimal getLeftPeriodVacationDays() {
        return leftPeriodVacationDays;
    }

    public void setLeftPeriodVacationDays(BigDecimal leftPeriodVacationDays) {
        this.leftPeriodVacationDays = leftPeriodVacationDays;
    }

    public BigDecimal getLeftRemainingPeriodVacationDays() {
        return leftRemainingPeriodVacationDays;
    }

    public void setLeftRemainingPeriodVacationDays(BigDecimal leftRemainingPeriodVacationDays) {
        this.leftRemainingPeriodVacationDays = leftRemainingPeriodVacationDays;
    }

    public Duration getLeftOvertime() {
        return leftOvertime;
    }

    public void setLeftOvertime(Duration leftOvertime) {
        this.leftOvertime = leftOvertime;
    }

    public BigDecimal getTotalWaitingVacationDays() {

        BigDecimal total = ZERO;
        for (BigDecimal days : getWaitingVacationDays().values()) {
            total = total.add(days);
        }

        return total;
    }

    public BigDecimal getTotalAllowedVacationDays() {

        BigDecimal total = ZERO;
        for (BigDecimal days : getAllowedVacationDays().values()) {
            total = total.add(days);
        }

        return total;
    }

    public void addWaitingVacationDays(VacationType vacationType, BigDecimal waitingVacationDays) {
        final BigDecimal currentWaitingVacationDays = getWaitingVacationDays().getOrDefault(vacationType, ZERO);
        getWaitingVacationDays().put(vacationType, currentWaitingVacationDays.add(waitingVacationDays));
    }

    public void addAllowedVacationDays(VacationType vacationType, BigDecimal allowedVacationDays) {
        final BigDecimal currentAllowedVacationDays = getAllowedVacationDays().getOrDefault(vacationType, ZERO);
        getAllowedVacationDays().put(vacationType, currentAllowedVacationDays.add(allowedVacationDays));
    }

    public boolean hasVacationType(VacationType type) {
        return waitingVacationDays.containsKey(type) || allowedVacationDays.containsKey(type);
    }

    public BigDecimal getWaitingVacationDays(VacationType type) {
        return waitingVacationDays.getOrDefault(type, ZERO);
    }

    public BigDecimal getAllowedVacationDays(VacationType type) {
        return allowedVacationDays.getOrDefault(type, ZERO);
    }
}

@@ -3071,33 +3071,32 @@
 ionDays() %7B%0A
-%0A
         
 BigDecimal t
@@ -3087,137 +3087,57 @@
     
-BigDecimal total = ZERO;%0A        for (BigDecimal days : getWaitingVacationDays().values()) %7B%0A            total = total.add(days);
+return getWaitingVacationDays().values().stream()
 %0A   
@@ -3141,39 +3141,50 @@
         
-%7D%0A%0A
     
-    return total
+.reduce(ZERO, BigDecimal::add)
 ;%0A    %7D%0A
@@ -3238,25 +3238,24 @@
 ays() %7B%0A
-%0A
         
 BigDecim
@@ -3250,137 +3250,57 @@
     
-BigDecimal total = ZERO;%0A        for (BigDecimal days : getAllowedVacationDays().values()) %7B%0A            total = total.add(days);
+return getAllowedVacationDays().values().stream()
 %0A   
@@ -3308,31 +3308,42 @@
     
-%7D%0A%0A
     
-    return total
+.reduce(ZERO, BigDecimal::add)
 ;%0A  

Use stream reduce instead of for each loop