package org.mifos.clientportfolio.newloan.domain;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.LocalDate;
import org.mifos.accounts.productdefinition.util.helpers.GraceType;
import org.mifos.accounts.util.helpers.InstallmentDate;
import org.mifos.application.holiday.business.Holiday;
import org.mifos.application.holiday.persistence.HolidayDao;
import org.mifos.config.FiscalCalendarRules;
import org.mifos.schedule.ScheduledDateGeneration;
import org.mifos.schedule.ScheduledEvent;
import org.mifos.schedule.internal.HolidayAndWorkingDaysAndMoratoriaScheduledDateGeneration;

public class AnyScheduledEventLoanInstallmentGenerator implements LoanInstallmentGenerator {

	private final ScheduledEvent scheduledEvent;
	private final HolidayDao holidayDao;

	public AnyScheduledEventLoanInstallmentGenerator(ScheduledEvent scheduledEvent, HolidayDao holidayDao) {
		this.scheduledEvent = scheduledEvent;
		this.holidayDao = holidayDao;
	}

	@Override
	public List<InstallmentDate> generate(LocalDate actualDisbursementDate, int numberOfInstallments, GraceType graceType, int gracePeriodDuration, Short officeId) {
		
		List<InstallmentDate> installmentDates = new ArrayList<InstallmentDate>();
		
        if (numberOfInstallments > 0) {
            List<Days> workingDays = new FiscalCalendarRules().getWorkingDaysAsJodaTimeDays();
            List<Holiday> holidays = new ArrayList<Holiday>();

            LocalDate startFromMeetingDate = actualDisbursementDate.plusDays(1);

            holidays = holidayDao.findAllHolidaysFromDateAndNext(officeId, startFromMeetingDate.toString());

            final int occurrences = numberOfInstallments + gracePeriodDuration;

            ScheduledDateGeneration dateGeneration = new HolidayAndWorkingDaysAndMoratoriaScheduledDateGeneration(workingDays, holidays);

            List<Date> dueDates = new ArrayList<Date>();
            List<DateTime> installmentDateTimes = dateGeneration.generateScheduledDates(occurrences, startFromMeetingDate.toDateMidnight().toDateTime(), scheduledEvent);
            for (DateTime installmentDate : installmentDateTimes) {
                dueDates.add(installmentDate.toDate());
            }

            installmentDates = createInstallmentDates(gracePeriodDuration, dueDates);
        }
		
		return installmentDates;
	}
	
    private List<InstallmentDate> createInstallmentDates(final int installmentToSkip, final List<Date> dueDates) {
        List<InstallmentDate> installmentDates = new ArrayList<InstallmentDate>();
        int installmentId = 1;
        for (Date date : dueDates) {
            installmentDates.add(new InstallmentDate((short) installmentId++, date));
        }
        removeInstallmentsNeedNotPay(installmentToSkip, installmentDates);
        return installmentDates;
    }

    private void removeInstallmentsNeedNotPay(final int installmentSkipToStartRepayment, final List<InstallmentDate> installmentDates) {
        int removeCounter = 0;
        for (int i = 0; i < installmentSkipToStartRepayment; i++) {
            installmentDates.remove(removeCounter);
        }
        // re-adjust the installment ids
        if (installmentSkipToStartRepayment > 0) {
            int count = installmentDates.size();
            for (int i = 0; i < count; i++) {
                InstallmentDate instDate = installmentDates.get(i);
                instDate.setInstallmentId(new Short(Integer.toString(i + 1)));
            }
        }
    }
}
@@ -1702,22 +1702,16 @@
         
-final 
 int occu
@@ -1740,18 +1740,111 @@
 allments
+;%0A            if (graceType == GraceType.GRACEONALLREPAYMENTS) %7B%0A                occurrences
  +
+=
  gracePe
@@ -1856,16 +1856,30 @@
 uration;
+%0A            %7D
 %0A%0A      
@@ -2435,39 +2435,180 @@
 tes(
-gracePeriodDuration, dueDates);
+dueDates);%0A            if (graceType == GraceType.GRACEONALLREPAYMENTS) %7B%0A                removeInstallmentsNeedNotPay(gracePeriodDuration, installmentDates);%0A            %7D
 %0A   
@@ -2716,37 +2716,8 @@
 nal 
-int installmentToSkip, final 
 List
@@ -2986,82 +2986,8 @@
   %7D%0A
-        removeInstallmentsNeedNotPay(installmentToSkip, installmentDates);
 %0A   

fix schedule generation when grace periods are used.