001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.data.gpx;
003
004import java.util.Collection;
005import java.util.HashMap;
006import java.util.Map;
007import java.util.Objects;
008
009/**
010 * Default implementation for IWithAttributes.
011 *
012 * Base class for various classes in the GPX model.
013 *
014 * @author Frederik Ramm
015 * @since 444
016 */
017public class WithAttributes implements IWithAttributes, GpxConstants {
018
019    /**
020     * The "attr" hash is used to store the XML payload (not only XML attributes!)
021     */
022    public Map<String, Object> attr = new HashMap<>(0);
023
024    /**
025     * The "exts" collection contains all extensions.
026     */
027    private GpxExtensionCollection exts;
028
029    /**
030     * Returns the Object value to which the specified key is mapped,
031     * or {@code null} if this map contains no mapping for the key.
032     *
033     * @param key the key whose associated value is to be returned
034     * @return the value
035     */
036    @Override
037    public Object get(String key) {
038        return attr.get(key);
039    }
040
041    /**
042     * Returns the String value to which the specified key is mapped,
043     * or {@code null} if this map contains no String mapping for the key.
044     *
045     * @param key the key whose associated value is to be returned
046     * @return the String value to which the specified key is mapped,
047     *         or {@code null} if this map contains no String mapping for the key
048     */
049    @Override
050    public String getString(String key) {
051        Object value = attr.get(key);
052        return (value instanceof String) ? (String) value : null;
053    }
054
055    /**
056     * Returns the Collection value to which the specified key is mapped,
057     * or {@code null} if this map contains no Collection mapping for the key.
058     *
059     * @param key the key whose associated value is to be returned
060     * @return the Collection value to which the specified key is mapped,
061     *         or {@code null} if this map contains no Collection mapping for the key
062     * @since 5502
063     */
064    @SuppressWarnings("unchecked")
065    @Override
066    public <T> Collection<T> getCollection(String key) {
067        Object value = attr.get(key);
068        return (value instanceof Collection) ? (Collection<T>) value : null;
069    }
070
071    /**
072     * Put a key / value pair as a new attribute.
073     * Overrides key / value pair with the same key (if present).
074     *
075     * @param key the key
076     * @param value the value
077     */
078    @Override
079    public void put(String key, Object value) {
080        attr.put(key, value);
081    }
082
083    @Override
084    public Map<String, Object> getAttributes() {
085        return attr;
086    }
087
088    @Override
089    public boolean hasExtensions() {
090        return exts != null;
091    }
092
093    @Override
094    public GpxExtensionCollection getExtensions() {
095        if (exts == null) {
096            exts = new GpxExtensionCollection(this);
097        }
098        return exts;
099    }
100
101    @Override
102    public int hashCode() {
103        return Objects.hash(attr, exts);
104    }
105
106    @Override
107    public boolean equals(Object obj) {
108        if (this == obj)
109            return true;
110        if (obj == null)
111            return false;
112        if (getClass() != obj.getClass())
113            return false;
114        WithAttributes other = (WithAttributes) obj;
115        if (attr == null) {
116            if (other.attr != null)
117                return false;
118        } else if (!attr.equals(other.attr))
119            return false;
120        if (exts == null) {
121            if (other.exts != null)
122                return false;
123        } else if (!exts.equals(other.exts))
124            return false;
125        return true;
126    }
127}