/**
* Copyright (c) 2010-2016 by the respective copyright holders.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.openhab.io.gcal.internal.util;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.commons.lang.math.LongRange;
import org.quartz.Calendar;
/**
* This implementation of the Quartz Calendar stores a list of TimeRanges that
* are excluded from scheduling.
*
* @author Thomas.Eichstaedt-Engelen
*/
public class TimeRangeCalendar implements Calendar, Serializable {
private static final long serialVersionUID = 6840341227522646373L;
private Calendar baseCalendar;
private String description;
private static final long ONE_MILLI = 1;
private List<LongRange> excludedRanges = new ArrayList<LongRange>();
public TimeRangeCalendar() {
this.baseCalendar = null;
this.description = "A special Quartz calendar which caries the excluded time ranges.";
}
@Override
public Calendar getBaseCalendar() {
return baseCalendar;
}
@Override
public void setBaseCalendar(Calendar baseCalendar) {
this.baseCalendar = baseCalendar;
}
@Override
public String getDescription() {
return description;
}
@Override
public void setDescription(String description) {
this.description = description;
}
/**
* Determine whether the given time (in milliseconds) is 'included' by the
* Calendar.
*/
@Override
public boolean isTimeIncluded(long timeStamp) {
return findTimeRange(timeStamp) != null;
}
/**
* Determine the next time (in milliseconds) that is 'included' by the
* Calendar after the given time.
*/
@Override
public long getNextIncludedTime(long timeStamp) {
long nextIncludedTime = timeStamp + ONE_MILLI;
while (isTimeIncluded(nextIncludedTime)) {
LongRange timeRange = findTimeRange(timeStamp);
if (nextIncludedTime >= timeRange.getMinimumLong() && nextIncludedTime <= timeRange.getMaximumLong()) {
nextIncludedTime = timeRange.getMaximumLong() + ONE_MILLI;
} else if ((getBaseCalendar() != null) && (!getBaseCalendar().isTimeIncluded(nextIncludedTime))) {
nextIncludedTime = getBaseCalendar().getNextIncludedTime(nextIncludedTime);
} else {
nextIncludedTime++;
}
}
return nextIncludedTime;
}
/**
* Find first TimeRange which contains the given <code>timeStamp</code>
*
* @param timeStamp the TimeStamp to find
* @return the first TimeRange which contains the given <code>timeStamp</code>
* or <code>null</code> if no matching TimeRange exists
*/
protected LongRange findTimeRange(long timeStamp) {
for (LongRange range : excludedRanges) {
if (range.containsLong(timeStamp)) {
return range;
}
}
return null;
}
/**
* Adds the given <code>timeRange</code> to the excluded ranges.
*/
public void addTimeRange(LongRange timeRange) {
this.excludedRanges.add(timeRange);
}
/**
* Removes the given <code>timeRange</code> from the excluded ranges.
*/
public void removeExcludedDate(LongRange dateToRemove) {
this.excludedRanges.remove(dateToRemove);
}
/**
* Returns an unmodifiable List of the excluded TimeRanges
*/
protected List<LongRange> getExcludedRanges() {
return Collections.unmodifiableList(excludedRanges);
}
@Override
public Object clone() {
TimeRangeCalendar clone = new TimeRangeCalendar();
clone.excludedRanges = new ArrayList<LongRange>(excludedRanges);
return clone;
}
}