package com.positive.charts.data.xy;
import java.util.ArrayList;
import java.util.List;
import com.positive.charts.data.DomainOrder;
import com.positive.charts.event.DatasetChangeEvent;
/**
* A default implementation of the {@link XYDataset} interface that stores data
* values in arrays of double primitives.
*/
public class DefaultXYDataset extends AbstractXYDataset implements XYDataset {
/** For serialization. */
private static final long serialVersionUID = 7190822741344141552L;
/**
* Storage for the series keys. This list must be kept in sync with the
* seriesList.
*/
private final List seriesKeys;
/**
* Storage for the series in the dataset. We use a list because the order of
* the series is significant. This list must be kept in sync with the
* seriesKeys list.
*/
private final List seriesList;
/**
* Creates a new <code>DefaultXYDataset</code> instance, initially
* containing no data.
*/
public DefaultXYDataset() {
this.seriesKeys = new ArrayList();
this.seriesList = new ArrayList();
}
/**
* Adds a series or if a series with the same key already exists replaces
* the data for that series, then sends a {@link DatasetChangeEvent} to all
* registered listeners.
*
* @param seriesKey
* the series key (<code>null</code> not permitted).
* @param data
* the data (must be an array with length 2, containing two
* arrays of equal length, the first containing the x-values and
* the second containing the y-values).
*/
public void addSeries(final Comparable seriesKey, final double[][] data) {
if (seriesKey == null) {
throw new IllegalArgumentException(
"The 'seriesKey' cannot be null.");
}
if (data == null) {
throw new IllegalArgumentException("The 'data' is null.");
}
if (data.length != 2) {
throw new IllegalArgumentException(
"The 'data' array must have length == 2.");
}
if (data[0].length != data[1].length) {
throw new IllegalArgumentException(
"The 'data' array must contain two arrays with equal length.");
}
final int seriesIndex = this.indexOf(seriesKey);
if (seriesIndex == -1) { // add a new series
this.seriesKeys.add(seriesKey);
this.seriesList.add(data);
} else { // replace an existing series
this.seriesList.remove(seriesIndex);
this.seriesList.add(seriesIndex, data);
}
this.notifyListeners(new DatasetChangeEvent(this, this));
}
/**
* Returns the order of the domain (x-) values in the dataset. In this
* implementation, we cannot guarantee that the x-values are ordered, so
* this method returns <code>DomainOrder.NONE</code>.
*
* @return <code>DomainOrder.NONE</code>.
*/
public DomainOrder getDomainOrder() {
return DomainOrder.NONE;
}
/**
* Returns the number of items in the specified series.
*
* @param series
* the series index (in the range <code>0</code> to
* <code>getSeriesCount() - 1</code>).
*
* @return The item count.
*
* @throws IllegalArgumentException
* if <code>series</code> is not in the specified range.
*/
public int getItemCount(final int series) {
if ((series < 0) || (series >= this.getSeriesCount())) {
throw new IllegalArgumentException("Series index out of bounds");
}
final double[][] seriesArray = (double[][]) this.seriesList.get(series);
return seriesArray[0].length;
}
/**
* Returns the number of series in the dataset.
*
* @return The series count.
*/
public int getSeriesCount() {
return this.seriesList.size();
}
/**
* Returns the key for a series.
*
* @param series
* the series index (in the range <code>0</code> to
* <code>getSeriesCount() - 1</code>).
*
* @throws IndexOutOfBoundsException
* if the index is out of range (index < 0 || index >= size()).
*
* @return The key for the series.
*/
public Comparable getSeriesKey(final int series) {
return (Comparable) this.seriesKeys.get(series);
}
/**
* Returns the x-value for an item within a series.
*
* @param series
* the series index (in the range <code>0</code> to
* <code>getSeriesCount() - 1</code>).
* @param item
* the item index (in the range <code>0</code> to
* <code>getItemCount(series)</code>).
*
* @return The x-value.
*
* @throws ArrayIndexOutOfBoundsException
* if <code>series</code> is not within the specified range.
* @throws ArrayIndexOutOfBoundsException
* if <code>item</code> is not within the specified range.
*
* @see #getXValue(int, int)
*/
public Number getX(final int series, final int item) {
return new Double(this.getXValue(series, item));
}
/**
* Returns the x-value for an item within a series.
*
* @param series
* the series index (in the range <code>0</code> to
* <code>getSeriesCount() - 1</code>).
* @param item
* the item index (in the range <code>0</code> to
* <code>getItemCount(series)</code>).
*
* @return The x-value.
*
* @throws ArrayIndexOutOfBoundsException
* if <code>series</code> is not within the specified range.
* @throws ArrayIndexOutOfBoundsException
* if <code>item</code> is not within the specified range.
*
* @see #getX(int, int)
*/
public double getXValue(final int series, final int item) {
final double[][] seriesData = (double[][]) this.seriesList.get(series);
return seriesData[0][item];
}
/**
* Returns the y-value for an item within a series.
*
* @param series
* the series index (in the range <code>0</code> to
* <code>getSeriesCount() - 1</code>).
* @param item
* the item index (in the range <code>0</code> to
* <code>getItemCount(series)</code>).
*
* @return The y-value.
*
* @throws ArrayIndexOutOfBoundsException
* if <code>series</code> is not within the specified range.
* @throws ArrayIndexOutOfBoundsException
* if <code>item</code> is not within the specified range.
*
* @see #getX(int, int)
*/
public Number getY(final int series, final int item) {
return new Double(this.getYValue(series, item));
}
/**
* Returns the y-value for an item within a series.
*
* @param series
* the series index (in the range <code>0</code> to
* <code>getSeriesCount() - 1</code>).
* @param item
* the item index (in the range <code>0</code> to
* <code>getItemCount(series)</code>).
*
* @return The y-value.
*
* @throws ArrayIndexOutOfBoundsException
* if <code>series</code> is not within the specified range.
* @throws ArrayIndexOutOfBoundsException
* if <code>item</code> is not within the specified range.
*
* @see #getY(int, int)
*/
public double getYValue(final int series, final int item) {
final double[][] seriesData = (double[][]) this.seriesList.get(series);
return seriesData[1][item];
}
/**
* Returns the index of the series with the specified key, or -1 if there is
* no such series in the dataset.
*
* @param seriesKey
* the series key (<code>null</code> permitted).
*
* @return The index, or -1.
*/
public int indexOf(final Comparable seriesKey) {
return this.seriesKeys.indexOf(seriesKey);
}
/**
* Removes a series from the dataset, then sends a
* {@link DatasetChangeEvent} to all registered listeners.
*
* @param seriesKey
* the series key (<code>null</code> not permitted).
*
*/
public void removeSeries(final Comparable seriesKey) {
final int seriesIndex = this.indexOf(seriesKey);
if (seriesIndex >= 0) {
this.seriesKeys.remove(seriesIndex);
this.seriesList.remove(seriesIndex);
this.notifyListeners(new DatasetChangeEvent(this, this));
}
}
}