/* * @(#)AggregatedRange.java 6/9/2011 * * Copyright 2002 - 2011 JIDE Software Inc. All rights reserved. */ package com.jidesoft.range; import com.jidesoft.swing.JideSwingUtilities; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; /** * A range class formed from a collection of Positionable instances. The class can be used to derive the minimum and * maximum values for the collection of Positionables, as well as providing other useful information such as the sum of * all the positive values and the sum of all the negative values. (These are used in the preparation of a stacked bar * chart.) */ public class AggregatedRange implements Range<Double> { private Double positiveSum; private int positiveCount; private Double negativeSum; private int negativeCount; private List<Positionable> positions; /** * Create an empty range */ public AggregatedRange() { this(null); } /** * Create a range from the supplied Positionable instances * * @param positions the instances of the Positionable interface */ public AggregatedRange(Collection<Positionable> positions) { this.positions = positions == null ? new ArrayList<Positionable>() : new ArrayList<Positionable>(positions); Collections.sort(this.positions); } /** * The lower value of the range; for this class it is the same as minimum() * * @return the lower value of the range */ public Double lower() { return minimum(); } /** * The upper value of the range; for this class it is the same as maximum() * * @return the upper value of the range */ public Double upper() { return maximum(); } /** * The number of points being combined in this range * * @return the number of points contributing to the range */ public int getCount() { return positions.size(); } /** * Computes the sum of all the positive Positionables * * @return the sum of all the positive Positionables */ public double getPositiveSum() { if (positiveSum == null) { updatePositives(); } return positiveSum; } public int getPositiveCount() { if (positiveSum == null) { updatePositives(); } return positiveCount; } private void updatePositives() { // Use a double to avoid autoboxing double sum = 0.0; positiveCount = 0; if (positions != null) { for (Positionable pos : positions) { if (pos.position() >= 0) { sum += pos.position(); positiveCount++; } } } positiveSum = sum; } /** * Computes the sum of all the negative Positionables * * @return the sum of all the negative Positionables */ public double getNegativeSum() { if (negativeSum == null) { updateNegatives(); } return negativeSum; } public int getNegativeCount() { if (negativeSum == null) { updateNegatives(); } return negativeCount; } private void updateNegatives() { // Use a double to avoid autoboxing double sum = 0.0; negativeCount = 0; if (positions != null) { for (Positionable pos : positions) { if (pos.position() < 0) { sum += pos.position(); negativeCount++; } } } negativeSum = sum; } /** * Returns the minimum (numeric) value in the range * * @return the minimum value in the range */ public double minimum() { if (positions == null || positions.size() == 0) { return Double.NEGATIVE_INFINITY; } Positionable first = positions.get(0); return first.position(); } /** * Returns the maximum (numeric) value in the range * * @return the maximum value in the range */ public double maximum() { if (positions == null || positions.size() == 0) { return Double.POSITIVE_INFINITY; } Positionable last = positions.get(positions.size() - 1); return last.position(); } /** * The size of the range, computed as the difference between the maximum and the minimum * * @return the size of the range (i.e., max - min) */ public double size() { return maximum() - minimum(); } /** * Returns a boolean to indicate whether the supplied Double lies within this range */ public boolean contains(Double item) { return item != null && item >= minimum() && item <= maximum(); } /** * Not supported in this class */ public void adjust(Double lower, Double upper) { throw new UnsupportedOperationException("An aggregated range is immutable"); } /** * Not supported in this class */ public void addPropertyChangeListener(PropertyChangeListener propertyChangeListener) { throw new UnsupportedOperationException("An aggregated range is immutable"); } /** * Not supported in this class */ public void removePropertyChangeListener(PropertyChangeListener propertyChangeListener) { throw new UnsupportedOperationException("An aggregated range is immutable"); } @Override public PropertyChangeListener[] getPropertyChangeListeners() { return new PropertyChangeListener[0]; } @Override public PropertyChangeListener[] getPropertyChangeListeners(String propertyName) { return new PropertyChangeListener[0]; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof AggregatedRange)) return false; AggregatedRange that = (AggregatedRange) o; if (negativeCount != that.negativeCount) return false; if (positiveCount != that.positiveCount) return false; if (negativeSum != null ? !negativeSum.equals(that.negativeSum) : that.negativeSum != null) return false; if (!JideSwingUtilities.equals(positions, that.positions, true)) return false; if (positiveSum != null ? !positiveSum.equals(that.positiveSum) : that.positiveSum != null) return false; return true; } @Override public int hashCode() { int result = positiveSum != null ? positiveSum.hashCode() : 0; result = 31 * result + positiveCount; result = 31 * result + (negativeSum != null ? negativeSum.hashCode() : 0); result = 31 * result + negativeCount; result = 31 * result + (positions != null ? positions.hashCode() : 0); return result; } }