package com.github.kazuki43zoo.domain.service.calendar;
import com.github.kazuki43zoo.domain.model.calendar.FixedHoliday;
import com.github.kazuki43zoo.domain.model.calendar.HappyMondayHoliday;
import com.github.kazuki43zoo.domain.model.calendar.Holiday;
import com.github.kazuki43zoo.domain.model.calendar.SeasonalHoliday;
import com.github.kazuki43zoo.domain.repository.calendar.FixedHolidayRepository;
import com.github.kazuki43zoo.domain.repository.calendar.HappyMondayHolidayRepository;
import com.github.kazuki43zoo.domain.repository.calendar.SeasonalHolidayRepository;
import org.joda.time.DateTimeConstants;
import org.joda.time.LocalDate;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import java.util.*;
@Service
public final class CalendarSharedServiceImpl implements CalendarSharedService {
@Inject
FixedHolidayRepository fixedHolidayRepository;
@Inject
HappyMondayHolidayRepository happyMondayHolidayRepository;
@Inject
SeasonalHolidayRepository seasonalHolidayRepository;
private Map<Integer, List<FixedHoliday>> fixedHolidaysMapping;
private Map<Integer, List<HappyMondayHoliday>> happyMondayHolidaysMapping;
private Map<LocalDate, List<SeasonalHoliday>> seasonalHolidaysMapping;
@PostConstruct
public void loadHolidays() {
loadFixedHolidays();
loadHappyMondayHolidays();
loadSeasonalHolidays();
}
private void loadFixedHolidays() {
final Map<Integer, List<FixedHoliday>> fixedHolidaysMapping = new HashMap<>();
final List<FixedHoliday> fixedHolidays = fixedHolidayRepository.findAll();
for (final FixedHoliday fixedHoliday : fixedHolidays) {
List<FixedHoliday> fixedHolidaysOfMonth =
fixedHolidaysMapping.get(fixedHoliday.getTargetMonth());
if (fixedHolidaysOfMonth == null) {
fixedHolidaysOfMonth = new ArrayList<>();
fixedHolidaysMapping.put(fixedHoliday.getTargetMonth(), fixedHolidaysOfMonth);
}
fixedHolidaysOfMonth.add(fixedHoliday);
}
this.fixedHolidaysMapping = Collections.unmodifiableMap(fixedHolidaysMapping);
}
private void loadHappyMondayHolidays() {
final Map<Integer, List<HappyMondayHoliday>> happyMondayHolidaysMapping = new HashMap<>();
final List<HappyMondayHoliday> happyMondayHolidays = happyMondayHolidayRepository.findAll();
for (final HappyMondayHoliday happyMondayHoliday : happyMondayHolidays) {
List<HappyMondayHoliday> happyMondayHolidaysOfMonth =
happyMondayHolidaysMapping.get(happyMondayHoliday.getTargetMonth());
if (happyMondayHolidaysOfMonth == null) {
happyMondayHolidaysOfMonth = new ArrayList<>();
happyMondayHolidaysMapping.put(happyMondayHoliday.getTargetMonth(), happyMondayHolidaysOfMonth);
}
happyMondayHolidaysOfMonth.add(happyMondayHoliday);
}
this.happyMondayHolidaysMapping = Collections.unmodifiableMap(happyMondayHolidaysMapping);
}
private void loadSeasonalHolidays() {
final Map<LocalDate, List<SeasonalHoliday>> seasonalHolidaysMapping = new HashMap<>();
final List<SeasonalHoliday> seasonalHolidays = seasonalHolidayRepository.findAll();
for (final SeasonalHoliday seasonalHoliday : seasonalHolidays) {
final LocalDate month = seasonalHoliday.getTargetDate().dayOfMonth().withMinimumValue();
List<SeasonalHoliday> seasonalHolidaysOfMonth = seasonalHolidaysMapping.get(month);
if (seasonalHolidaysOfMonth == null) {
seasonalHolidaysOfMonth = new ArrayList<>();
seasonalHolidaysMapping.put(month, seasonalHolidaysOfMonth);
}
seasonalHolidaysOfMonth.add(seasonalHoliday);
}
this.seasonalHolidaysMapping = Collections.unmodifiableMap(seasonalHolidaysMapping);
}
@Override
public Map<LocalDate, Holiday> getHolidays(final LocalDate month) {
final Map<LocalDate, Holiday> holidays = new LinkedHashMap<>();
pickupFixedHolidays(month, holidays);
pickupHappyMondayHolidays(month, holidays);
pickupSeasonalHolidays(month, holidays);
return holidays;
}
private void pickupFixedHolidays(final LocalDate month, final Map<LocalDate, Holiday> holidays) {
final List<FixedHoliday> fixedHolidays = fixedHolidaysMapping.get(month.getMonthOfYear());
if (fixedHolidays == null) {
return;
}
for (final FixedHoliday fixedHoliday : fixedHolidays) {
if (!((fixedHoliday.getBeginYear() <= month.getYear()) && (month.getYear() <= fixedHoliday.getEndYear()))) {
continue;
}
LocalDate targetDate = month.withDayOfMonth(fixedHoliday.getTargetDay());
if (targetDate.getDayOfWeek() == DateTimeConstants.SUNDAY && fixedHoliday.getTransferredLaterDays() != null) {
targetDate = targetDate.plusDays(fixedHoliday.getTransferredLaterDays());
}
holidays.put(targetDate, fixedHoliday);
}
}
private void pickupHappyMondayHolidays(final LocalDate month, final Map<LocalDate, Holiday> holidays) {
final List<HappyMondayHoliday> happyMondayHolidays = happyMondayHolidaysMapping.get(month.getMonthOfYear());
if (happyMondayHolidays == null) {
return;
}
for (final HappyMondayHoliday happyMondayHoliday : happyMondayHolidays) {
if (!((happyMondayHoliday.getBeginYear() <= month.getYear()) && (month.getYear() <= happyMondayHoliday.getEndYear()))) {
continue;
}
int plusWeeks = happyMondayHoliday.getTargetWeek();
if (month.getDayOfWeek() == DateTimeConstants.MONDAY) {
plusWeeks--;
}
final LocalDate targetDate = month.plusWeeks(plusWeeks).dayOfWeek().withMinimumValue();
holidays.put(targetDate, happyMondayHoliday);
}
}
private void pickupSeasonalHolidays(final LocalDate month, final Map<LocalDate, Holiday> holidays) {
final List<SeasonalHoliday> seasonalHolidays = seasonalHolidaysMapping.get(month);
if (seasonalHolidays == null) {
return;
}
for (final SeasonalHoliday seasonalHoliday : seasonalHolidays) {
LocalDate targetDate = seasonalHoliday.getTargetDate();
if (targetDate.getDayOfWeek() == DateTimeConstants.SUNDAY) {
targetDate = targetDate.plusDays(1);
}
holidays.put(targetDate, seasonalHoliday);
}
}
}