001package jmri.jmrit.logixng.util;
002
003import java.util.Collection;
004import java.util.ArrayList;
005import java.util.Collections;
006import java.util.HashMap;
007import java.util.List;
008import java.util.Map;
009import java.util.Set;
010
011/**
012 * A map that may contain multiple items with same key
013 */
014public class DuplicateKeyMap<K, V> implements Map<K, V> {
015
016    Map<K, List<V>> _internalMap = new HashMap<>();
017
018    @Override
019    public int size() {
020        int c = 0;
021        for (List<V> l : _internalMap.values()) {
022            c += l.size();
023        }
024        return c;
025    }
026
027    @Override
028    public boolean isEmpty() {
029        return size() == 0;
030    }
031
032    @Override
033    public boolean containsKey(Object key) {
034        return _internalMap.containsKey(key);
035    }
036
037    @Override
038    public boolean containsValue(Object value) {
039        for (List<V> l : _internalMap.values()) {
040            if (l.contains(value)) {
041                return true;
042            }
043        }
044        return false;
045    }
046
047    @Override
048    public V get(Object key) {
049        throw new UnsupportedOperationException("Not supported");
050    }
051
052    /**
053     * Get all items in the map that has the key 'key'
054     * @param key the key whose associated values is to be returned
055     * @return an unmodifiable list of all the items
056     */
057    public List<V> getAll(K key) {
058        List<V> list = _internalMap.get(key);
059        if (list == null) list = new ArrayList<>();
060        return Collections.unmodifiableList(list);
061    }
062
063    /**
064     * {@inheritDoc}
065     * @return always null
066     */
067    @Override
068    public V put(K key, V value) {
069        List<V> l = _internalMap.get(key);
070        if (l == null) {
071            l = new ArrayList<>();
072            _internalMap.put(key, l);
073        }
074        if (! l.contains(value)) {
075            l.add(value);
076        }
077        return null;
078    }
079
080    @Override
081    public void putAll(Map<? extends K,? extends V> m) {
082        throw new UnsupportedOperationException("Not supported");
083    }
084
085    @Override
086    public V remove(Object key) {
087        throw new UnsupportedOperationException("Not supported");
088    }
089
090    /** {@inheritDoc} */
091    @Override
092    public boolean remove(Object key, Object value) {
093        // NetBeans complains about suspicious call to Map.get(), but
094        // JMRI Static analysis doesn't allow casting to (K)key
095        List<V> l = _internalMap.get(key);
096        if (l != null) {
097            if (l.remove(value)) {
098                if (l.isEmpty()) _internalMap.remove(key);
099                return true;
100            }
101        }
102        return false;
103    }
104
105    /**
106     * Remove a value.
107     * @param key the key
108     * @param value the value
109     */
110    public void removeValue(K key, V value) {
111        List<V> l = _internalMap.get(key);
112        if (l != null) {
113            l.remove(value);
114        }
115    }
116
117    @Override
118    public void clear() {
119        // Empty the lists since others may have indirect references to the list
120        // after calling the method getAll()
121        for (List<V> l : _internalMap.values()) {
122            l.clear();
123        }
124        _internalMap.clear();
125    }
126
127    @Override
128    public Set<K> keySet() {
129        return Collections.unmodifiableSet(_internalMap.keySet());
130    }
131
132    @Override
133    public Collection<V> values() {
134        List<V> list = new ArrayList<>();
135        for (List<V> l : _internalMap.values()) {
136            list.addAll(l);
137        }
138        return Collections.unmodifiableList(list);
139    }
140
141    @Override
142    public Set<Map.Entry<K,V>> entrySet() {
143        throw new UnsupportedOperationException("Not supported");
144    }
145
146}