001    package ezvcard.util;
002    
003    import java.util.ArrayList;
004    import java.util.Collection;
005    import java.util.LinkedHashMap;
006    import java.util.List;
007    import java.util.Map;
008    import java.util.Set;
009    
010    /*
011     Copyright (c) 2012, Michael Angstadt
012     All rights reserved.
013    
014     Redistribution and use in source and binary forms, with or without
015     modification, are permitted provided that the following conditions are met: 
016    
017     1. Redistributions of source code must retain the above copyright notice, this
018     list of conditions and the following disclaimer. 
019     2. Redistributions in binary form must reproduce the above copyright notice,
020     this list of conditions and the following disclaimer in the documentation
021     and/or other materials provided with the distribution. 
022    
023     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
024     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
025     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
026     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
027     ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
028     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
029     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
030     ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
031     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
032     SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
033    
034     The views and conclusions contained in the software and documentation are those
035     of the authors and should not be interpreted as representing official policies, 
036     either expressed or implied, of the FreeBSD Project.
037     */
038    
039    /**
040     * A multimap that uses {@link List} objects to store its values.
041     * 
042     * <p>
043     * The internal {@link Map} implementation is a {@link LinkedHashMap} that uses
044     * {@link ArrayList} for its values.
045     * </p>
046     * @author Michael Angstadt
047     * @param <K> the key
048     * @param <V> the value
049     */
050    public class ListMultimap<K, V> {
051            private final Map<K, List<V>> map = new LinkedHashMap<K, List<V>>();
052    
053            public ListMultimap() {
054            }
055    
056            /**
057             * Copy constructor.
058             * @param orig the multimap to copy from
059             */
060            public ListMultimap(ListMultimap<K, V> orig) {
061                    for (Map.Entry<K, List<V>> entry : orig.map.entrySet()) {
062                            List<V> values = new ArrayList<V>(entry.getValue());
063                            map.put(entry.getKey(), values);
064                    }
065            }
066    
067            /**
068             * Adds a value to the multimap.
069             * @param key the key
070             * @param value the value
071             */
072            public void put(K key, V value) {
073                    List<V> values = map.get(key);
074                    if (values == null) {
075                            values = new ArrayList<V>();
076                            map.put(key, values);
077                    }
078                    values.add(value);
079            }
080    
081            /**
082             * Gets the values associated with the key.
083             * @param key the key
084             * @return the list of values or empty list if the key doesn't exist
085             */
086            public List<V> get(K key) {
087                    List<V> values = map.get(key);
088                    if (values == null) {
089                            values = new ArrayList<V>();
090                    }
091                    return values;
092            }
093    
094            /**
095             * Removes all the values associated with a key
096             * @param key the key to remove
097             * @return the removed values
098             */
099            public List<V> remove(K key) {
100                    return map.remove(key);
101            }
102    
103            /**
104             * Removes a particular value.
105             * @param key the key
106             * @param value the value to remove
107             * @return true if the multimap contained the value, false if not
108             */
109            public boolean remove(K key, V value) {
110                    List<V> values = map.get(key);
111                    if (values != null) {
112                            return values.remove(value);
113                    }
114                    return false;
115            }
116    
117            /**
118             * Returns all the keys.
119             * @return all the keys
120             */
121            public Set<K> keySet() {
122                    return map.keySet();
123            }
124    
125            /**
126             * Returns all the values.
127             * @return all the values
128             */
129            public Collection<V> values() {
130                    Collection<V> list = new ArrayList<V>();
131                    for (List<V> value : map.values()) {
132                            list.addAll(value);
133                    }
134                    return list;
135            }
136    
137            /**
138             * Determines if the multimap is empty or not.
139             * @return true if it's empty, false if not
140             */
141            public boolean isEmpty() {
142                    return size() == 0;
143            }
144    
145            /**
146             * Returns the number of values in the map.
147             * @return the number of values
148             */
149            public int size() {
150                    int size = 0;
151                    for (List<V> value : map.values()) {
152                            size += value.size();
153                    }
154                    return size;
155            }
156    
157            /**
158             * Gets the underlying {@link Map} object.
159             * @return the underlying {@link Map} object
160             */
161            public Map<K, List<V>> getMap() {
162                    return map;
163            }
164    }