package io.teiler.server.services;

import java.util.LinkedList;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import io.teiler.server.dto.Compensation;
import io.teiler.server.dto.Debt;
import io.teiler.server.services.util.GroupUtil;
import io.teiler.server.services.util.settleup.PersonChooser;
import io.teiler.server.services.util.settleup.TopBottomChooser;

/**
 * Provides service-methods for suggested compensations.
 *
 * @author dthoma
 */
@Service
public class SuggestCompensationService {

    private static final Logger LOGGER = LoggerFactory.getLogger(SuggestCompensationService.class);

    private SortedMap<Integer, Debt> debts;

    @Autowired
    private GroupUtil groupUtil;

    @Autowired
    private DebtService debtService;

    /**
     * Gets the suggested compensations for this group.
     *
     * @param groupId The group to get the suggested compensations for.
     * @return The suggested compensations for this group
     */
    public List<Compensation> getSuggestedCompensations(String groupId) {
        groupUtil.checkIdExists(groupId);

        this.debts = new TreeMap<>();
        debtService.getDebts(groupId).stream().filter(d -> d.getBalance() != 0)
            .forEach(d -> this.debts.put(d.getBalance(), d));

        List<Compensation> suggestedCompensations = new LinkedList<>();
        PersonChooser personChooser = new TopBottomChooser(debts);

        while (personChooser.personsLeft()) {
            Debt creditor = personChooser.getNextCreditor();
            Debt debitor = personChooser.getNextDebitor();

            if (creditor.getBalance() >= debitor.getBalance()) {
                Compensation compensation = new Compensation(
                    null,
                    - debitor.getBalance(),
                    debitor.getPerson(),
                    creditor.getPerson()
                );
                suggestedCompensations.add(compensation);

                int newCreditorBalance = creditor.getBalance() + debitor.getBalance();
                int newDebitorBalance = 0;

                updateDebts(newCreditorBalance, creditor);
                updateDebts(newDebitorBalance, debitor);
            } else {
                Compensation compensation = new Compensation(
                    null,
                    creditor.getBalance(),
                    debitor.getPerson(),
                    creditor.getPerson()
                );
                suggestedCompensations.add(compensation);

                int newCreditorBalance = 0;
                int newDebitorBalance = debitor.getBalance() + creditor.getBalance();

                updateDebts(newCreditorBalance, creditor);
                updateDebts(newDebitorBalance, debitor);
            }
        }

        LOGGER.debug("View suggested compensations: {}", suggestedCompensations);
        return suggestedCompensations;
    }

    private void updateDebts(int newBalance, Debt debt) {
        this.debts.remove(debt.getBalance(), debt);
        debt.setBalance(newBalance);
        this.debts.put(newBalance, debt);
    }

}

@@ -29,16 +29,268 @@
 vices;%0A%0A
+import io.teiler.server.dto.Compensation;%0Aimport io.teiler.server.dto.Debt;%0Aimport io.teiler.server.services.util.GroupUtil;%0Aimport io.teiler.server.services.util.settleup.PersonChooser;%0Aimport io.teiler.server.services.util.settleup.TopBottomChooser;%0A
 import j
@@ -306,24 +306,24 @@
 LinkedList;%0A
-
 import java.
@@ -387,17 +387,16 @@
 reeMap;%0A
-%0A
 import o
@@ -559,261 +559,8 @@
 e;%0A%0A
-import io.teiler.server.dto.Compensation;%0Aimport io.teiler.server.dto.Debt;%0Aimport io.teiler.server.services.util.GroupUtil;%0Aimport io.teiler.server.services.util.settleup.PersonChooser;%0Aimport io.teiler.server.services.util.settleup.TopBottomChooser;%0A%0A
 /**%0A
@@ -1751,24 +1751,95 @@
 Debitor();%0A%0A
+            int newCreditorBalance;%0A            int newDebitorBalance;%0A
             
@@ -2191,36 +2191,32 @@
                 
-int 
 newCreditorBalan
@@ -2274,36 +2274,32 @@
                 
-int 
 newDebitorBalanc
@@ -2308,125 +2308,8 @@
 = 0;
-%0A%0A                updateDebts(newCreditorBalance, creditor);%0A                updateDebts(newDebitorBalance, debitor);
 %0A   
@@ -2625,36 +2625,32 @@
                 
-int 
 newCreditorBalan
@@ -2665,36 +2665,32 @@
                 
-int 
 newDebitorBalanc
@@ -2735,29 +2735,38 @@
 tBalance();%0A
-%0A
+        
     
+%7D%0A
             
@@ -2812,36 +2812,32 @@
 r);%0A            
-    
 updateDebts(newD
@@ -2861,30 +2861,16 @@
 bitor);%0A
-            %7D%0A
         

Move duplicated code in SuggestCompensationService