/*
* 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.core.Guard;
import kr.debop4j.core.Pair;
import kr.debop4j.core.ValueObjectBase;
import kr.debop4j.core.tools.HashTool;
import kr.debop4j.timeperiod.tools.TimeSpec;
import kr.debop4j.timeperiod.tools.Times;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.joda.time.Duration;
/**
* 기간을 표현하는 기본 클래스입니다.
*
* @author 배성혁 sunghyouk.bae@gmail.com
* @since 13. 5. 11. 오후 12:12
*/
@Slf4j
public class TimePeriodBase extends ValueObjectBase implements ITimePeriod {
private static final long serialVersionUID = -7255762434105570062L;
// region << Constructors >>
/** Instantiates a new Time period base. */
protected TimePeriodBase() {
this(TimeSpec.MinPeriodTime, TimeSpec.MaxPeriodTime, false);
}
/**
* Instantiates a new Time period base.
*
* @param readonly the readonly
*/
protected TimePeriodBase(boolean readonly) {
this(TimeSpec.MinPeriodTime, TimeSpec.MaxPeriodTime, readonly);
}
/**
* Instantiates a new Time period base.
*
* @param moment the moment
*/
protected TimePeriodBase(DateTime moment) {
this(moment, moment, false);
}
/**
* Instantiates a new Time period base.
*
* @param moment the moment
* @param readonly the readonly
*/
protected TimePeriodBase(DateTime moment, boolean readonly) {
this(moment, moment, readonly);
}
/**
* Instantiates a new Time period base.
*
* @param start the start
* @param end the end
*/
protected TimePeriodBase(DateTime start, DateTime end) {
this(start, end, false);
}
/**
* Instantiates a new Time period base.
*
* @param start the start
* @param end the end
* @param readonly the readonly
*/
protected TimePeriodBase(DateTime start, DateTime end, boolean readonly) {
start = Guard.firstNotNull(start, TimeSpec.MinPeriodTime);
end = Guard.firstNotNull(end, TimeSpec.MaxPeriodTime);
Pair<DateTime, DateTime> result = Times.adjustPeriod(start, end);
this.start = result.getV1();
this.end = result.getV2();
this.readonly = readonly;
}
/**
* Instantiates a new Time period base.
*
* @param start the start
* @param duration the duration
*/
protected TimePeriodBase(DateTime start, Duration duration) {
this(start, duration, false);
}
/**
* Instantiates a new Time period base.
*
* @param start the start
* @param duration the duration
* @param readonly the readonly
*/
protected TimePeriodBase(DateTime start, Duration duration, boolean readonly) {
Pair<DateTime, Duration> result = Times.adjustPeriod(start, duration);
this.start = result.getV1();
setDuration(result.getV2());
this.readonly = readonly;
}
/**
* Instantiates a new Time period base.
*
* @param source the source
*/
protected TimePeriodBase(ITimePeriod source) {
Guard.shouldNotBeNull(source, "source");
this.start = source.getStart();
this.end = source.getEnd();
this.readonly = source.isReadonly();
}
/**
* Instantiates a new Time period base.
*
* @param source the source
* @param readonly the readonly
*/
protected TimePeriodBase(ITimePeriod source, boolean readonly) {
Guard.shouldNotBeNull(source, "source");
this.start = source.getStart();
this.end = source.getEnd();
this.readonly = readonly;
}
// endregion
/** The Start. */
@Getter
protected DateTime start;
/** The End. */
@Getter
protected DateTime end;
/** The Readonly. */
@Getter
@Setter(AccessLevel.PROTECTED)
protected boolean readonly;
/** 기간을 TimeSpan으료 표현, 기간이 정해지지 않았다면 <see cref="TimeSpec.MaxPeriodTime"/> 을 반환합니다. */
@Override
public Duration getDuration() {
return new Duration(getStart(), getEnd());
}
/**
* Sets duration.
*
* @param duration the duration
*/
public void setDuration(Duration duration) {
assert duration.getMillis() >= Duration.ZERO.getMillis() : "Duration의 크기가 0보다 크거나 같아야 합니다.";
if (hasStart())
end = start.plus(duration);
}
@Override
public boolean hasStart() {
return start != TimeSpec.MinPeriodTime;
}
@Override
public boolean hasEnd() {
return end != TimeSpec.MaxPeriodTime;
}
@Override
public boolean hasPeriod() {
return hasStart() && hasEnd();
}
@Override
public boolean isMoment() {
return Objects.equal(start, end);
}
@Override
public boolean isAnytime() {
return !hasStart() && !hasEnd();
}
@Override
public void setup(DateTime ns, DateTime ne) {
log.trace("기간을 새로 설정합니다. newStart=[{}], newEnd=[{}]", ns, ne);
ns = Guard.firstNotNull(ns, TimeSpec.MinPeriodTime);
ne = Guard.firstNotNull(ne, TimeSpec.MaxPeriodTime);
if (ns.compareTo(ne) < 0) {
this.start = ns;
this.end = ne;
} else {
this.start = ne;
this.end = ns;
}
}
/**
* Copy i time period.
*
* @return the i time period
*/
public ITimePeriod copy() {
return copy(Duration.ZERO);
}
@Override
public ITimePeriod copy(Duration offset) {
log.trace("기간 [{}]에 offset[{}]을 준 기간을 반환합니다...", this, offset);
if (offset == Duration.ZERO)
return new TimeRange(this);
return new TimeRange(hasStart() ? start.plus(offset.getMillis()) : start,
hasEnd() ? end.plus(offset.getMillis()) : end,
readonly);
}
@Override
public void move(Duration offset) {
if (offset == Duration.ZERO)
return;
assertMutable();
log.trace("기간[{}]을 offset[{}]만큼 이동합니다.", this, offset);
if (hasStart())
start = start.plus(offset.getMillis());
if (hasEnd())
end = end.plus(offset.getMillis());
}
/** 시작과 완료 시각이 같은지 여부 */
@Override
public boolean isSamePeriod(ITimePeriod other) {
return (other != null) &&
Objects.equal(start, other.getStart()) &&
Objects.equal(end, 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() {
assertMutable();
start = TimeSpec.MinPeriodTime;
end = TimeSpec.MaxPeriodTime;
log.trace("기간을 리셋했습니다. start=[{}], end=[{}]", start, end);
}
@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);
}
/** Assert mutable. */
protected final void assertMutable() {
assert !readonly : "readonly 입니다.";
}
@Override
public int compareTo(ITimePeriod o) {
return start.compareTo(o.getStart());
}
@Override
public boolean equals(Object obj) {
return obj != null &&
getClass().equals(obj.getClass()) &&
hashCode() == obj.hashCode();
}
@Override
public int hashCode() {
return HashTool.compute(start, end, readonly);
}
@Override
protected Objects.ToStringHelper buildStringHelper() {
return super.buildStringHelper()
.add("start", start)
.add("end", end);
//.add("readonly", readonly);
}
}