/**
  * Returns the numerical limit at the given index in the list of LightDefinition entries.
  *
  * @param index the position of the entry that should be queried.
  * @return the numerical limit at the given position.
  */
 public Number getLimit(final int index) {
   final LightDefinition ldef = limits.get(index);
   if (ldef == null) {
     return null;
   }
   return ldef.getLimit();
 }
 /**
  * Returns the color at the given index in the list of LightDefinition entries.
  *
  * @param index the position of the entry that should be queried.
  * @return the color at the given position.
  */
 public Color getColor(final int index) {
   final LightDefinition ldef = limits.get(index);
   if (ldef == null) {
     return null;
   }
   return ldef.getColor();
 }
 /**
  * Returns all numerical limits defined in this function mapped to their respective position.
  *
  * @return the numerical limits as array.
  */
 public Number[] getLimit() {
   final Number[] retval = new Number[limits.size()];
   for (int i = 0; i < limits.size(); i++) {
     final LightDefinition definition = limits.get(i);
     retval[i] = definition.getLimit();
   }
   return retval;
 }
 /**
  * Returns all colors defined in this function mapped to their respective position.
  *
  * @return the colors as array.
  */
 public Color[] getColor() {
   final Color[] retval = new Color[limits.size()];
   for (int i = 0; i < limits.size(); i++) {
     final LightDefinition definition = limits.get(i);
     retval[i] = definition.getColor();
   }
   return retval;
 }
 /**
  * Return a completly separated copy of this function. The copy does no longer share any
  * changeable objects with the original function.
  *
  * @return a copy of this function.
  */
 public ElementTrafficLightFunction getInstance() {
   final ElementTrafficLightFunction elf = (ElementTrafficLightFunction) super.getInstance();
   elf.limits = (ArrayList<LightDefinition>) limits.clone();
   for (int i = 0; i < limits.size(); i++) {
     final LightDefinition definition = limits.get(i);
     elf.limits.set(i, (LightDefinition) definition.clone());
   }
   if (lightDefArray != null) {
     elf.lightDefArray = lightDefArray.clone();
   }
   return elf;
 }
 /**
  * Updates the numerical limit at the given index in the list of LightDefinition entries.
  *
  * @param index the position of the entry that should be updated.
  * @param value the new numerical limit.
  */
 public void setLimit(final int index, final Number value) {
   if (limits.size() == index) {
     final LightDefinition ldef = new LightDefinition(value, null);
     limits.add(ldef);
   } else {
     final LightDefinition ldef = limits.get(index);
     if (ldef == null) {
       final LightDefinition newdef = new LightDefinition(value, null);
       limits.set(index, newdef);
     } else {
       final LightDefinition newdef = new LightDefinition(value, ldef.getColor());
       limits.set(index, newdef);
     }
   }
   lightDefArray = null;
 }
 /**
  * Updates the color at the given index in the list of LightDefinition entries.
  *
  * @param index the position of the entry that should be updated.
  * @param color the new color.
  */
 public void setColor(final int index, final Color color) {
   if (limits.size() == index) {
     final LightDefinition ldef = new LightDefinition(null, color);
     limits.add(ldef);
     lightDefArray = null;
   } else {
     final LightDefinition ldef = limits.get(index);
     if (ldef == null) {
       final LightDefinition newdef = new LightDefinition(null, color);
       limits.set(index, newdef);
       lightDefArray = null;
     } else {
       final LightDefinition newdef = new LightDefinition(ldef.getLimit(), color);
       limits.set(index, newdef);
       lightDefArray = null;
     }
   }
 }
 /**
  * Compares this LightDefinition with another LightDefinition. This will happily crash if the
  * given object is no LightDefinition object.
  *
  * @param o the other object.
  * @return -1, 0 or -1 depending on whether this object is less, equal or greater than the given
  *     object.
  * @throws ClassCastException if the given object is no LightDefinition.
  */
 public int compareTo(final Object o) {
   final LightDefinition ldef = (LightDefinition) o;
   final Number myLimit = this.getLimit();
   final Number otherLimit = ldef.getLimit();
   if (myLimit == null && otherLimit == null) {
     return 0;
   }
   if (myLimit == null) {
     return +1;
   }
   if (otherLimit == null) {
     return -1;
   }
   final double myValue = myLimit.doubleValue();
   final double otherValue = otherLimit.doubleValue();
   if (myValue < otherValue) {
     return -1;
   }
   if (myValue > otherValue) {
     return +1;
   }
   return 0;
 }
  /**
   * Computes the color that corresponds to the LightDefinition entry for which the limits match the
   * value read from field.
   *
   * @return the computed color.
   */
  private Color computeColor() {
    if (field == null) {
      return defaultColor;
    }

    final Object o = getDataRow().get(field);
    if (o instanceof Number == false) {
      return defaultColor;
    }

    final Number n = (Number) o;
    final Number value;
    if (useAbsoluteValue) {
      if (n instanceof BigDecimal) {
        final BigDecimal td = (BigDecimal) n;
        value = td.abs();
      } else {
        final BigDecimal td = new BigDecimal(n.toString());
        value = td.abs();
      }
    } else {
      value = n;
    }

    if (lightDefArray == null) {
      lightDefArray = limits.toArray(new LightDefinition[limits.size()]);
      Arrays.sort(lightDefArray);
    }

    if (useOppositeLogic) {
      // Inverse logic. The first interval ranging from '-INF' to the first limit will use the
      // first color. If the value is in the range 'limit[i]' and 'limit[i+1]', the color[i+1]
      // will be used. If the value is greater than the last limit, the default color is used.

      if (limits.isEmpty()) {
        return defaultColor;
      }

      Color returnColor = defaultColor;
      for (int i = lightDefArray.length - 1; i >= 0; i--) {
        final LightDefinition definition = lightDefArray[i];
        if (definition == null) {
          continue;
        }
        final Number limit = definition.getLimit();
        if (limit == null) {
          continue;
        }
        if (value.doubleValue() < limit.doubleValue()) {
          returnColor = definition.getColor();
        }
      }
      if (returnColor == null) {
        return defaultColor;
      }
      return returnColor;
    } else {
      // Standard logic. The first interval from '-INF' to the first limit uses the default color.
      // from there, the color for the first limit that is greater than the given value is used.
      // For the interval ranging from the last limit to '+INF', the last color is used.
      // If there are no limits defined, the default color is always used.

      Color returnColor = defaultColor;
      for (int i = 0; i < lightDefArray.length; i++) {
        final LightDefinition definition = lightDefArray[i];
        if (definition == null) {
          continue;
        }
        final Number limit = definition.getLimit();
        if (limit == null) {
          continue;
        }
        if (value.doubleValue() >= limit.doubleValue()) {
          returnColor = definition.getColor();
        }
      }
      if (returnColor == null) {
        return defaultColor;
      }
      return returnColor;
    }
  }