// Copyright (c) 2016, Miquel Martí <miquelmarti111@gmail.com>
// See LICENSE for licensing information

package cat.mvmike.minimalcalendarwidget.domain.entry;

import android.content.Context;
import android.widget.RemoteViews;

import java.time.LocalDate;
import java.util.Set;

import cat.mvmike.minimalcalendarwidget.domain.configuration.ConfigurationService;
import cat.mvmike.minimalcalendarwidget.domain.configuration.item.Colour;
import cat.mvmike.minimalcalendarwidget.domain.configuration.item.Symbol;
import cat.mvmike.minimalcalendarwidget.domain.configuration.item.Theme;
import cat.mvmike.minimalcalendarwidget.infrastructure.SystemResolver;

import static java.time.temporal.ChronoField.DAY_OF_MONTH;
import static java.time.temporal.ChronoField.DAY_OF_WEEK;
import static java.time.temporal.ChronoUnit.DAYS;

public final class DayService {

    private static final String PADDING = " ";

    private static final int MONTH_FIRST_DAY = 1;

    private static final int MAXIMUM_DAYS_IN_MONTH = 31;

    private static final int NUM_WEEKS = 6;

    private static final int DAYS_IN_WEEK = 7;

    public static void setDays(final Context context, final RemoteViews remoteViews, final Set<Instance> instanceSet) {

        int firstDayOfWeek = ConfigurationService.getStartWeekDay(context).ordinal();
        Theme theme = ConfigurationService.getTheme(context);
        Symbol symbol = ConfigurationService.getInstancesSymbols(context);
        Colour colour = ConfigurationService.getInstancesSymbolsColours(context);

        LocalDate systemLocalDate = SystemResolver.get().getSystemLocalDate();
        LocalDate iterationLocalDate = getInitialLocalDate(systemLocalDate, firstDayOfWeek);

        RemoteViews rowRv;
        for (int week = 0; week < NUM_WEEKS; week++) {

            rowRv = SystemResolver.get().createRow(context);

            Day ds;
            RemoteViews cellRv;
            for (int day = 0; day < DAYS_IN_WEEK; day++) {

                ds = new Day(systemLocalDate, iterationLocalDate);
                cellRv = SystemResolver.get().createDay(context, getDayLayout(theme, ds));

                int numberOfInstances = getNumberOfInstances(instanceSet, ds);
                int color = ds.isToday() ?
                    SystemResolver.get().getColorInstancesTodayId(context) :
                    SystemResolver.get().getColorInstancesId(context, colour);

                SystemResolver.get().addDayCellRemoteView(
                    context,
                    rowRv,
                    cellRv,
                    PADDING + ds.getDayOfMonthString() + PADDING + symbol.getSymbol(numberOfInstances),
                    ds.isToday(),
                    ds.isSingleDigitDay(),
                    symbol.getRelativeSize(),
                    color);

                iterationLocalDate = iterationLocalDate.plus(1, DAYS);
            }

            SystemResolver.get().addRowToWidget(remoteViews, rowRv);
        }
    }

    static int getDayLayout(final Theme theme, final Day ds) {

        if (ds.isToday()) {
            return theme.getCellToday(ds.getDayOfWeek());
        }

        if (ds.inMonth()) {
            return theme.getCellThisMonth(ds.getDayOfWeek());
        }

        return theme.getCellNotThisMonth();
    }

    static int getNumberOfInstances(final Set<Instance> instanceSet, final Day ds) {

        if (instanceSet == null || instanceSet.isEmpty()) {
            return 0;
        }

        return (int) instanceSet.stream()
            .filter(instance -> ds.isInDay(instance.getStart(), instance.getEnd(), instance.isAllDay()))
            .count();
    }

    static LocalDate getInitialLocalDate(final LocalDate systemLocalDate, final int firstDayOfWeek) {

        LocalDate firstDayOfMonth = LocalDate.of(systemLocalDate.getYear(), systemLocalDate.getMonthValue(), MONTH_FIRST_DAY);

        int difference = firstDayOfWeek - firstDayOfMonth.get(DAY_OF_WEEK) + 1;
        LocalDate localDate = firstDayOfMonth.plus(difference, DAYS);

        // overlap month manually if dayOfMonth is in current month and greater than 1
        if (localDate.get(DAY_OF_MONTH) > MONTH_FIRST_DAY
            && localDate.get(DAY_OF_MONTH) < (MAXIMUM_DAYS_IN_MONTH / 2)) {
            return localDate.minus(DAYS_IN_WEEK, DAYS);
        }

        return localDate;
    }
}
@@ -271,16 +271,51 @@
 til.Set;
+%0Aimport java.util.stream.IntStream;
 %0A%0Aimport
@@ -1562,32 +1562,38 @@
 text);%0A%0A        
+final 
 LocalDate system
@@ -1647,24 +1647,25 @@
 Date();%0A
+%0A
         
 LocalDat
@@ -1660,173 +1660,53 @@
     
-LocalDate iterationLocalDate = getInitialLocalDate(systemLocalDate, firstDayOfWeek);%0A%0A        RemoteViews rowRv;%0A        for (int week = 0; week %3C NUM_WEEKS; 
+IntStream.range(0, NUM_WEEKS).forEach(
 week
-++)
+ -%3E
  %7B%0A%0A
@@ -1713,24 +1713,36 @@
             
+RemoteViews 
 rowRv = Syst
@@ -1795,83 +1795,161 @@
     
-Day ds;%0A            RemoteViews cellRv;%0A            for (int day = 0; day %3C
+IntStream.range(0, DAYS_IN_WEEK).forEach(day -%3E %7B%0A%0A                LocalDate localDate = getInitialLocalDate(systemLocalDate, firstDayOfWeek).plus(week *
  DAY
@@ -1961,19 +1961,22 @@
 WEEK
-;
+ +
  day
-++) %7B%0A
+, DAYS);
 %0A   
@@ -1988,18 +1988,30 @@
         
-ds
+Day currentDay
  = new D
@@ -2030,26 +2030,17 @@
 alDate, 
-iterationL
+l
 ocalDate
@@ -2054,24 +2054,36 @@
             
+RemoteViews 
 cellRv = Sys
@@ -2139,18 +2139,26 @@
 (theme, 
-ds
+currentDay
 ));%0A%0A   
@@ -2228,18 +2228,26 @@
 nceSet, 
-ds
+currentDay
 );%0A     
@@ -2269,18 +2269,26 @@
 color = 
-ds
+currentDay
 .isToday
@@ -2540,55 +2540,15 @@
 ext,
-%0A                    rowRv,%0A                   
+ rowRv,
  cel
@@ -2582,18 +2582,26 @@
 DDING + 
-ds
+currentDay
 .getDayO
@@ -2684,18 +2684,26 @@
         
-ds
+currentDay
 .isToday
@@ -2709,71 +2709,39 @@
 y(),
-%0A                    ds.isSingleDigitDay(),%0A                   
+ currentDay.isSingleDigitDay(),
  sym
@@ -2762,36 +2762,16 @@
 eSize(),
-%0A                   
  color);
@@ -2767,27 +2767,24 @@
 (), color);%0A
-%0A  
             
@@ -2787,78 +2787,11 @@
     
-  iterationLocalDate = iterationLocalDate.plus(1, DAYS);%0A            %7D
+%7D);
 %0A%0A  
@@ -2866,16 +2866,19 @@
        %7D
+);%0A
 %0A    %7D%0A%0A

use IntStream for iteration and enforce immutability