001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2008, by Object Refinery Limited 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 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025 * in the United States and other countries.]
026 *
027 * ---------------
028 * XYDataItem.java
029 * ---------------
030 * (C) Copyright 2003-2008, by Object Refinery Limited.
031 *
032 * Original Author:  David Gilbert (for Object Refinery Limited);
033 * Contributor(s):   -;
034 *
035 * Changes
036 * -------
037 * 05-Aug-2003 : Renamed XYDataPair --> XYDataItem (DG);
038 * 03-Feb-2004 : Fixed bug in equals() method (DG);
039 * 21-Feb-2005 : Added setY(double) method (DG);
040 * ------------- JFREECHART 1.0.x ---------------------------------------------
041 * 30-Nov-2007 : Implemented getXValue() and getYValue(), plus toString() for
042 *               debugging use (DG);
043 *
044 */
045
046package org.jfree.data.xy;
047
048import java.io.Serializable;
049
050import org.jfree.util.ObjectUtilities;
051
052/**
053 * Represents one (x, y) data item for an {@link XYSeries}.
054 */
055public class XYDataItem implements Cloneable, Comparable, Serializable {
056
057    /** For serialization. */
058    private static final long serialVersionUID = 2751513470325494890L;
059
060    /** The x-value (<code>null</code> not permitted). */
061    private Number x;
062
063    /** The y-value. */
064    private Number y;
065
066    /**
067     * Constructs a new data item.
068     *
069     * @param x  the x-value (<code>null</code> NOT permitted).
070     * @param y  the y-value (<code>null</code> permitted).
071     */
072    public XYDataItem(Number x, Number y) {
073        if (x == null) {
074            throw new IllegalArgumentException("Null 'x' argument.");
075        }
076        this.x = x;
077        this.y = y;
078    }
079
080    /**
081     * Constructs a new data item.
082     *
083     * @param x  the x-value.
084     * @param y  the y-value.
085     */
086    public XYDataItem(double x, double y) {
087        this(new Double(x), new Double(y));
088    }
089
090    /**
091     * Returns the x-value.
092     *
093     * @return The x-value (never <code>null</code>).
094     */
095    public Number getX() {
096        return this.x;
097    }
098
099    /**
100     * Returns the x-value as a double primitive.
101     *
102     * @return The x-value.
103     *
104     * @see #getX()
105     * @see #getYValue()
106     *
107     * @since 1.0.9
108     */
109    public double getXValue() {
110        // this.x is not allowed to be null...
111        return this.x.doubleValue();
112    }
113
114    /**
115     * Returns the y-value.
116     *
117     * @return The y-value (possibly <code>null</code>).
118     */
119    public Number getY() {
120        return this.y;
121    }
122
123    /**
124     * Returns the y-value as a double primitive.
125     *
126     * @return The y-value.
127     *
128     * @see #getY()
129     * @see #getXValue()
130     *
131     * @since 1.0.9
132     */
133    public double getYValue() {
134        double result = Double.NaN;
135        if (this.y != null) {
136            result = this.y.doubleValue();
137        }
138        return result;
139    }
140
141    /**
142     * Sets the y-value for this data item.  Note that there is no
143     * corresponding method to change the x-value.
144     *
145     * @param y  the new y-value.
146     */
147    public void setY(double y) {
148        setY(new Double(y));
149    }
150
151    /**
152     * Sets the y-value for this data item.  Note that there is no
153     * corresponding method to change the x-value.
154     *
155     * @param y  the new y-value (<code>null</code> permitted).
156     */
157    public void setY(Number y) {
158        this.y = y;
159    }
160
161    /**
162     * Returns an integer indicating the order of this object relative to
163     * another object.
164     * <P>
165     * For the order we consider only the x-value:
166     * negative == "less-than", zero == "equal", positive == "greater-than".
167     *
168     * @param o1  the object being compared to.
169     *
170     * @return An integer indicating the order of this data pair object
171     *      relative to another object.
172     */
173    public int compareTo(Object o1) {
174
175        int result;
176
177        // CASE 1 : Comparing to another TimeSeriesDataPair object
178        // -------------------------------------------------------
179        if (o1 instanceof XYDataItem) {
180            XYDataItem dataItem = (XYDataItem) o1;
181            double compare = this.x.doubleValue()
182                             - dataItem.getX().doubleValue();
183            if (compare > 0.0) {
184                result = 1;
185            }
186            else {
187                if (compare < 0.0) {
188                    result = -1;
189                }
190                else {
191                    result = 0;
192                }
193            }
194        }
195
196        // CASE 2 : Comparing to a general object
197        // ---------------------------------------------
198        else {
199            // consider time periods to be ordered after general objects
200            result = 1;
201        }
202
203        return result;
204
205    }
206
207    /**
208     * Returns a clone of this object.
209     *
210     * @return A clone.
211     *
212     * @throws CloneNotSupportedException not thrown by this class, but
213     *         subclasses may differ.
214     */
215    public Object clone() throws CloneNotSupportedException {
216        return super.clone();
217    }
218
219    /**
220     * Tests if this object is equal to another.
221     *
222     * @param obj  the object to test against for equality (<code>null</code>
223     *             permitted).
224     *
225     * @return A boolean.
226     */
227    public boolean equals(Object obj) {
228        if (obj == this) {
229            return true;
230        }
231        if (!(obj instanceof XYDataItem)) {
232            return false;
233        }
234        XYDataItem that = (XYDataItem) obj;
235        if (!this.x.equals(that.x)) {
236            return false;
237        }
238        if (!ObjectUtilities.equal(this.y, that.y)) {
239            return false;
240        }
241        return true;
242    }
243
244    /**
245     * Returns a hash code.
246     *
247     * @return A hash code.
248     */
249    public int hashCode() {
250        int result;
251        result = this.x.hashCode();
252        result = 29 * result + (this.y != null ? this.y.hashCode() : 0);
253        return result;
254    }
255
256    /**
257     * Returns a string representing this instance, primarily for debugging
258     * use.
259     *
260     * @return A string.
261     */
262    public String toString() {
263        return "[" + getXValue() + ", " + getYValue() + "]";
264    }
265
266}