Java tutorial
/* * 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.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 java.util.Arrays; import static kr.debop4j.core.Guard.*; /** * {@link ITimePeriod} ? ?? Chain (Linked List) ?. * * @author ? sunghyouk.bae@gmail.com * @since 13. 5. 17. 4:17 */ @Slf4j public class TimePeriodChain extends TimePeriodContainer implements ITimePeriodChain { private static final long serialVersionUID = -5838724440389574448L; public TimePeriodChain() { } public TimePeriodChain(ITimePeriod... periods) { if (periods != null) addAll(Arrays.asList(periods)); } public TimePeriodChain(Iterable<? extends ITimePeriod> collection) { if (collection != null) addAll(collection); } @Override public DateTime getStart() { return (getFirst() != null) ? getFirst().getStart() : TimeSpec.MinPeriodTime; } /** period chain? ?? . */ @Override public void setStart(DateTime value) { if (getFirst() != null) move(new Duration(getStart(), value)); } @Override public DateTime getEnd() { return (getLast() != null) ? getLast().getEnd() : TimeSpec.MaxPeriodTime; } @Override public void setEnd(DateTime value) { if (getLast() != null) move(new Duration(getEnd(), value)); } /** * Period ?? , null? . * * @return */ @Override public ITimePeriod getFirst() { return (size() > 0) ? getPeriods().get(0) : null; } /** * period chain? , null? . * * @return */ @Override public ITimePeriod getLast() { return (size() > 0) ? getPeriods().get(size() - 1) : null; } @Override public ITimePeriod set(int index, ITimePeriod element) { shouldBeInRange(index, 0, size(), "index"); remove(index); add(index, element); return element; } /** * ? . * * @param period * @return */ @Override public boolean add(ITimePeriod period) { shouldNotBeNull(period, "period"); Times.assertMutable(period); ITimePeriod last = getLast(); if (last != null) { assertSpaceAfter(last.getEnd(), period.getDuration()); period.setup(last.getEnd(), last.getEnd().plus(period.getDuration())); } log.trace("Period chain? ??? . period=[{}]", period); return getPeriods().add(period); } /** * ? ? . * * @param periods */ @Override public void addAll(final Iterable<? extends ITimePeriod> periods) { shouldNotBeNull(periods, "periods"); for (ITimePeriod period : periods) add(period); } /** * {@link ITimePeriod}? Chain? index ? item? . Period Period? ? ?. * * @param index * @param item */ @Override public void add(int index, ITimePeriod item) { shouldNotBeNull(item, "item"); shouldBeInRange(index, 0, size(), "index"); Times.assertMutable(item); log.trace("Chain? ??[{}]? [{}] ...", index, item); Duration itemDuration = item.getDuration(); ITimePeriod prevItem = null; ITimePeriod nextItem = null; if (size() > 0) { log.trace("? ? ..."); if (index > 0) { prevItem = get(index - 1); assertSpaceAfter(getEnd(), itemDuration); } if (index < size() - 1) { nextItem = get(index); assertSpaceBefore(getStart(), itemDuration); } } getPeriods().add(index, item); if (prevItem != null) { log.trace( " period? period period? ? ..."); item.setup(prevItem.getEnd(), prevItem.getEnd().plus(itemDuration)); for (int i = index + 1; i < size(); i++) { ITimePeriod p = get(i); DateTime startTime = p.getStart().plus(itemDuration); p.setup(startTime, startTime.plus(p.getDuration())); } } if (nextItem != null) { log.trace( " period? period period? ? ..."); DateTime nextStart = nextItem.getStart().minus(itemDuration); item.setup(nextStart, nextStart.plus(itemDuration)); for (int i = 0; i < index - 1; i++) { ITimePeriod p = get(i); nextStart = p.getStart().minus(itemDuration); p.setup(nextStart, nextStart.plus(p.getDuration())); } } } /** , ? ITimePeriod ? ? . ( ?) */ @Override public boolean remove(Object o) { shouldNotBeNull(o, "o"); shouldBe(o instanceof ITimePeriod, "o is not ITimePeriod type. class=[%s]", o.getClass()); if (size() <= 0) return false; ITimePeriod item = (ITimePeriod) o; log.trace(" [{}] ? ...", item); Duration itemDuration = item.getDuration(); int index = indexOf(item); ITimePeriod next = null; if (itemDuration.getMillis() > 0 && index >= 0 && index < size() - 1) next = get(index); boolean removed = getPeriods().remove(item); if (removed && next != null) { log.trace("[{}] , chain? ? periods ? ? ...", item); for (int i = index; i < size(); i++) { DateTime start = get(i).getStart().minus(itemDuration); get(i).setup(start, start.plus(get(i).getDuration())); } } log.trace("[{}] =[{}]", item, removed); return removed; } /** , ? ITimePeriod ? ? . ( ?) */ @Override public ITimePeriod remove(int index) { shouldBeInRange(index, 0, size(), "index"); ITimePeriod removed = get(index); return remove(removed) ? removed : null; } /** moment ?? duration ?? ? ? ( ? ? ) */ protected void assertSpaceBefore(DateTime moment, Duration duration) { boolean hasSpace = moment != TimeSpec.MinPeriodTime; if (hasSpace) { Duration remaining = new Duration(TimeSpec.MinPeriodTime, moment); hasSpace = duration.compareTo(remaining) <= 0; } shouldBe(hasSpace, "duration [%s] is out of range.", duration); } /** moment ?? duration ?? ? ? ( ? ? ) */ protected void assertSpaceAfter(DateTime moment, Duration duration) { boolean hasSpace = moment != TimeSpec.MaxPeriodTime; if (hasSpace) { Duration remaining = new Duration(moment, TimeSpec.MaxPeriodTime); hasSpace = duration.compareTo(remaining) <= 0; } shouldBe(hasSpace, "duration [%s] is out of range.", duration); } }