001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2022, by David Gilbert and Contributors.
006 *
007 * Project Info:  http://www.jfree.org/jfreechart/index.html
008 *
009 * This library is free software; you can redistribute it and/or modify it
010 * under the terms of the GNU Lesser General Public License as published by
011 * the Free Software Foundation; either version 2.1 of the License, or
012 * (at your option) any later version.
013 *
014 * This library is distributed in the hope that it will be useful, but
015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017 * License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this library; if not, write to the Free Software
021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
022 * USA.
023 *
024 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 
025 * Other names may be trademarks of their respective owners.]
026 *
027 * ---------------------------
028 * MatrixSeriesCollection.java
029 * ---------------------------
030 * (C) Copyright 2003-2021, by Barak Naveh and Contributors.
031 *
032 * Original Author:  Barak Naveh;
033 * Contributor(s):   David Gilbert;
034 *
035 */
036
037package org.jfree.data.xy;
038
039import java.io.Serializable;
040import java.util.ArrayList;
041import java.util.List;
042import java.util.Objects;
043
044import org.jfree.chart.internal.Args;
045import org.jfree.chart.internal.CloneUtils;
046import org.jfree.chart.api.PublicCloneable;
047
048/**
049 * Represents a collection of {@link MatrixSeries} that can be used as a
050 * dataset.
051 *
052 * @see org.jfree.data.xy.MatrixSeries
053 */
054public class MatrixSeriesCollection<S extends Comparable<S>> 
055        extends AbstractXYZDataset
056        implements XYZDataset, PublicCloneable, Serializable {
057
058    /** For serialization. */
059    private static final long serialVersionUID = -3197705779242543945L;
060
061    /** The series that are included in the collection. */
062    private List<MatrixSeries<S>> seriesList;
063
064    /**
065     * Constructs an empty dataset.
066     */
067    public MatrixSeriesCollection() {
068        this(null);
069    }
070
071
072    /**
073     * Constructs a dataset and populates it with a single matrix series.
074     *
075     * @param series the time series.
076     */
077    public MatrixSeriesCollection(MatrixSeries<S> series) {
078        this.seriesList = new ArrayList<>();
079
080        if (series != null) {
081            this.seriesList.add(series);
082            series.addChangeListener(this);
083        }
084    }
085
086    /**
087     * Returns the number of items in the specified series.
088     *
089     * @param seriesIndex zero-based series index.
090     *
091     * @return The number of items in the specified series.
092     */
093    @Override
094    public int getItemCount(int seriesIndex) {
095        return getSeries(seriesIndex).getItemCount();
096    }
097
098
099    /**
100     * Returns the series having the specified index.
101     *
102     * @param seriesIndex zero-based series index.
103     *
104     * @return The series.
105     */
106    public MatrixSeries<S> getSeries(int seriesIndex) {
107        Args.requireInRange(seriesIndex, "seriesIndex", 0, this.seriesList.size() - 1);
108        MatrixSeries<S> series = this.seriesList.get(seriesIndex);
109        return series;
110    }
111
112
113    /**
114     * Returns the number of series in the collection.
115     *
116     * @return The number of series in the collection.
117     */
118    @Override
119    public int getSeriesCount() {
120        return this.seriesList.size();
121    }
122
123
124    /**
125     * Returns the key for a series.
126     *
127     * @param seriesIndex zero-based series index.
128     *
129     * @return The key for a series.
130     */
131    @Override
132    public S getSeriesKey(int seriesIndex) {
133        return getSeries(seriesIndex).getKey();
134    }
135
136
137    /**
138     * Returns the j index value of the specified Mij matrix item in the
139     * specified matrix series.
140     *
141     * @param seriesIndex zero-based series index.
142     * @param itemIndex zero-based item index.
143     *
144     * @return The j index value for the specified matrix item.
145     *
146     * @see org.jfree.data.xy.XYDataset#getXValue(int, int)
147     */
148    @Override
149    public Number getX(int seriesIndex, int itemIndex) {
150        MatrixSeries series = this.seriesList.get(seriesIndex);
151        return series.getItemColumn(itemIndex);
152    }
153
154
155    /**
156     * Returns the i index value of the specified Mij matrix item in the
157     * specified matrix series.
158     *
159     * @param seriesIndex zero-based series index.
160     * @param itemIndex zero-based item index.
161     *
162     * @return The i index value for the specified matrix item.
163     *
164     * @see org.jfree.data.xy.XYDataset#getYValue(int, int)
165     */
166    @Override
167    public Number getY(int seriesIndex, int itemIndex) {
168        MatrixSeries series = this.seriesList.get(seriesIndex);
169        return series.getItemRow(itemIndex);
170    }
171
172
173    /**
174     * Returns the Mij item value of the specified Mij matrix item in the
175     * specified matrix series.
176     *
177     * @param seriesIndex the series (zero-based index).
178     * @param itemIndex zero-based item index.
179     *
180     * @return The Mij item value for the specified matrix item.
181     *
182     * @see org.jfree.data.xy.XYZDataset#getZValue(int, int)
183     */
184    @Override
185    public Number getZ(int seriesIndex, int itemIndex) {
186        MatrixSeries series = this.seriesList.get(seriesIndex);
187        return series.getItem(itemIndex);
188    }
189
190    /**
191     * Adds a series to the collection.
192     * <P>
193     * Notifies all registered listeners that the dataset has changed.
194     * </p>
195     *
196     * @param series the series ({@code null} not permitted).
197     */
198    public void addSeries(MatrixSeries<S> series) {
199        Args.nullNotPermitted(series, "series");
200        // FIXME: Check that there isn't already a series with the same key
201
202        // add the series...
203        this.seriesList.add(series);
204        series.addChangeListener(this);
205        fireDatasetChanged();
206    }
207
208
209    /**
210     * Tests this collection for equality with an arbitrary object.
211     *
212     * @param obj the object.
213     *
214     * @return A boolean.
215     */
216    @Override
217    public boolean equals(Object obj) {
218        if (obj == null) {
219            return false;
220        }
221
222        if (obj == this) {
223            return true;
224        }
225
226        if (obj instanceof MatrixSeriesCollection) {
227            MatrixSeriesCollection<S> c = (MatrixSeriesCollection) obj;
228
229            return Objects.equals(this.seriesList, c.seriesList);
230        }
231
232        return false;
233    }
234
235    /**
236     * Returns a hash code.
237     *
238     * @return A hash code.
239     */
240    @Override
241    public int hashCode() {
242        return (this.seriesList != null ? this.seriesList.hashCode() : 0);
243    }
244
245    /**
246     * Returns a clone of this instance.
247     *
248     * @return A clone.
249     *
250     * @throws CloneNotSupportedException if there is a problem.
251     */
252    @Override
253    public Object clone() throws CloneNotSupportedException {
254        MatrixSeriesCollection<S> clone = (MatrixSeriesCollection) super.clone();
255        clone.seriesList = CloneUtils.cloneList(this.seriesList);
256        return clone;
257    }
258
259    /**
260     * Removes all the series from the collection.
261     * <P>
262     * Notifies all registered listeners that the dataset has changed.
263     * </p>
264     */
265    public void removeAllSeries() {
266        // Unregister the collection as a change listener to each series in
267        // the collection.
268        for (MatrixSeries series : this.seriesList) {
269            series.removeChangeListener(this);
270        }
271
272        // Remove all the series from the collection and notify listeners.
273        this.seriesList.clear();
274        fireDatasetChanged();
275    }
276
277
278    /**
279     * Removes a series from the collection.
280     * <P>
281     * Notifies all registered listeners that the dataset has changed.
282     * </p>
283     *
284     * @param series the series ({@code null}).
285     */
286    public void removeSeries(MatrixSeries<S> series) {
287        Args.nullNotPermitted(series, "series");
288        if (this.seriesList.contains(series)) {
289            series.removeChangeListener(this);
290            this.seriesList.remove(series);
291            fireDatasetChanged();
292        }
293    }
294
295
296    /**
297     * Removes a series from the collection.
298     * <P>
299     * Notifies all registered listeners that the dataset has changed.
300     *
301     * @param seriesIndex the series (zero based index).
302     */
303    public void removeSeries(int seriesIndex) {
304        Args.requireInRange(seriesIndex, "seriesIndex", 0, this.seriesList.size() -1);
305
306        // fetch the series, remove the change listener, then remove the series.
307        MatrixSeries series = this.seriesList.get(seriesIndex);
308        series.removeChangeListener(this);
309        this.seriesList.remove(seriesIndex);
310        fireDatasetChanged();
311    }
312
313}