@Override
  @SuppressWarnings("unchecked")
  public String isValid() {

    String superIsValid = super.isValid();
    if (superIsValid != null) return superIsValid;

    if (intervals.isEmpty()) {
      return "No intervals specified";
    }

    for (int i = 1; i < intervals.size(); i++) {
      Interval<T> interval1 = intervals.get(i - 1);
      Interval<T> interval2 = intervals.get(i);

      if (!interval1.getMax().equals(interval2.getMin())) {
        return "Gap between " + interval1 + " and " + interval2;
      }

      if (interval1.getMin().equals(interval2.getMin())
          && interval1.getMax().equals(interval2.getMax())) {
        return "Repeating intervals " + interval1 + " and " + interval2;
      }
    }

    DataTypeWithRatioScale<T> type = (DataTypeWithRatioScale<T>) getDataType();
    if (lowerRange.getRepeatBound() != null
        && upperRange.getRepeatBound() != null
        && type.compare(lowerRange.getRepeatBound(), upperRange.getRepeatBound()) > 0) {
      return "Lower repeat bound must be < upper repeat bound";
    }

    if (lowerRange.getSnapBound() != null
        && lowerRange.getRepeatBound() != null
        && type.compare(lowerRange.getSnapBound(), lowerRange.getRepeatBound()) > 0) {
      return "Lower snap bound must be <= lower repeat bound";
    }

    if (lowerRange.getLabelBound() != null
        && lowerRange.getSnapBound() != null
        && type.compare(lowerRange.getLabelBound(), lowerRange.getSnapBound()) > 0) {
      return "Lower label bound must be <= lower snap bound";
    }

    if (upperRange.getRepeatBound() != null
        && upperRange.getSnapBound() != null
        && type.compare(upperRange.getSnapBound(), upperRange.getRepeatBound()) < 0) {
      return "Upper snap bound must be >= upper repeat bound";
    }

    if (lowerRange.getLabelBound() != null
        && upperRange.getSnapBound() != null
        && type.compare(upperRange.getLabelBound(), upperRange.getSnapBound()) < 0) {
      return "Upper label bound must be >= upper snap bound";
    }

    return null;
  }
 /**
  * Returns adjusted ranges.
  *
  * @return Array containing {lower, upper}
  */
 @SuppressWarnings("unchecked")
 protected Range<T>[] getAdjustedRanges() {
   // Create adjustments
   Range<T> tempLower = new Range<T>(null, null, null);
   Range<T> tempUpper = new Range<T>(null, null, null);
   if (lowerRange.getRepeatBound() != null) {
     tempLower.setRepeatBound(lowerRange.getRepeatBound());
   } else {
     tempLower.setRepeatBound(intervals.get(0).min);
   }
   if (lowerRange.getSnapBound() != null) {
     tempLower.setSnapBound(lowerRange.getSnapBound());
   } else {
     tempLower.setSnapBound(tempLower.getRepeatBound());
   }
   if (lowerRange.getLabelBound() != null) {
     tempLower.setLabelBound(lowerRange.getLabelBound());
   } else {
     tempLower.setLabelBound(tempLower.getSnapBound());
   }
   if (upperRange.getRepeatBound() != null) {
     tempUpper.setRepeatBound(upperRange.getRepeatBound());
   } else {
     tempUpper.setRepeatBound(intervals.get(intervals.size() - 1).max);
   }
   if (upperRange.getSnapBound() != null) {
     tempUpper.setSnapBound(upperRange.getSnapBound());
   } else {
     tempUpper.setSnapBound(tempUpper.getRepeatBound());
   }
   if (upperRange.getLabelBound() != null) {
     tempUpper.setLabelBound(upperRange.getLabelBound());
   } else {
     tempUpper.setLabelBound(tempUpper.getSnapBound());
   }
   return new Range[] {tempLower, tempUpper};
 }