package com.bbn.bue.common.collections;


import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Ordering;
import com.google.common.collect.Range;
import com.google.common.collect.Sets;

import java.util.Collection;
import java.util.Set;

/**
 * A Naive implementation of an OverlappingRangeSet - uses O(nlog(n)) operation to construct the
 * object, then uses O(n) operations to find an offending ranges)
 */
public final class ImmutableOverlappingRangeSet<T extends Comparable<T>>
    implements OverlappingRangeSet<T> {

  private final ImmutableList<Range<T>> ranges;

  private ImmutableOverlappingRangeSet(final Iterable<Range<T>> ranges) {
    this.ranges = ImmutableOverlappingRangeSet.<T>rangeOrdering().immutableSortedCopy(ranges);
  }

  public static <T extends Comparable<T>> ImmutableOverlappingRangeSet<T> create(
      final Iterable<Range<T>> ranges) {
    return new ImmutableOverlappingRangeSet<T>(ranges);
  }

  /**
   * Returns all ranges for which {@link Range#contains(Comparable)} item is true, without
   * preserving mulitiplicity.
   */
  @Override
  public Collection<Range<T>> rangesContaining(final T item) {
    final ImmutableSet.Builder<Range<T>> ret = ImmutableSet.builder();
    for (final Range<T> range : ranges) {
      if (range.contains(item)) {
        ret.add(range);
      }
    }
    return ret.build();
  }

  /**
   * Finds every range in this object for which {@code range}.{@link Range#encloses(Range)} {@code
   * queryRange}, without preserving mulitiplicity.
   */
  @Override
  public Collection<Range<T>> rangesContaining(final Range<T> queryRange) {
    final ImmutableSet.Builder<Range<T>> ret = ImmutableSet.builder();
    for (final Range<T> range : ranges) {
      if (range.encloses(queryRange)) {
        ret.add(range);
      }
    }
    return ret.build();
  }

  /**
   * Finds every range in this object for which {@code queryRange}.{@link Range#encloses(Range)},
   * without preserving mulitiplicity.
   */
  @Override
  public Collection<Range<T>> rangesContainedBy(final Range<T> queryRange) {
    final ImmutableSet.Builder<Range<T>> ret = ImmutableSet.builder();
    for (final Range<T> range : ranges) {
      if (queryRange.encloses(range)) {
        ret.add(range);
      }
    }
    return ret.build();
  }

  /**
   * For every range in this, asks Guava's {@link Range#isConnected(Range)} to {@code queryRange},
   * without preserving mulitiplicity.
   */
  @Override
  public Collection<Range<T>> rangesOverlapping(final Range<T> queryRange) {
    final ImmutableSet.Builder<Range<T>> ret = ImmutableSet.builder();
    for (final Range<T> range : ranges) {
      if (range.isConnected(queryRange)) {
        ret.add(range);
      }
    }
    return ret.build();
  }

  private static <T extends Comparable<T>> Ordering<Range<T>> rangeOrdering() {
    return Ordering.natural().onResultOf(RangeUtils.<T>lowerEndPointFunction())
        .compound(Ordering.natural().onResultOf(RangeUtils.<T>upperEndPointFunction()))
        .compound(Ordering.usingToString());
  }

  public static <T extends Comparable<T>> Builder<T> builder() {
    return new Builder<>();
  }

  public static class Builder<T extends Comparable<T>> {

    private final Set<Range<T>> ranges = Sets.newHashSet();

    public void addRange(final Range<T> range) {
      ranges.add(range);
    }

    public void addRanges(final Collection<Range<T>> ranges) {
      this.ranges.addAll(ranges);
    }
  }
}

@@ -1105,33 +1105,32 @@
 * preserving mul
-i
 tiplicity.%0A   */
@@ -1116,32 +1116,32 @@
 g multiplicity.%0A
+
    */%0A  @Overrid
@@ -1556,33 +1556,32 @@
 t preserving mul
-i
 tiplicity.%0A   */
@@ -2012,33 +2012,32 @@
 t preserving mul
-i
 tiplicity.%0A   */
@@ -2361,44 +2361,33 @@
   * 
-For every range in this, asks Guava'
+Returns all %7B@link Range%7D
 s %7B@
@@ -2420,16 +2420,20 @@
 ge)%7D to 
+the 
 %7B@code q
@@ -2442,29 +2442,73 @@
 ryRange%7D
-,%0A   * withou
+ for which%0A   * %7B@link Range#isEmpty()%7D is false. Does no
 t preser
@@ -2512,16 +2512,13 @@
 serv
-ing
+e
  mul
-i
 tipl
@@ -2514,33 +2514,50 @@
 rve multiplicity
-.
+ of %7B@link Range%7Ds
 %0A   */%0A  @Overri
@@ -2741,32 +2741,32 @@
 nge : ranges) %7B%0A
-
       if (range.
@@ -2780,32 +2780,77 @@
 cted(queryRange)
+ && !range.intersection(queryRange).isEmpty()
 ) %7B%0A        ret.

fix case where [4,6] and (6,8] would be considered overlapping