/* * 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; import com.google.common.collect.Iterables; import kr.debop4j.core.Guard; import kr.debop4j.core.NotSupportException; import kr.debop4j.timeperiod.tools.TimeSpec; import kr.debop4j.timeperiod.tools.Times; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.joda.time.DateTime; import org.joda.time.Duration; import javax.validation.constraints.NotNull; import java.util.*; /** * 요소로 {@link ITimePeriod} 를 가지는 컨테이너를 표현합니다. * * @author 배성혁 sunghyouk.bae@gmail.com * @since 13. 5. 12. 오전 2:20 */ @Slf4j public class TimePeriodContainer implements ITimePeriodContainer { private static final long serialVersionUID = -7112720659283751048L; @Getter protected final List<ITimePeriod> periods = new ArrayList<ITimePeriod>(); public TimePeriodContainer() {} public TimePeriodContainer(ITimePeriod... periods) { Collections.addAll(this.periods, periods); } public TimePeriodContainer(Iterable<? extends ITimePeriod> collection) { if (collection != null) Iterables.addAll(periods, collection); } @Override public void setStart(DateTime value) { if (size() > 0) move(new Duration(getStart(), value)); } @Override public void setEnd(DateTime value) { if (size() > 0) move(new Duration(getEnd(), value)); } @Override public DateTime getStart() { if (size() == 0) return TimeSpec.MinPeriodTime; DateTime min = periods.get(0).getStart(); for (ITimePeriod period : periods) { if (period.getStart().compareTo(min) < 0) { min = period.getStart(); } } return min; } @Override public DateTime getEnd() { if (size() == 0) return TimeSpec.MaxPeriodTime; DateTime max = periods.get(0).getEnd(); for (ITimePeriod period : periods) { if (period.getEnd().compareTo(max) > 0) { max = period.getEnd(); } } return max; } @Override public Duration getDuration() { return hasPeriod() ? new Duration(getStart(), getEnd()) : TimeSpec.MaxDuration; } @Override public boolean hasStart() { return getStart() != TimeSpec.MinPeriodTime; } @Override public boolean hasEnd() { return getEnd() != TimeSpec.MaxPeriodTime; } @Override public boolean hasPeriod() { return hasStart() && hasEnd(); } @Override public boolean isMoment() { return hasStart() && getStart().equals(getEnd()); } @Override public boolean isAnytime() { return !hasStart() && !hasEnd(); } @Override public boolean isReadonly() { return false; } @Override public void setup(DateTime ns, DateTime ne) { throw new NotSupportException("TimePeriodContainer에서는 setup 메소드를 지원하지 않습니다."); } @Override public ITimePeriod copy(Duration offset) { throw new NotSupportException("TimePeriodContainer에서는 copy 메소드를 지원하지 않습니다."); } @Override public void move(Duration offset) { if (offset == null || offset.getMillis() == 0) return; log.trace("모든 기간을 offset[{}] 만큼 이동합니다.", offset); for (ITimePeriod period : this.periods) period.move(offset); } @Override public boolean isSamePeriod(ITimePeriod other) { return getStart().equals(other.getStart()) && getEnd().equals(other.getEnd()); } @Override public boolean hasInside(DateTime moment) { return Times.hasInside(this, moment); } @Override public boolean hasInside(ITimePeriod other) { return Times.hasInside(this, other); } @Override public boolean intersectsWith(ITimePeriod other) { return Times.intersectsWith(this, other); } @Override public boolean overlapsWith(ITimePeriod other) { return Times.overlapsWith(this, other); } @Override public void reset() { this.periods.clear(); } @Override public PeriodRelation getRelation(ITimePeriod other) { return Times.getRelation(this, other); } @Override public ITimePeriod getIntersection(ITimePeriod other) { return Times.getIntersectionRange(this, other); } @Override public ITimePeriod getUnion(ITimePeriod other) { return Times.getUnionRange(this, other); } /** 지정한 기간을 포함하는지 여부 */ @Override public boolean containsPeriod(ITimePeriod target) { Guard.shouldNotBeNull(target, "target"); for (ITimePeriod period : this.periods) if (period.isSamePeriod(target)) return true; return false; } /** * 모든 기간들을 추가합니다. * * @param periods 추가할 기간들 */ @Override public void addAll(final Iterable<? extends ITimePeriod> periods) { Iterables.addAll(this.periods, periods); } /** * 시작시각으로 정렬을 수행합니다. * * @param sortDir 정렬 방식 (순차|역순) */ @Override public void sortByStart(OrderDirection sortDir) { if (sortDir == OrderDirection.ASC) { Collections.sort(periods, Times.getStartComparator()); } else { Collections.sort(periods, Times.getStartDescComparator()); } } /** * 완료시각으로 정렬을 수행합니다. * * @param sortDir 정렬 방식 (순차|역순) */ @Override public void sortByEnd(OrderDirection sortDir) { if (sortDir == OrderDirection.ASC) { Collections.sort(periods, Times.getEndComparator()); } else { Collections.sort(periods, Times.getEndDescComparator()); } } /** * Duration 속성값으로 정렬을 수행합니다. * * @param sortDir 정렬 방식 (순차|역순) */ @Override public void sortByDuration(OrderDirection sortDir) { if (sortDir == OrderDirection.ASC) { Collections.sort(periods, Times.getDurationComparator()); } else { Collections.sort(periods, Times.getDurationDescComparator()); } } @Override public int compareTo(ITimePeriod o) { return getStart().compareTo(o.getStart()); } @Override public int size() { return periods.size(); } @Override public boolean isEmpty() { return periods.isEmpty(); } @Override public boolean contains(Object o) { return periods.contains(o); } @Override public Iterator<ITimePeriod> iterator() { return this.periods.iterator(); } @Override public Object[] toArray() { return toArray(new TimeRange[size()]); } @Override public <T> T[] toArray(T[] a) { return periods.toArray(a); } @Override public boolean add(ITimePeriod period) { return periods.add(period); } @Override public boolean remove(Object o) { return periods.remove(o); } @Override public boolean containsAll(Collection<?> c) { return periods.containsAll(c); } @Override public synchronized boolean addAll(Collection<? extends ITimePeriod> c) { for (ITimePeriod item : c) periods.add(item); return true; } @Override public synchronized boolean addAll(int index, Collection<? extends ITimePeriod> c) { int start = index; for (ITimePeriod item : c) { periods.add(start, item); start++; } return true; } @Override public boolean removeAll(Collection<?> c) { return periods.removeAll(c); } @Override public boolean retainAll(@NotNull Collection<?> c) { return periods.retainAll(c); } @Override public void clear() { periods.clear(); } @Override public ITimePeriod get(int index) { return periods.get(index); } @Override public ITimePeriod set(int index, ITimePeriod element) { return periods.set(index, element); } @Override public void add(int index, ITimePeriod element) { periods.add(index, element); } @Override public ITimePeriod remove(int index) { return periods.remove(index); } @Override public int indexOf(Object o) { return periods.indexOf(o); } @Override public int lastIndexOf(Object o) { return periods.lastIndexOf(o); } @Override public ListIterator<ITimePeriod> listIterator() { return periods.listIterator(); } @Override public ListIterator<ITimePeriod> listIterator(int index) { return periods.listIterator(index); } @Override public List<ITimePeriod> subList(int fromIndex, int toIndex) { return getPeriods().subList(fromIndex, toIndex); } }