/*
* 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.base.Objects;
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.timeperiod.tools.TimeSpec.ZeroDuration;
import static org.joda.time.Duration.ZERO;
/**
* 기준 일자의 시간 간격을 이용하여 기간을 표현합니다.
*
* @author 배성혁 sunghyouk.bae@gmail.com
* @since 13. 5. 11. 오후 9:04
*/
@Slf4j
public class TimeBlock extends TimePeriodBase implements ITimeBlock {
private static final long serialVersionUID = 3967092362222887325L;
public static final TimeBlock Anytime = new TimeBlock(true);
public static TimeRange toRange(TimeBlock block) {
return new TimeRange(block.getStart(), block.getDuration(), block.isReadonly());
}
public static TimeInterval toInterval(TimeBlock block) {
return new TimeInterval(block.getStart(), block.getEnd(), block.isReadonly());
}
// region << Constructor >>
public TimeBlock() {}
public TimeBlock(boolean readonly) {
super(readonly);
this.duration = TimeSpec.MaxDuration;
}
public TimeBlock(DateTime moment) {
super(moment);
this.duration = super.getDuration();
}
public TimeBlock(DateTime moment, boolean readonly) {
super(moment, readonly);
this.duration = super.getDuration();
}
public TimeBlock(DateTime start, DateTime end) {
this(start, end, false);
}
public TimeBlock(DateTime start, DateTime end, boolean readonly) {
super(start, end, readonly);
this.duration = super.getDuration();
}
public TimeBlock(DateTime start, Duration duration) {
this(start, duration, false);
}
public TimeBlock(DateTime start, Duration duration, boolean readonly) {
super(start, duration, readonly);
assertValidDuration(duration);
this.duration = super.getDuration();
}
public TimeBlock(Duration duration, DateTime end) {
this(duration, end, false);
}
public TimeBlock(Duration duration, DateTime end, boolean readonly) {
super(null, end, readonly);
assertValidDuration(duration);
this.duration = duration;
this.start = end.minus(duration);
}
public TimeBlock(ITimePeriod source) {
super(source);
this.duration = source.getDuration();
}
public TimeBlock(ITimePeriod source, boolean readonly) {
super(source, readonly);
this.duration = source.getDuration();
}
// endregion
private Duration duration;
protected void assertValidDuration(Duration duration) {
assert duration.compareTo(ZeroDuration) >= 0 : "duration은 0 이상이어야 합니다.";
}
@Override
public void setStart(DateTime start) {
assertMutable();
this.start = start;
}
@Override
public void setEnd(DateTime end) {
assertMutable();
this.end = end;
}
@Override
public Duration getDuration() {
return duration;
}
@Override
public void setDuration(Duration duration) {
assertMutable();
assertValidDuration(duration);
durationFromStart(duration);
}
@Override
public TimeBlock copy() {
return copy(ZERO);
}
@Override
public TimeBlock copy(Duration offset) {
if (ZERO.isEqual(offset))
return new TimeBlock(this);
return new TimeBlock(hasStart() ? start.plus(offset) : start,
hasEnd() ? end.plus(offset) : end,
readonly);
}
public void setup(DateTime newStart, Duration duration) {
assertMutable();
assertValidDuration(duration);
log.trace("TimeBlock 값을 새로 설정합니다. newStart=[{}], duration=[{}]", newStart, duration);
this.start = newStart;
this.duration = duration;
this.end = newStart.plus(duration);
}
@Override
public void durationFromStart(Duration newDuration) {
assertMutable();
assertValidDuration(newDuration);
if (newDuration.isEqual(TimeSpec.MaxDuration)) {
this.duration = newDuration;
this.end = TimeSpec.MaxPeriodTime;
} else {
if (end != null)
assert this.end.plus(newDuration).compareTo(TimeSpec.MaxPeriodTime) <= 0 : "duration 이 너무 크네요.";
this.duration = newDuration;
this.end = this.start.plus(this.duration);
}
}
@Override
public void durationFromEnd(Duration newDuration) {
assertMutable();
assertValidDuration(newDuration);
this.duration = newDuration;
this.start = this.end.minus(this.duration);
}
public ITimeBlock getPreviousBlock() {
return getPreviousBlock(ZERO);
}
@Override
public ITimeBlock getPreviousBlock(Duration offset) {
Duration endOffset = (offset.compareTo(ZERO) > 0) ? new Duration(-offset.getMillis()) : offset;
return new TimeBlock(getDuration(), getStart().plus(endOffset), readonly);
}
public ITimeBlock getNextBlock() {
return getNextBlock(ZERO);
}
@Override
public ITimeBlock getNextBlock(Duration offset) {
Duration startOffset = (offset.compareTo(ZERO) > 0) ? offset : new Duration(-offset.getMillis());
return new TimeBlock(getEnd().plus(startOffset), getDuration(), readonly);
}
public TimeBlock getIntersection(ITimePeriod other) {
assert other != null;
return Times.getIntersectionBlock(this, other);
}
public TimeBlock getUnion(ITimePeriod other) {
assert other != null;
return Times.getUnionBlock(this, other);
}
@Override
protected Objects.ToStringHelper buildStringHelper() {
return super.buildStringHelper();
//.add("duration", duration);
}
}