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 * YIntervalSeriesCollection.java
029 * ------------------------------
030 * (C) Copyright 2006-2022, by David Gilbert.
031 *
032 * Original Author:  David Gilbert;
033 * Contributor(s):   -;
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.CloneUtils;
045import org.jfree.chart.internal.Args;
046import org.jfree.chart.api.PublicCloneable;
047
048import org.jfree.data.general.DatasetChangeEvent;
049
050/**
051 * A collection of {@link YIntervalSeries} objects.
052 *
053 * @param <S> The type for the series keys.
054 *
055 * @see YIntervalSeries
056 */
057public class YIntervalSeriesCollection<S extends Comparable<S>> 
058        extends AbstractIntervalXYDataset<S>
059        implements IntervalXYDataset<S>, PublicCloneable, Serializable {
060
061    /** Storage for the data series. */
062    private List<YIntervalSeries> data;
063
064    /**
065     * Creates a new instance of {@code YIntervalSeriesCollection}.
066     */
067    public YIntervalSeriesCollection() {
068        this.data = new ArrayList<>();
069    }
070
071    /**
072     * Adds a series to the collection and sends a {@link DatasetChangeEvent}
073     * to all registered listeners.
074     *
075     * @param series  the series ({@code null} not permitted).
076     */
077    public void addSeries(YIntervalSeries<S> series) {
078        Args.nullNotPermitted(series, "series");
079        this.data.add(series);
080        series.addChangeListener(this);
081        fireDatasetChanged();
082    }
083
084    /**
085     * Returns the number of series in the collection.
086     *
087     * @return The series count.
088     */
089    @Override
090    public int getSeriesCount() {
091        return this.data.size();
092    }
093
094    /**
095     * Returns a series from the collection.
096     *
097     * @param series  the series index (zero-based).
098     *
099     * @return The series.
100     *
101     * @throws IllegalArgumentException if {@code series} is not in the
102     *     range {@code 0} to {@code getSeriesCount() - 1}.
103     */
104    public YIntervalSeries<S> getSeries(int series) {
105        Args.requireInRange(series, "series", 0, this.data.size() - 1);
106        return this.data.get(series);
107    }
108
109    /**
110     * Returns the key for a series.
111     *
112     * @param series  the series index (in the range {@code 0} to
113     *     {@code getSeriesCount() - 1}).
114     *
115     * @return The key for a series.
116     *
117     * @throws IllegalArgumentException if {@code series} is not in the
118     *     specified range.
119     */
120    @Override
121    public S getSeriesKey(int series) {
122        // defer argument checking
123        return getSeries(series).getKey();
124    }
125
126    /**
127     * Returns the number of items in the specified series.
128     *
129     * @param series  the series (zero-based index).
130     *
131     * @return The item count.
132     *
133     * @throws IllegalArgumentException if {@code series} is not in the
134     *     range {@code 0} to {@code getSeriesCount() - 1}.
135     */
136    @Override
137    public int getItemCount(int series) {
138        // defer argument checking
139        return getSeries(series).getItemCount();
140    }
141
142    /**
143     * Returns the x-value for an item within a series.
144     *
145     * @param series  the series index.
146     * @param item  the item index.
147     *
148     * @return The x-value.
149     */
150    @Override
151    public Number getX(int series, int item) {
152        YIntervalSeries s = this.data.get(series);
153        return s.getX(item);
154    }
155
156    /**
157     * Returns the y-value (as a double primitive) for an item within a
158     * series.
159     *
160     * @param series  the series index (zero-based).
161     * @param item  the item index (zero-based).
162     *
163     * @return The value.
164     */
165    @Override
166    public double getYValue(int series, int item) {
167        YIntervalSeries s = this.data.get(series);
168        return s.getYValue(item);
169    }
170
171    /**
172     * Returns the start y-value (as a double primitive) for an item within a
173     * series.
174     *
175     * @param series  the series index (zero-based).
176     * @param item  the item index (zero-based).
177     *
178     * @return The value.
179     */
180    @Override
181    public double getStartYValue(int series, int item) {
182        YIntervalSeries s = this.data.get(series);
183        return s.getYLowValue(item);
184    }
185
186    /**
187     * Returns the end y-value (as a double primitive) for an item within a
188     * series.
189     *
190     * @param series  the series (zero-based index).
191     * @param item  the item (zero-based index).
192     *
193     * @return The value.
194     */
195    @Override
196    public double getEndYValue(int series, int item) {
197        YIntervalSeries s = this.data.get(series);
198        return s.getYHighValue(item);
199    }
200
201    /**
202     * Returns the y-value for an item within a series.
203     *
204     * @param series  the series index.
205     * @param item  the item index.
206     *
207     * @return The y-value.
208     */
209    @Override
210    public Number getY(int series, int item) {
211        YIntervalSeries s = this.data.get(series);
212        return s.getYValue(item);
213    }
214
215    /**
216     * Returns the start x-value for an item within a series.  This method
217     * maps directly to {@link #getX(int, int)}.
218     *
219     * @param series  the series index.
220     * @param item  the item index.
221     *
222     * @return The x-value.
223     */
224    @Override
225    public Number getStartX(int series, int item) {
226        return getX(series, item);
227    }
228
229    /**
230     * Returns the end x-value for an item within a series.  This method
231     * maps directly to {@link #getX(int, int)}.
232     *
233     * @param series  the series index.
234     * @param item  the item index.
235     *
236     * @return The x-value.
237     */
238    @Override
239    public Number getEndX(int series, int item) {
240        return getX(series, item);
241    }
242
243    /**
244     * Returns the start y-value for an item within a series.
245     *
246     * @param series  the series index.
247     * @param item  the item index.
248     *
249     * @return The start y-value.
250     */
251    @Override
252    public Number getStartY(int series, int item) {
253        YIntervalSeries s = this.data.get(series);
254        return s.getYLowValue(item);
255    }
256
257    /**
258     * Returns the end y-value for an item within a series.
259     *
260     * @param series  the series index.
261     * @param item  the item index.
262     *
263     * @return The end y-value.
264     */
265    @Override
266    public Number getEndY(int series, int item) {
267        YIntervalSeries s = this.data.get(series);
268        return s.getYHighValue(item);
269    }
270
271    /**
272     * Removes a series from the collection and sends a
273     * {@link DatasetChangeEvent} to all registered listeners.
274     *
275     * @param series  the series index (zero-based).
276     */
277    public void removeSeries(int series) {
278        Args.requireInRange(series, "series", 0, this.data.size() - 1);
279        YIntervalSeries ts = this.data.get(series);
280        ts.removeChangeListener(this);
281        this.data.remove(series);
282        fireDatasetChanged();
283    }
284
285    /**
286     * Removes a series from the collection and sends a
287     * {@link DatasetChangeEvent} to all registered listeners.
288     *
289     * @param series  the series ({@code null} not permitted).
290     */
291    public void removeSeries(YIntervalSeries<S> series) {
292        Args.nullNotPermitted(series, "series");
293        if (this.data.contains(series)) {
294            series.removeChangeListener(this);
295            this.data.remove(series);
296            fireDatasetChanged();
297        }
298    }
299
300    /**
301     * Removes all the series from the collection and sends a
302     * {@link DatasetChangeEvent} to all registered listeners.
303     */
304    public void removeAllSeries() {
305        // Unregister the collection as a change listener to each series in
306        // the collection.
307        for (YIntervalSeries series : this.data) {
308          series.removeChangeListener(this);
309        }
310        this.data.clear();
311        fireDatasetChanged();
312    }
313
314    /**
315     * Tests this instance for equality with an arbitrary object.
316     *
317     * @param obj  the object ({@code null} permitted).
318     *
319     * @return A boolean.
320     */
321    @Override
322    public boolean equals(Object obj) {
323        if (obj == this) {
324            return true;
325        }
326        if (!(obj instanceof YIntervalSeriesCollection)) {
327            return false;
328        }
329        YIntervalSeriesCollection<S> that = (YIntervalSeriesCollection) obj;
330        return Objects.equals(this.data, that.data);
331    }
332
333    /**
334     * Returns a clone of this instance.
335     *
336     * @return A clone.
337     *
338     * @throws CloneNotSupportedException if there is a problem.
339     */
340    @Override
341    public Object clone() throws CloneNotSupportedException {
342        YIntervalSeriesCollection<S> clone
343                = (YIntervalSeriesCollection) super.clone();
344        clone.data = CloneUtils.cloneList(this.data);
345        return clone;
346    }
347
348}