/* * Copyright 2011-2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package kr.debop4j.timeperiod.calendars.seeker; import kr.debop4j.timeperiod.*; import kr.debop4j.timeperiod.calendars.CalendarVisitor; import kr.debop4j.timeperiod.calendars.CalendarVisitorFilter; import kr.debop4j.timeperiod.timerange.DayRange; import kr.debop4j.timeperiod.timerange.MonthRange; import kr.debop4j.timeperiod.timerange.YearRange; import kr.debop4j.timeperiod.timerange.YearRangeCollection; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import static kr.debop4j.core.Guard.shouldNotBeNull; /** * 일(Day) 단위로 탐색하는 탐색기입니다. * * @author 배성혁 sunghyouk.bae@gmail.com * @since 13. 5. 20. 오후 8:46 */ @Slf4j public class DaySeeker extends CalendarVisitor<CalendarVisitorFilter, DaySeekerContext> { @Getter private final ITimePeriodCollection periods = new TimePeriodCollection(); // region << Constructor >> public DaySeeker() { this(SeekDirection.Forward, TimeCalendar.getDefault()); } public DaySeeker(CalendarVisitorFilter filter) { this(filter, SeekDirection.Forward, TimeCalendar.getDefault()); } public DaySeeker(SeekDirection seekDir) { this(new CalendarVisitorFilter(), seekDir, TimeCalendar.getDefault()); } public DaySeeker(SeekDirection seekDir, ITimeCalendar calendar) { this(new CalendarVisitorFilter(), seekDir, calendar); } public DaySeeker(CalendarVisitorFilter filter, SeekDirection seekDir, ITimeCalendar calendar) { super(filter, TimeRange.Anytime, seekDir, calendar); } // endregion /** * 기준일로부터 offset 만큼의 일수가 지난 후의 일자를 구합니다. (제외되는 날을 고려) * * @param startDay 기준일 * @param dayCount 이후 일수 * @return 기준일로부터 dayCount 만큼 떨어진 일자 */ public DayRange findDay(DayRange startDay, int dayCount) { if (DaySeeker.log.isTraceEnabled()) DaySeeker.log.trace("Day 찾기... startDay=[{}], dayCount=[{}]", startDay, dayCount); if (dayCount == 0) return startDay; DaySeekerContext context = new DaySeekerContext(startDay, dayCount); SeekDirection visitDir = getSeekDirection(); if (dayCount < 0) visitDir = (visitDir == SeekDirection.Forward) ? SeekDirection.Backward : SeekDirection.Forward; startDayVisit(startDay, context, visitDir); if (DaySeeker.log.isTraceEnabled()) DaySeeker.log.trace("Day 찾기... startDay=[{}], dayCount=[{}], foundDay=[{}]", startDay, dayCount, context.getFoundDay()); return context.getFoundDay(); } @Override protected boolean enterYears(YearRangeCollection yearRangeCollection, DaySeekerContext context) { return !context.isFinished(); } @Override protected boolean enterMonths(YearRange yearRange, DaySeekerContext context) { return !context.isFinished(); } @Override protected boolean enterDays(MonthRange month, DaySeekerContext context) { return !context.isFinished(); } @Override protected boolean enterHours(DayRange day, DaySeekerContext context) { // Day 단위로 탐색을 수행하므로, 시간 단위는 필요없습니다. return false; } @Override protected boolean onVisitDay(DayRange day, DaySeekerContext context) { shouldNotBeNull(day, "day"); if (context.isFinished()) return false; if (day.isSamePeriod(context.getStartDay())) return true; if (!isMatchingDay(day, context)) return true; if (!checkLimits(day)) return true; context.processDay(day); // context가 찾기를 완료하면, 탐색(visit) 중단하도록 합니다. return !context.isFinished(); } }