001/* ===========================================================
002 * Orson Charts : a 3D chart library for the Java(tm) platform
003 * ===========================================================
004 * 
005 * (C)opyright 2013-2016, by Object Refinery Limited.  All rights reserved.
006 * 
007 * http://www.object-refinery.com/orsoncharts/index.html
008 * 
009 * This program is free software: you can redistribute it and/or modify
010 * it under the terms of the GNU General Public License as published by
011 * the Free Software Foundation, either version 3 of the License, or
012 * (at your option) any later version.
013 *
014 * This program is distributed in the hope that it will be useful,
015 * but WITHOUT ANY WARRANTY; without even the implied warranty of
016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
017 * GNU General Public License for more details.
018 *
019 * You should have received a copy of the GNU General Public License
020 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
021 * 
022 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 
023 * Other names may be trademarks of their respective owners.]
024 * 
025 * If you do not wish to be bound by the terms of the GPL, an alternative
026 * commercial license can be purchased.  For details, please see visit the
027 * Orson Charts home page:
028 * 
029 * http://www.object-refinery.com/orsoncharts/index.html
030 * 
031 */
032
033package com.orsoncharts.data.xyz;
034
035import java.io.Serializable;
036import java.util.ArrayList;
037import java.util.List;
038
039import com.orsoncharts.util.ArgChecks;
040import com.orsoncharts.data.AbstractDataset3D;
041import com.orsoncharts.data.JSONUtils;
042import com.orsoncharts.plot.XYZPlot;
043import com.orsoncharts.renderer.xyz.XYZRenderer;
044import com.orsoncharts.util.ObjectUtils;
045
046/**
047 * A collection of {@link XYZSeries} objects (implements the {@link XYZDataset}
048 * interface so that it can be used as a source of data for an 
049 * {@link XYZRenderer} on an {@link XYZPlot}).
050 * <br><br>
051 * NOTE: This class is serializable, but the serialization format is subject 
052 * to change in future releases and should not be relied upon for persisting 
053 * instances of this class. 
054 */
055@SuppressWarnings("serial")
056public class XYZSeriesCollection extends AbstractDataset3D 
057        implements XYZDataset, Serializable {
058
059    /** Storage for the data series. */
060    private final List<XYZSeries> series;
061
062    /**
063     * Creates a new (empty) {@code XYZSeriesCollection} instance.
064     */
065    public XYZSeriesCollection() {
066        this.series = new ArrayList<XYZSeries>();
067    }
068
069    /**
070     * Returns the number of series in the collection.
071     * 
072     * @return The number of series in the collection. 
073     */
074    @Override
075    public int getSeriesCount() {
076        return this.series.size();
077    }
078    
079    /**
080     * Returns the index of the series with the specified key, or 
081     * {@code -1} if there is no series with the specified key.
082     * 
083     * @param key  the key ({@code null} not permitted).
084     * 
085     * @return The series index or {@code -1}. 
086     */
087    @Override
088    public int getSeriesIndex(Comparable<?> key) {
089        ArgChecks.nullNotPermitted(key, "key");
090        return getSeriesKeys().indexOf(key);
091    }
092
093    /**
094     * Returns a new list containing all the series keys.  Modifying this list 
095     * will have no impact on the {@code XYZSeriesCollection} instance.
096     * 
097     * @return A list containing the series keys (possibly empty, but never 
098     *     {@code null}).
099     */
100    @Override
101    public List<Comparable<?>> getSeriesKeys() {
102        List<Comparable<?>> result = new ArrayList<Comparable<?>>();
103        for (XYZSeries s : this.series) {
104            result.add(s.getKey());
105        }
106        return result;
107    }
108    
109    /**
110     * Returns the key for the specified series.
111     * 
112     * @param seriesIndex  the series index.
113     * 
114     * @return The series key.
115     * 
116     * @since 1.3
117     */
118    @Override
119    public Comparable<?> getSeriesKey(int seriesIndex) {
120        return getSeries(seriesIndex).getKey();
121    }
122
123    /**
124     * Adds a series to the collection (note that the series key must be
125     * unique within the collection).
126     * 
127     * @param series  the series ({@code null} not permitted). 
128     */
129    public void add(XYZSeries series) {
130        ArgChecks.nullNotPermitted(series, "series");
131        if (getSeriesIndex(series.getKey()) >= 0) {
132            throw new IllegalArgumentException("Another series with the same key already exists within the collection.");
133        }
134        this.series.add(series);
135    }
136    
137    /**
138     * Returns the series with the specified index.
139     * 
140     * @param index  the series index.
141     * 
142     * @return The series.
143     * 
144     * @since 1.2
145     */
146    public XYZSeries getSeries(int index) {
147        ArgChecks.checkArrayBounds(index, "index", this.series.size());
148        return this.series.get(index);
149    }
150    
151    /**
152     * Returns the series with the specified key, or {@code null} if 
153     * there is no such series.
154     * 
155     * @param key  the key ({@code null} not permitted).
156     * 
157     * @return The series. 
158     * 
159     * @since 1.2
160     */
161    public XYZSeries getSeries(Comparable<?> key) {
162        ArgChecks.nullNotPermitted(key, "key");
163        for (XYZSeries s : this.series) {
164            if (s.getKey().equals(key)) {
165                return s;
166            }
167        }
168        return null;
169    }
170
171    /**
172     * Returns the number of items in the specified series.
173     * 
174     * @param seriesIndex  the series index.
175     * 
176     * @return The number of items in the specified series. 
177     */
178    @Override
179    public int getItemCount(int seriesIndex) {
180        XYZSeries s = this.series.get(seriesIndex);
181        return s.getItemCount();
182    }
183
184    /**
185     * Returns the x-value for one item in a series.
186     * 
187     * @param seriesIndex  the series index.
188     * @param itemIndex  the item index.
189     * 
190     * @return The x-value. 
191     */
192    @Override
193    public double getX(int seriesIndex, int itemIndex) {
194        XYZSeries s = this.series.get(seriesIndex);
195        return s.getXValue(itemIndex);
196    }
197
198    /**
199     * Returns the y-value for one item in a series.
200     * 
201     * @param seriesIndex  the series index.
202     * @param itemIndex  the item index.
203     * 
204     * @return The y-value. 
205     */
206    @Override
207    public double getY(int seriesIndex, int itemIndex) {
208        XYZSeries s = this.series.get(seriesIndex);
209        return s.getYValue(itemIndex);
210    }
211
212    /**
213     * Returns the z-value for one item in a series.
214     * 
215     * @param seriesIndex  the series index.
216     * @param itemIndex  the item index.
217     * 
218     * @return The z-value. 
219     */
220    @Override
221    public double getZ(int seriesIndex, int itemIndex) {
222        XYZSeries s = this.series.get(seriesIndex);
223        return s.getZValue(itemIndex);
224    }
225
226    /**
227     * Tests this dataset for equality with an arbitrary object.
228     * 
229     * @param obj  the object ({@code null} not permitted).
230     * 
231     * @return A boolean. 
232     */
233    @Override
234    public boolean equals(Object obj) {
235        if (obj == this) {
236            return true;
237        }
238        if (!(obj instanceof XYZSeriesCollection)) {
239            return false;
240        }
241        XYZSeriesCollection that = (XYZSeriesCollection) obj;
242        if (!this.series.equals(that.series)) {
243            return false;
244        }
245        return true;
246    }
247
248    @Override
249    public int hashCode() {
250        int hash = 5;
251        hash = 59 * hash + ObjectUtils.hashCode(this.series);
252        return hash;
253    }
254    
255    /**
256     * Returns a string representation of this instance, primarily for 
257     * debugging purposes.
258     * <br><br>
259     * Implementation note: the current implementation (which is subject to 
260     * change) writes the dataset in JSON format using 
261     * {@link JSONUtils#writeXYZDataset(com.orsoncharts.data.xyz.XYZDataset)}.
262     * 
263     * @return A string. 
264     */
265    @Override
266    public String toString() {
267        return JSONUtils.writeXYZDataset(this);
268    }
269
270}