public static RangeEndpointCalculator<? extends Comparable<?>> create(RangeFacetRequest request) {
   final SchemaField sf = request.getField();
   final FieldType ft = sf.getType();
   final RangeEndpointCalculator<?> calc;
   if (ft instanceof TrieField) {
     final TrieField trie = (TrieField) ft;
     switch (trie.getType()) {
       case FLOAT:
         calc = new FloatRangeEndpointCalculator(request);
         break;
       case DOUBLE:
         calc = new DoubleRangeEndpointCalculator(request);
         break;
       case INTEGER:
         calc = new IntegerRangeEndpointCalculator(request);
         break;
       case LONG:
         calc = new LongRangeEndpointCalculator(request);
         break;
       default:
         throw new SolrException(
             SolrException.ErrorCode.BAD_REQUEST,
             "Unable to range facet on tried field of unexpected type:" + sf.getName());
     }
   } else if (ft instanceof DateField) {
     calc = new DateRangeEndpointCalculator(request, null);
   } else {
     throw new SolrException(
         SolrException.ErrorCode.BAD_REQUEST, "Unable to range facet on field:" + sf);
   }
   return calc;
 }
 public RangeEndpointCalculator(final RangeFacetRequest request) {
   this.field = request.getField();
   this.request = request;
 }
  public List<FacetRange> getRanges() {

    final T start = getValue(request.getStart());
    T end = getValue(request.getEnd()); // not final, hardend may change this

    if (end.compareTo(start) < 0) {
      throw new SolrException(
          SolrException.ErrorCode.BAD_REQUEST,
          "range facet 'end' comes before 'start': " + end + " < " + start);
    }

    // explicitly return the gap.  compute this early so we are more
    // likely to catch parse errors before attempting math
    final String[] gaps = request.getGaps();
    String gap = gaps[0];

    final EnumSet<FacetRangeInclude> include = request.getInclude();

    T low = start;

    List<FacetRange> ranges = new ArrayList<FacetRange>();

    int gapCounter = 0;

    while (low.compareTo(end) < 0) {
      if (gapCounter < gaps.length) {
        gap = gaps[gapCounter++];
      }
      T high = addGap(low, gap);
      if (end.compareTo(high) < 0) {
        if (request.isHardEnd()) {
          high = end;
        } else {
          end = high;
        }
      }

      if (high.compareTo(low) < 0) {
        throw new SolrException(
            SolrException.ErrorCode.BAD_REQUEST,
            "range facet infinite loop (is gap negative? did the math overflow?)");
      }

      if (high.compareTo(low) == 0) {
        throw new SolrException(
            SolrException.ErrorCode.BAD_REQUEST,
            "range facet infinite loop: gap is either zero, or too small relative start/end and caused underflow: "
                + low
                + " + "
                + gap
                + " = "
                + high);
      }

      final boolean includeLower =
          (include.contains(FacetRangeInclude.ALL)
              || include.contains(FacetRangeInclude.LOWER)
              || (include.contains(FacetRangeInclude.EDGE) && 0 == low.compareTo(start)));
      final boolean includeUpper =
          (include.contains(FacetRangeInclude.ALL)
              || include.contains(FacetRangeInclude.UPPER)
              || (include.contains(FacetRangeInclude.EDGE) && 0 == high.compareTo(end)));

      final String lowS = formatValue(low);
      final String highS = formatValue(high);

      ranges.add(new FacetRange(lowS, lowS, highS, includeLower, includeUpper));
      low = high;
    }

    final Set<FacetRangeOther> others = request.getOthers();
    if (null != others && 0 < others.size()) {

      // no matter what other values are listed, we don't do
      // anything if "none" is specified.
      if (!others.contains(FacetRangeOther.NONE)) {

        boolean all = others.contains(FacetRangeOther.ALL);

        if (all || others.contains(FacetRangeOther.BEFORE)) {
          // include upper bound if "outer" or if first gap doesn't already include it
          ranges.add(
              new FacetRange(
                  FacetRangeOther.BEFORE.toString(),
                  null,
                  formatValue(start),
                  false,
                  include.contains(FacetRangeInclude.OUTER)
                      || include.contains(FacetRangeInclude.ALL)
                      || !(include.contains(FacetRangeInclude.LOWER)
                          || include.contains(FacetRangeInclude.EDGE))));
        }
        if (all || others.contains(FacetRangeOther.AFTER)) {
          // include lower bound if "outer" or if last gap doesn't already include it
          ranges.add(
              new FacetRange(
                  FacetRangeOther.AFTER.toString(),
                  formatValue(end),
                  null,
                  include.contains(FacetRangeInclude.OUTER)
                      || include.contains(FacetRangeInclude.ALL)
                      || !(include.contains(FacetRangeInclude.UPPER)
                          || include.contains(FacetRangeInclude.EDGE)),
                  false));
        }
        if (all || others.contains(FacetRangeOther.BETWEEN)) {
          ranges.add(
              new FacetRange(
                  FacetRangeOther.BETWEEN.toString(),
                  formatValue(start),
                  formatValue(end),
                  include.contains(FacetRangeInclude.LOWER)
                      || include.contains(FacetRangeInclude.EDGE)
                      || include.contains(FacetRangeInclude.ALL),
                  include.contains(FacetRangeInclude.UPPER)
                      || include.contains(FacetRangeInclude.EDGE)
                      || include.contains(FacetRangeInclude.ALL)));
        }
      }
    }

    return ranges;
  }