package com.revolsys.collection.range;
import java.util.Iterator;
import java.util.List;
import com.revolsys.collection.list.Lists;
import com.revolsys.datatype.DataType;
import com.revolsys.util.Emptyable;
import com.revolsys.util.number.Numbers;
public abstract class AbstractRange<V>
implements Iterable<V>, Emptyable, Comparable<AbstractRange<? extends Object>> {
public static int compare(final Object value1, final Object value2) {
if (value1 == null) {
if (value2 == null) {
return 0;
} else {
return -1;
}
} else if (value2 == null) {
return 1;
} else {
final Long longValue1 = Numbers.toLong(value1);
final Long longValue2 = Numbers.toLong(value2);
if (longValue1 == null) {
if (longValue2 == null) {
return value1.toString().compareTo(value2.toString());
} else {
return 1;
}
} else if (longValue2 == null) {
return -1;
} else {
return Long.compare(longValue1, longValue2);
}
}
}
public int compareFromValue(final Object value) {
final V from = getFrom();
return compare(from, value);
}
@Override
public int compareTo(final AbstractRange<? extends Object> range) {
final Object rangeFrom = range.getFrom();
final int fromCompare = compareFromValue(rangeFrom);
if (fromCompare == 0) {
final Object rangeTo = range.getTo();
final int toCompare = compareToValue(rangeTo);
return toCompare;
}
return fromCompare;
}
public int compareToValue(final Object value) {
final V to = getTo();
return compare(to, value);
}
public boolean contains(final Object value) {
final int fromCompare = compareFromValue(value);
if (fromCompare <= 0) {
final int toCompare = compareToValue(value);
if (toCompare >= 0) {
return true;
}
}
return false;
}
@Override
public boolean equals(final Object other) {
if (this == other) {
return true;
} else if (other == null) {
return false;
} else if (other instanceof AbstractRange) {
final AbstractRange<?> range = (AbstractRange<?>)other;
final V from = getFrom();
final Object rangeFrom = range.getFrom();
if (!DataType.equal(from, rangeFrom)) {
return false;
} else if (!DataType.equal(getTo(), range.getTo())) {
return false;
} else {
return true;
}
} else {
return false;
}
}
/**
* Construct a newn expanded range if the this range and the other overlap or touch
*
* @param range
* @return
*/
public AbstractRange<?> expand(final AbstractRange<?> range) {
final V from = getFrom();
final V to = getTo();
final Object rangeFrom = range.getFrom();
final Object rangeTo = range.getTo();
final int fromCompare = compareFromValue(rangeFrom);
final int toCompare = compareToValue(rangeTo);
if (fromCompare == 0) {
if (toCompare >= 0) {
return this;
} else {
return range;
}
} else if (toCompare == 0) {
if (fromCompare < 0) {
return this;
} else {
return range;
}
} else if (fromCompare < 0) {
if (toCompare > 0) {
return this;
} else if (compareToValue(rangeFrom) > 0) {
return newRange(from, rangeTo);
} else if (DataType.equal(to, previous(rangeFrom)) || DataType.equal(to, rangeFrom)) {
return newRange(from, rangeTo);
}
} else if (fromCompare > 0) {
if (toCompare < 0) {
return range;
} else if (compareFromValue(rangeTo) < 0) {
return newRange(rangeFrom, to);
} else if (DataType.equal(previous(from), rangeTo) || DataType.equal(from, rangeTo)) {
return newRange(rangeFrom, to);
}
}
return null;
}
/**
* Construct a newn expanded range to include the specified value if possible.
* <ul>
* <li>If the range contains this value return this instance.</li>
* <li>If the value = from - 1 return a new range from value-to</li>
* <li>If the value = to + 1 return a new range from from-value</li>
* <li>Otherwise return null as it is not a consecutive range</li>
* @param value
* @return
*/
public AbstractRange<?> expand(final Object value) {
if (value == null || contains(value)) {
return this;
} else {
final V from = getFrom();
final V to = getTo();
final V next = next(value);
if (next == null) {
return null;
} else if (compareFromValue(next) == 0) { // value == from -1
return newRange(value, to);
} else {
final V previous = previous(value);
if (previous == null) {
return null;
} else if (compareToValue(previous) == 0) { // value == to + 1
return newRange(from, value);
} else {
return null;
}
}
}
}
public abstract V getFrom();
public abstract V getTo();
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + getFrom().hashCode();
result = prime * result + getTo().hashCode();
return result;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public Iterator<V> iterator() {
return new RangeIterator<>(this);
}
protected AbstractRange<?> newRange(final Object from, final Object to) {
throw new UnsupportedOperationException();
}
public V next(final Object value) {
return null;
}
public V previous(final Object value) {
return null;
}
public long size() {
return 1;
}
public List<V> toList() {
return Lists.toArray(this);
}
@Override
public String toString() {
if (size() == 0) {
return "";
} else {
final V from = getFrom();
final V to = getTo();
if (from.equals(to)) {
return from.toString();
} else {
return from + "~" + to;
}
}
}
}