    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;
    034
    035import java.io.Serializable;
    036import java.util.ArrayList;
    037import java.util.List;
    038
    039import com.orsoncharts.util.ArgChecks;
    040
    041/**
    042 * A list of {@code (key, value)} pairs.
    043 * <br><br>
    044 * This is the basic structure of the data required for a pie chart.
    045 * <br><br>
    046 * NOTE: This class is serializable, but the serialization format is subject
    047 * to change in future releases and should not be relied upon for persisting
    048 * instances of this class.
    049 */
    050@SuppressWarnings("serial")
    051public final class DefaultKeyedValues<T> implements KeyedValues<T>,
    052        Serializable {
    053
    054    /** Storage for the data items. */
    055    private List<KeyedValue<T>> data;
    056
    057    /**
    058     * Creates a new (empty) list of keyed values.
    059     */
    060    public DefaultKeyedValues() {
    061        this(new ArrayList<Comparable<?>>());
    062    }
    063
    064    /**
    065     * Creates a new instance with the specified keys (each associated with
    066     * a {@code null} value).  There is usually no need to specify any
    067     * keys in advance, so you will normally use the default constructor.  This
    068     * constructor is provided for the convenience of some internal code.
    069     *
    070     * @param keys  the keys ({@code null} not permitted).
    071     */
    072    public DefaultKeyedValues(List<Comparable<?>> keys) {
    073        ArgChecks.nullNotPermitted(keys, "keys");
    074        this.data = new ArrayList<KeyedValue<T>>();
    075        for (Comparable<?> key : keys) {
    076            this.data.add(new DefaultKeyedValue<T>(key, null));
    077        }
    078    }
    079
    080    /**
    081     * Clears all the data.
    082     */
    083    public void clear() {
    084        this.data.clear();
    085    }
    086
    087    /**
    088     * Adds a value or, if there is an existing value with the same key, updates
    089     * an existing value.
    090     *
    091     * @param key  the key ({@code null} not permitted)
    092     * @param value  the value.
    093     */
    094    public void put(Comparable<?> key, T value) {
    095        ArgChecks.nullNotPermitted(key, "key");
    096        DefaultKeyedValue<T> dkv;
    097        int index = getIndex(key);
    098        if (index >= 0) {
    099            dkv = (DefaultKeyedValue<T>) this.data.get(index);
    100            dkv.setValue(value);
    101        } else {
    102            this.data.add(new DefaultKeyedValue<T>(key, value));
    103        }
    104    }
    105
    106    /**
    107     * Removes the item with the specified key, if there is one.
    108     *
    109     * @param key  the key ({@code null} not permitted).
    110     */
    111    public void remove(Comparable<?> key) {
    112        ArgChecks.nullNotPermitted(key, "key");
    113        int index = getIndex(key);
    114        if (index >= 0) {
    115            remove(index);
    116        }
    117    }
    118
    119    /**
    120     * Removes the item with the specified index.
    121     *
    122     * @param index  the index.
    123     */
    124    public void remove(int index) {
    125        this.data.remove(index);
    126    }
    127
    128    /**
    129     * Returns the key for the item with the specified index.
    130     *
    131     * @param index  the item index.
    132     *
    133     * @return The key.
    134     */
    135    @Override
    136    public Comparable<?> getKey(int index) {
    137        KeyedValue<T> kv = this.data.get(index);
    138        return kv.getKey();
    139    }
    140
    141    /**
    142     * Returns the index of the item with the specified key, or {@code -1}
    143     * if there is no such item.
    144     *
    145     * @param key  the key ({@code null} not permitted).
    146     *
    147     * @return The item index, or {@code -1}.
    148     */
    149    @Override
    150    public int getIndex(Comparable<?> key) {
    151        ArgChecks.nullNotPermitted(key, "key");
    152        for (int i = 0; i < this.data.size(); i++) {
    153            KeyedValue<T> kv = this.data.get(i);
    154            if (kv.getKey().equals(key)) {
    155                return i;
    156            }
    157        }
    158        return -1;
    159    }
    160
    161    /**
    162     * Returns a list of all the keys.  Note that the list will be a copy, so
    163     * modifying it will not impact this data structure.
    164     *
    165     * @return A list of keys (possibly empty, but never {@code null}).
    166     */
    167    @Override
    168    public List<Comparable<?>> getKeys() {
    169        List<Comparable<?>> keys = new ArrayList<Comparable<?>>();
    170        for (KeyedValue<T> kv : this.data) {
    171            keys.add(kv.getKey());
    172        }
    173        return keys;
    174    }
    175
    176    /**
    177     * Returns the value with the specified key.
    178     *
    179     * @param key  the key ({@code null} not permitted).
    180     *
    181     * @return The value (possibly {@code null}).
    182     */
    183    @Override
    184    public T getValue(Comparable<?> key) {
    185        // arg checking is performed by getIndex()
    186        int index = getIndex(key);
    187        if (index < 0) {
    188            return null;
    189        }
    190        return getValue(index);
    191    }
    192
    193    /**
    194     * Returns the number of items in the list.
    195     *
    196     * @return The number of items in the list.
    197     */
    198    @Override
    199    public int getItemCount() {
    200        return this.data.size();
    201    }
    202
    203    /**
    204     * Returns the value for the specified item.
    205     *
    206     * @param item  the item index.
    207     *
    208     * @return The value (possibly {@code null}).
    209     */
    210    @Override
    211    public T getValue(int item) {
    212        KeyedValue<T> kv = this.data.get(item);
    213        return kv.getValue();
    214    }
    215
    216    /**
    217     * Returns the value for the specified item, as a double primitive,
    218     * provided that the data value is an instance of {@code Number}.
    219     *
    220     * @param item  the item index.
    221     *
    222     * @return The value.
    223     */
    224    @Override
    225    public double getDoubleValue(int item) {
    226        T n = getValue(item);
    227        if (n != null && n instanceof Number) {
    228            return ((Number) n).doubleValue();
    229        }
    230        return Double.NaN;
    231    }
    232
    233    /**
    234     * Tests this instance for equality with an arbitrary object.
    235     *
    236     * @param obj  the object to test against ({@code null} permitted).
    237     *
    238     * @return A boolean.
    239     */
    240    @Override
    241    public boolean equals(Object obj) {
    242        if (obj == this) {
    243            return true;
    244        }
    245        if (!(obj instanceof DefaultKeyedValues<?>)) {
    246            return false;
    247        }
    248        DefaultKeyedValues<?> that = (DefaultKeyedValues<?>) obj;
    249        if (!this.data.equals(that.data)) {
    250            return false;
    251        }
    252        return true;
    253    }
    254}