/**
* This file is part of d:swarm graph extension.
*
* d:swarm graph extension 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, either version 3 of the License, or
* (at your option) any later version.
*
* d:swarm graph extension 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 d:swarm graph extension. If not, see <http://www.gnu.org/licenses/>.
*/
package org.dswarm.graph.versioning;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Range implements Comparable<Range> {
public static final Range NIL = new Range(-1, -1);
private final int from;
private final int to;
public Range(final int from, final int to) {
if (from > to) {
throw new IllegalArgumentException(String.format("From [%d] was after To [%d].", from, to));
}
this.from = from;
this.to = to;
}
public int from() {
return from;
}
public int to() {
return to;
}
public Range intersect(final Range other) {
if (to < other.from || from > other.to) {
return Range.NIL;
}
if (to == other.from) {
return new Range(to, to);
}
if (from == other.to) {
return new Range(from, from);
}
final int newFrom = Math.max(from, other.from);
final int newTo = Math.min(to, other.to);
return new Range(newFrom, newTo);
}
public Set<Range> union(final Range other) {
if (intersect(other) == Range.NIL) {
return Range.asSet(this, other);
}
if (equals(other)) {
return Range.asSet(this);
}
return Range.asSet(realUnion(other));
}
public static Set<Range> asSet(final Range... items) {
return new HashSet<>(Arrays.asList(items));
}
private Range realUnion(final Range other) {
final int newFrom = Math.min(from, other.from);
final int newTo = Math.max(to, other.to);
return new Range(newFrom, newTo);
}
public boolean overlaps(final Range other) {
return !intersect(other).equals(Range.NIL);
}
public boolean contains(final int point) {
return point >= from && point < to;
}
@Override
public String toString() {
return String.format("Range[%d,%d]", from, to);
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final Range range = (Range) o;
return from == range.from && to == range.to;
}
@Override
public int hashCode() {
int result = (int) (from ^ (from >>> 32));
result = 31 * result + (int) (to ^ (to >>> 32));
return result;
}
@Override
public int compareTo(final Range o) {
if (o == null) {
return -1;
}
return Integer.valueOf(from).compareTo(o.from);
}
public static List<Range> compactRanges(final Collection<Range> ranges) {
final List<Range> result = new ArrayList<>();
Range.takeNextRangeAndMergeOverlappingRanges(new ArrayList<>(ranges), result);
Collections.sort(result);
return result;
}
private static void takeNextRangeAndMergeOverlappingRanges(final List<Range> rangeList, final List<Range> result) {
if (rangeList.isEmpty()) {
return;
}
result.add(Range.consumeAndMergeOverlappingRanges(rangeList.remove(0), rangeList));
Range.takeNextRangeAndMergeOverlappingRanges(rangeList, result);
}
private static Range consumeAndMergeOverlappingRanges(Range first, final List<Range> rangeList) {
for (int i = 0; i < rangeList.size(); i++) {
final Range rangeInList = rangeList.get(i);
if (first.overlaps(rangeInList)) {
first = first.union(rangeInList).iterator().next();
rangeList.remove(i);
return Range.consumeAndMergeOverlappingRanges(first, rangeList);
}
}
return first;
}
public static Range range(final int from, final int to) {
return new Range(from, to);
}
public static Range range(final int from) {
return new Range(from, Integer.MAX_VALUE);
}
}