/* * 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 kr.debop4j.core.tools.HashTool; import kr.debop4j.timeperiod.tools.TimeSpec; import kr.debop4j.timeperiod.tools.Times; import lombok.extern.slf4j.Slf4j; import org.joda.time.DateTime; import org.joda.time.Duration; import static kr.debop4j.core.Guard.firstNotNull; /** * kr.debop4j.timeperiod.TimeInterval * * @author 배성혁 sunghyouk.bae@gmail.com * @since 13. 5. 11. 오후 9:06 */ @Slf4j public class TimeInterval extends TimePeriodBase implements ITimeInterval { private static final long serialVersionUID = 5941695883167563118L; public static TimeInterval Anytime = new TimeInterval(TimeSpec.MinPeriodTime, TimeSpec.MaxPeriodTime, IntervalEdge.Closed, IntervalEdge.Closed, false, true); public static TimeRange toRange(ITimeInterval interval) { if (interval == null) return null; return interval.isAnytime() ? TimeRange.Anytime : new TimeRange(interval.getStartInterval(), interval.getEndInterval(), interval.isReadonly()); } public static TimeBlock toBlock(ITimeInterval interval) { if (interval == null) return null; return interval.isAnytime() ? TimeBlock.Anytime : new TimeBlock(interval.getStartInterval(), interval.getEndInterval(), interval.isReadonly()); } private IntervalEdge startEdge; private IntervalEdge endEdge; private boolean intervalEnabled; // region << Constructor >> public TimeInterval() { this(TimeSpec.MinPeriodTime, TimeSpec.MaxPeriodTime); } public TimeInterval(DateTime moment) { this(moment, moment); } public TimeInterval(DateTime moment, boolean readonly) { this(moment, moment, readonly); } public TimeInterval(DateTime moment, IntervalEdge startEdge, IntervalEdge endEdge) { this(moment, moment, startEdge, endEdge, true, false); } public TimeInterval(DateTime moment, IntervalEdge startEdge, IntervalEdge endEdge, boolean intervalEnabled, boolean readonly) { this(moment, moment, startEdge, endEdge, intervalEnabled, readonly); } public TimeInterval(DateTime start, DateTime end) { this(start, end, IntervalEdge.Closed, IntervalEdge.Closed, true, false); } public TimeInterval(DateTime start, DateTime end, boolean readonly) { this(start, end, IntervalEdge.Closed, IntervalEdge.Closed, true, readonly); } public TimeInterval(DateTime start, DateTime end, IntervalEdge startEdge, IntervalEdge endEdge) { this(start, end, startEdge, endEdge, true, false); } public TimeInterval(DateTime start, DateTime end, IntervalEdge startEdge, IntervalEdge endEdge, boolean intervalEnabled, boolean readonly) { super(start, end, readonly); this.startEdge = startEdge; this.endEdge = endEdge; this.intervalEnabled = intervalEnabled; } // endregion @Override public boolean isStartOpen() { return startEdge == IntervalEdge.Open; } @Override public boolean isEndOpen() { return endEdge == IntervalEdge.Open; } @Override public boolean isOpen() { return isStartOpen() && isEndOpen(); } @Override public boolean isStartClosed() { return startEdge == IntervalEdge.Closed; } @Override public boolean isEndClosed() { return endEdge == IntervalEdge.Closed; } @Override public boolean isClosed() { return isStartClosed() && isEndClosed(); } @Override public boolean isEmpty() { return isMoment() && !isClosed(); } @Override public boolean isDegenerate() { return isMoment() && isClosed(); } @Override public boolean isIntervalEnabled() { return this.intervalEnabled; } @Override public boolean hasStart() { return !this.start.equals(TimeSpec.MinPeriodTime) || !isStartClosed(); } public void setIntervalEnabled(boolean intervalEnabled) { this.intervalEnabled = intervalEnabled; } @Override public DateTime getStartInterval() { return start; } @Override public void setStartInterval(DateTime start) { assertMutable(); assert start.compareTo(this.end) <= 0; this.start = start; } public DateTime getStart() { return (isIntervalEnabled() && isStartOpen()) ? this.start.plus(1) : this.start; } @Override public IntervalEdge getStartEdge() { return this.startEdge; } @Override public void setStartEdge(IntervalEdge startEdge) { assertMutable(); this.startEdge = startEdge; } @Override public boolean hasEnd() { return (!this.end.equals(TimeSpec.MaxPeriodTime) || !isEndClosed()); } @Override public DateTime getEndInterval() { return end; } @Override public void setEndInterval(DateTime end) { assertMutable(); assert end.compareTo(this.start) >= 0; this.end = end; } @Override public DateTime getEnd() { return (isIntervalEnabled() && isEndOpen()) ? this.end.minus(1) : this.end; } @Override public IntervalEdge getEndEdge() { return this.endEdge; } @Override public void setEndEdge(IntervalEdge startEdge) { assertMutable(); this.startEdge = startEdge; } @Override public Duration getDuration() { return new Duration(start, end); } @Override public void setup(DateTime ns, DateTime ne) { assertMutable(); super.setup(ns, ne); if (log.isDebugEnabled()) log.debug("기간을 새로 설정합니다. newStart=[{}], newEnd=[{}]", ns, ne); Times.adjustPeriod(ns, ne); this.start = firstNotNull(ns, TimeSpec.MinPeriodTime); this.end = firstNotNull(ne, TimeSpec.MaxPeriodTime); } @Override public void expandStartTo(DateTime moment) { assertMutable(); if (start.compareTo(moment) > 0) start = moment; } @Override public void expandEndTo(DateTime moment) { assertMutable(); if (end.compareTo(moment) < 0) end = moment; } @Override public void expandTo(DateTime moment) { expandStartTo(moment); expandEndTo(moment); } @Override public void expandTo(ITimePeriod period) { assert period != null; if (period.hasStart()) expandStartTo(period.getStart()); if (period.hasEnd()) expandEndTo(period.getEnd()); } @Override public void shrinkStartTo(DateTime moment) { assertMutable(); if (start.compareTo(moment) < 0) start = moment; } @Override public void shrinkEndTo(DateTime moment) { assertMutable(); if (end.compareTo(moment) > 0) end = moment; } @Override public void shrinkTo(DateTime moment) { assertMutable(); shrinkStartTo(moment); shrinkEndTo(moment); } @Override public void shrinkTo(ITimePeriod period) { assert period != null; assertMutable(); if (period.hasStart()) shrinkStartTo(period.getStart()); if (period.hasEnd()) shrinkEndTo(period.getEnd()); } @Override public ITimeInterval copy() { return copy(Duration.ZERO); } /** 현재 IInterval에서 오프셋만큼 이동한 {@link ITimeInterval}을 반환합니다. */ @Override public ITimeInterval copy(Duration offset) { return new TimeInterval(getStartInterval().plus(offset), getEndInterval().plus(offset), getStartEdge(), getEndEdge(), isIntervalEnabled(), isReadonly()); } @Override public void reset() { super.reset(); intervalEnabled = true; startEdge = IntervalEdge.Closed; endEdge = IntervalEdge.Closed; } @Override public ITimeInterval getIntersection(ITimePeriod other) { assert other != null; ITimePeriod range = super.getIntersection(other); return new TimeInterval(range.getStart(), range.getEnd()); } @Override public ITimeInterval getUnion(ITimePeriod other) { assert other != null; ITimePeriod union = Times.getUnionRange(this, other); return new TimeInterval(union.getStart(), union.getEnd()); } @Override public int hashCode() { return HashTool.compute(super.hashCode(), isIntervalEnabled(), getStartEdge(), getEndEdge()); } }