package org.mifos.clientportfolio.newloan.domain;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.mifos.accounts.loan.business.LoanScheduleEntity;
import org.mifos.accounts.loan.business.RepaymentTotals;
import org.mifos.accounts.productdefinition.util.helpers.GraceType;
import org.mifos.accounts.productdefinition.util.helpers.InterestType;
import org.mifos.framework.util.helpers.Money;
public class FirstInstallmentRoudingDifferenceLoanScheduleRounder extends DefaultLoanScheduleRounder {
public FirstInstallmentRoudingDifferenceLoanScheduleRounder(LoanScheduleRounderHelper loanScheduleInstallmentRounder) {
super(loanScheduleInstallmentRounder);
}
@Override
public List<LoanScheduleEntity> round(GraceType graceType, Short gracePeriodDuration, Money loanAmount,
InterestType interestType, List<LoanScheduleEntity> unroundedLoanSchedules,
List<LoanScheduleEntity> allExistingLoanSchedules) {
if (!interestType.equals(InterestType.FLAT)) {
return super.round(graceType, gracePeriodDuration, loanAmount, interestType, unroundedLoanSchedules,
allExistingLoanSchedules);
}
Collections.sort(unroundedLoanSchedules);
List<LoanScheduleEntity> roundedLoanSchedules = new ArrayList<LoanScheduleEntity>();
RepaymentTotals totals = loanScheduleInstallmentRounder.calculateInitialTotals_v2(unroundedLoanSchedules,
loanAmount, allExistingLoanSchedules);
Integer gracePeriodInstallmentsCount = countGracePeriodInstallments(unroundedLoanSchedules, graceType,
gracePeriodDuration);
roundGracePeriodInstallments(gracePeriodInstallmentsCount, graceType, gracePeriodDuration,
unroundedLoanSchedules, roundedLoanSchedules, totals);
roundNonGracePeriodInstallments(gracePeriodInstallmentsCount, unroundedLoanSchedules, roundedLoanSchedules,
totals);
Collections.sort(roundedLoanSchedules);
return roundedLoanSchedules;
}
private int countGracePeriodInstallments(List<LoanScheduleEntity> unroundedLoanSchedules, GraceType graceType,
Short gracePeriodDuration) {
for (int installmentNum = 1; installmentNum <= unroundedLoanSchedules.size(); installmentNum++) {
if (!loanScheduleInstallmentRounder.isGraceInstallment_v2(installmentNum, graceType, gracePeriodDuration)) {
return installmentNum - 1;
}
}
return unroundedLoanSchedules.size();
}
private void roundGracePeriodInstallments(Integer gracePeriodInstallmentsCount, GraceType graceType,
Short gracePeriodDuration, List<LoanScheduleEntity> unroundedLoanSchedules,
List<LoanScheduleEntity> roundedLoanSchedules, RepaymentTotals totals) {
int installmentNum = 0;
while (installmentNum < gracePeriodInstallmentsCount) {
LoanScheduleEntity currentInstallment = unroundedLoanSchedules.get(installmentNum);
LoanScheduleEntity roundedInstallment = currentInstallment;
installmentNum++;
roundedInstallment = loanScheduleInstallmentRounder.roundAndAdjustGraceInstallment_v2(roundedInstallment);
loanScheduleInstallmentRounder.updateRunningTotals_v2(totals, roundedInstallment);
roundedLoanSchedules.add(roundedInstallment);
}
}
private void roundNonGracePeriodInstallments(Integer gracePeriodInstallmentsCount,
List<LoanScheduleEntity> unroundedLoanSchedules, List<LoanScheduleEntity> roundedLoanSchedules,
RepaymentTotals totals) {
int installmentNum;
for (installmentNum = unroundedLoanSchedules.size() - 1; installmentNum >= gracePeriodInstallmentsCount; installmentNum--) {
LoanScheduleEntity currentInstallment = unroundedLoanSchedules.get(installmentNum);
LoanScheduleEntity roundedInstallment = currentInstallment;
if (installmentNum != gracePeriodInstallmentsCount) {
loanScheduleInstallmentRounder.roundAndAdjustButLastNonGraceInstallment_v2(roundedInstallment);
loanScheduleInstallmentRounder.updateRunningTotals_v2(totals, roundedInstallment);
} else {
loanScheduleInstallmentRounder.roundAndAdjustLastInstallment_v2(roundedInstallment, totals);
}
roundedLoanSchedules.add(roundedInstallment);
}
}
}