public Interval locateInterval(Object value) {
   Date d = (Date) value;
   for (Interval interval : this) {
     IntervalDateRange dateRange = (IntervalDateRange) interval;
     if (d.equals(dateRange.getMinDate())
         || (d.after(dateRange.getMinDate()) && d.before(dateRange.getMaxDate()))) {
       return interval;
     }
   }
   return null;
 }
  public IntervalList build(DataSetHandler handler, ColumnGroup columnGroup) {
    IntervalDateRangeList results = new IntervalDateRangeList(columnGroup);
    DataSet dataSet = handler.getDataSet();
    List values = dataSet.getColumnById(columnGroup.getSourceId()).getValues();
    if (values.isEmpty()) {
      return results;
    }

    // Sort the column dates.
    DataSetSort sortOp = new DataSetSort();
    sortOp.addSortColumn(new ColumnSort(columnGroup.getSourceId(), SortOrder.ASCENDING));
    DataSetHandler sortResults = handler.sort(sortOp);
    List<Integer> sortedRows = sortResults.getRows();
    if (sortedRows == null || sortedRows.isEmpty()) {
      return results;
    }

    // Get the lower & upper limits (discard nulls).
    SortedList sortedValues = new SortedList(values, sortedRows);
    Date minDate = null;
    Date maxDate = null;
    for (int i = 0; minDate == null && i < sortedValues.size(); i++) {
      minDate = (Date) sortedValues.get(i);
    }
    for (int i = sortedValues.size() - 1; maxDate == null && i >= 0; i--) {
      maxDate = (Date) sortedValues.get(i);
    }

    // If min/max are equals then return a single interval.
    DateIntervalType intervalType = calculateIntervalSize(minDate, maxDate, columnGroup);
    if (minDate == null || minDate.compareTo(maxDate) == 0) {

      IntervalDateRange interval = new IntervalDateRange(0, intervalType, minDate, maxDate);
      for (int row = 0; row < sortedValues.size(); row++) interval.getRows().add(row);

      results.add(interval);
      results.setIntervalType(columnGroup.getIntervalSize());
      results.setMinValue(minDate);
      results.setMaxValue(maxDate);
      return results;
    }

    // Create the intervals according to the min/max dates.
    Calendar c = firstIntervalDate(intervalType, minDate, columnGroup);
    int index = 0;
    int counter = 0;
    while (c.getTime().compareTo(maxDate) <= 0) {
      Date intervalMinDate = c.getTime();

      // Create the next interval
      nextIntervalDate(c, intervalType, 1);
      Date intervalMaxDate = c.getTime();
      IntervalDateRange interval =
          new IntervalDateRange(counter++, intervalType, intervalMinDate, intervalMaxDate);
      results.add(interval);

      // Add the target rows
      boolean stop = false;
      while (!stop) {
        if (index >= sortedValues.size()) {
          stop = true;
        } else {
          Date dateValue = (Date) sortedValues.get(index);
          Integer row = sortedRows.get(index);
          if (dateValue == null) {
            index++;
          } else if (dateValue.before(intervalMaxDate)) {
            interval.getRows().add(row);
            index++;
          } else {
            stop = true;
          }
        }
      }
    }

    // Reverse intervals if requested
    boolean asc = columnGroup.isAscendingOrder();
    if (!asc) Collections.reverse(results);

    // Return the results
    results.setIntervalType(intervalType.toString());
    results.setMinValue(minDate);
    results.setMaxValue(maxDate);
    return results;
  }