package be.raildelays.batch.decider;

import be.raildelays.domain.xls.ExcelRow;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
import org.springframework.batch.core.job.flow.JobExecutionDecider;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.batch.repeat.support.RepeatTemplate;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;

import java.time.LocalDate;
import java.time.Period;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Date;

/**
 * Read all {@link be.raildelays.domain.xls.ExcelRow} given in {@link ItemReader} and store the start date and the end date.
 * If the difference between start and end is greater or equal to the {@code maxNumberOfMonth} then we return the status
 * {@link #COMPLETED_WITH_MAX_MONTHS} on which you can branch another flow.
 *
 * The threshold {@link Date} is stored in the {@code jobExecutionContext} via the key {@code 'threshold.date'}.
 *
 * @author Almex
 * @since 1.2
 */
public class MaxMonthsDecider implements JobExecutionDecider, InitializingBean {

    public static final FlowExecutionStatus COMPLETED_WITH_MAX_MONTHS = new FlowExecutionStatus("COMPLETED_WITH_MAX_MONTHS");
    private ItemReader<ExcelRow> reader;
    private Date minimum;
    private Date maximum;
    private long maxNumberOfMonth;
    // Must be a field to be modifiable inside a lambda expression
    private FlowExecutionStatus finalStatus = FlowExecutionStatus.COMPLETED;

    @Override
    public void afterPropertiesSet() throws Exception {
        Assert.notNull(this.maxNumberOfMonth, "The 'maxNumberOfMonth' property must be provided");
        Assert.notNull(this.reader, "The 'reader' property must be provided");
    }

    @Override
    public FlowExecutionStatus decide(final JobExecution jobExecution, final StepExecution stepExecution) {
        new RepeatTemplate().iterate((context) -> {
            RepeatStatus result = RepeatStatus.CONTINUABLE;
            ExcelRow item = reader.read();

            if (item != null) {
                if (maximum == null || maximum.before(item.getDate())) {
                    maximum = item.getDate();
                }

                if (minimum == null || minimum.after(item.getDate())) {
                    minimum = item.getDate();
                }

                LocalDate startDate = minimum.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
                LocalDate endDate = maximum.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
                Period period = Period.between(startDate, endDate);

                if (period.get(ChronoUnit.MONTHS) >= maxNumberOfMonth) {
                    this.finalStatus = COMPLETED_WITH_MAX_MONTHS;
                    result = RepeatStatus.FINISHED;
                    jobExecution.getExecutionContext().put("threshold.date", maximum);
                }
            } else {
                result = RepeatStatus.FINISHED;
            }

            return result;
        });

        return this.finalStatus;
    }

    public void setReader(ItemReader<ExcelRow> reader) {
        this.reader = reader;
    }

    public void setMaxNumberOfMonth(long maxNumberOfMonth) {
        this.maxNumberOfMonth = maxNumberOfMonth;
    }

}

@@ -816,45 +816,41 @@
 and 
-sto
+compa
 re the 
-star
+firs
 t date 
-and the end date
+with today
 .%0A *
@@ -880,21 +880,23 @@
 een 
-start and end
+those two dates
  is 
@@ -1044,24 +1044,29 @@
 her flow.%0A *
+ %3Cp/%3E
 %0A * The thre
@@ -1470,226 +1470,193 @@
 ate 
-Date minimum;%0A    private Date maximum;%0A    private long maxNumberOfMonth;%0A    // Must be a field to be modifiable inside a lambda expression%0A    private FlowExecutionStatus finalStatus = FlowExecutionStatus.COMPLETED;
+long maxNumberOfMonth;%0A    private FlowExecutionStatus finalStatus; // To be accessible by the Lambda expression%0A    private Date firstDate; // To be accessible by the Lambda expression
 %0A%0A  
@@ -2026,24 +2026,155 @@
 xecution) %7B%0A
+        final LocalDate now = LocalDate.now();%0A%0A        finalStatus = FlowExecutionStatus.COMPLETED; // By default it's COMPLETED%0A%0A
         new 
@@ -2373,153 +2373,17 @@
 if (
-maximum == null %7C%7C maximum.before(item.getDate())) %7B%0A                    maximum = item.getDate();%0A                %7D%0A%0A                if (minimum
+firstDate
  == 
@@ -2390,23 +2390,25 @@
 null %7C%7C 
-minimum
+firstDate
 .after(i
@@ -2445,23 +2445,25 @@
         
-minimum
+firstDate
  = item.
@@ -2534,15 +2534,17 @@
 e = 
-minimum
+firstDate
 .toI
@@ -2638,72 +2638,11 @@
 e = 
-maximum.toInstant().atZone(ZoneId.systemDefault()).toLocalDate()
+now
 ;%0A  
@@ -2704,24 +2704,170 @@
  endDate);%0A%0A
+                /**%0A                 * If the period between the first date and today is greater or equal to maxNumberOfMonth%0A                 */%0A
             
@@ -2947,21 +2947,16 @@
         
-this.
 finalSta
@@ -3064,72 +3064,281 @@
     
-jobExecution.getExecutionContext().put(%22threshold.date%22, maximum
+// We store the threshold date in the context%0A                    jobExecution.getExecutionContext().put(%22threshold.date%22, Date.from(%0A                                    now.atStartOfDay(ZoneId.systemDefault()).toInstant()%0A                            )%0A                    
 );%0A 
@@ -3493,21 +3493,16 @@
  return 
-this.
 finalSta
@@ -3727,8 +3727,9 @@
    %7D%0A%0A%7D%0A
+%0A

Use today as the threshold date