/////////////////////////////////////////////////////////////////////////////
//
// Project ProjectForge Community Edition
// www.projectforge.org
//
// Copyright (C) 2001-2014 Kai Reinhard (k.reinhard@micromata.de)
//
// ProjectForge is dual-licensed.
//
// This community edition is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation; version 3 of the License.
//
// This community edition is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
// Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, see http://www.gnu.org/licenses/.
//
/////////////////////////////////////////////////////////////////////////////
package org.projectforge.common;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.springframework.util.CollectionUtils;
/**
* Holds number ranges, such as "10,20-25,30-35,50" (comma separated ranges and values).
*
* @author Kai Reinhard (k.reinhard@micromata.de)
*
*/
public abstract class Ranges<T extends Comparable<T>> implements Serializable
{
private static final long serialVersionUID = 844349548492107372L;
private List<Range<T>> ranges;
private List<T> values;
private final String separatorChars = ";,";
private final char rangesSeparatorChar = '-';
private boolean nullRangeMatchesAlways;
/**
* Number ranges, such as "10,20-25,30-35,50" (comma separated ranges and values).
* @param rangesString
*/
public Ranges(final String rangesString)
{
setRanges(rangesString);
}
public boolean doesMatch(final T value)
{
if (value == null) {
return false;
}
if (CollectionUtils.isEmpty(ranges) == true && CollectionUtils.isEmpty(values) == true) {
return nullRangeMatchesAlways;
}
for (final Range<T> range : ranges) {
if (range.doesMatch(value) == true) {
return true;
}
}
for (final T val : values) {
if (value.compareTo(val) == 0) {
return true;
}
}
return false;
}
protected abstract T parseValue(String value);
/**
* Number ranges, such as "10,20-25,30-35,50" (comma separated ranges and values).
* @param rangesString
*/
public Ranges<T> setRanges(final String rangesString)
{
ranges = new ArrayList<Range<T>>();
values = new ArrayList<T>();
if (StringUtils.isBlank(rangesString) == true) {
// No ranges given.
return this;
}
final String[] rangeStrings = StringUtils.split(rangesString, separatorChars);
for (final String rangeString : rangeStrings) {
if (StringUtils.isBlank(rangeString) == true) {
// No range given.
continue;
}
final String str = rangeString.trim();
final int pos = str.indexOf(rangesSeparatorChar, 1); // Ignore any leading and trailing '-'
if (pos > 0) {
if (pos >= str.length()) {
throw new IllegalArgumentException("Couldn't parse range: '" + rangesString + "'.");
}
final String from = str.substring(0, pos);
final String to = str.substring(pos + 1);
try {
final Range<T> range = new Range<T>(parseValue(from.trim()), parseValue(to.trim()));
ranges.add(range);
} catch (final NumberFormatException ex) {
throw new IllegalArgumentException("Couldn't parse range: '" + rangesString + "'." + ex.getMessage(), ex);
}
} else {
try {
values.add(parseValue(str));
} catch (final NumberFormatException ex) {
throw new IllegalArgumentException("Couldn't parse range: '" + rangesString + "'." + ex.getMessage(), ex);
}
}
}
return this;
}
/**
* If set to true, all values will match if no range is given.
* @param nullRangeMatchesAlways the nullRangeMatchesAlways to set
* @return this for chaining.
*/
public Ranges<T> setNullRangeMatchesAlways(final boolean nullRangeMatchesAlways)
{
this.nullRangeMatchesAlways = nullRangeMatchesAlways;
return this;
}
/**
* @return the values
*/
public List<T> getValues()
{
return values;
}
/**
* @return the ranges
*/
public List<Range<T>> getRanges()
{
return ranges;
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString()
{
final StringBuffer buf = new StringBuffer();
boolean first = true;
if (ranges != null) {
for (final Range<T> range : ranges) {
first = StringHelper.append(buf, first, String.valueOf(range.getMinValue()) + rangesSeparatorChar + range.getMaxValue(), ",");
}
}
if (values != null) {
for (final T value : values) {
first = StringHelper.append(buf, first, String.valueOf(value), ",");
}
}
return buf.toString();
}
}