001    /* JAPI - (Yet anothr (hopefully) useful) Java API
002     *
003     * Copyright (C) 2004-2006 Christian Hujer
004     *
005     * This program is free software; you can redistribute it and/or
006     * modify it under the terms of the GNU General Public License as
007     * published by the Free Software Foundation; either version 2 of the
008     * License, or (at your option) any later version.
009     *
010     * This program is distributed in the hope that it will be useful, but
011     * WITHOUT ANY WARRANTY; without even the implied warranty of
012     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013     * General Public License for more details.
014     *
015     * You should have received a copy of the GNU General Public License
016     * along with this program; if not, write to the Free Software
017     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
018     * 02111-1307, USA.
019     */
020    
021    package net.sf.japi.util;
022    
023    import java.util.Collection;
024    import java.util.HashSet;
025    import java.util.Iterator;
026    import java.util.Set;
027    
028    /** A special Collection class that is like a Map but which allows duplicate keys.
029     * Only duplicate key/value pairs aren't allowed.
030     * The key therefor is named first, the value second.
031     * Uniqueness is gained with Key/Value pairs.
032     * @author <a href="mailto:Christian.Hujer@itcqis.com">Christian Hujer</a>
033     */
034    @SuppressWarnings({"BooleanMethodNameMustStartWithQuestion"})
035    public class Table<T1,T2> {
036    
037        /** The pairs of the table. */
038        private Set<Pair<T1,T2>> pairs = new HashSet<Pair<T1,T2>>();
039    
040        /** Create a table. */
041        public Table() {
042        }
043    
044        /** Completely Clear the table. */
045        public void clear() {
046            pairs.clear();
047        }
048    
049        /** Get all firsts that match the second.
050         * @param second second to match
051         * @return all firsts that match second
052         */
053        public Collection<T1> getFirstsBySecond(final T2 second) {
054            final Set<T1> firsts = new HashSet<T1>();
055            for (final Pair<T1, T2> pair : pairs) {
056                final T2 pairSecond = pair.getSecond();
057                if (pairSecond == second || pairSecond.equals(second)) {
058                    firsts.add(pair.getFirst());
059                }
060            }
061            return firsts;
062        }
063    
064        /** Get all pairs that match the first.
065         * @param first first to match
066         * @return all pairs that match first
067         */
068        public Collection<Pair<T1,T2>> getPairsByFirst(final T1 first) {
069            final Set<Pair<T1,T2>> pairsByFirst = new HashSet<Pair<T1,T2>>();
070            for (Pair<T1, T2> pair : pairs) {
071                final T1 pairFirst = pair.getFirst();
072                if (pairFirst == first || pairFirst.equals(first)) {
073                    pairsByFirst.add(pair);
074                }
075            }
076            return pairsByFirst;
077        }
078    
079        /** Get all pairs that match the second.
080         * @param second second to match
081         * @return all pairs that match second
082         */
083        public Collection<Pair<T1,T2>> getPairsBySecond(final T2 second) {
084            final Set<Pair<T1,T2>> pairsBySecond = new HashSet<Pair<T1,T2>>();
085            for (Pair<T1, T2> pair : pairs) {
086                final T2 pairSecond = pair.getSecond();
087                if (pairSecond == second || pairSecond.equals(second)) {
088                    pairsBySecond.add(pair);
089                }
090            }
091            return pairsBySecond;
092        }
093    
094        /** Get all seconds that match the first.
095         * @param first first to match
096         * @return all seconds that match first
097         */
098        public Collection<T2> getSecondsByFirst(final T1 first) {
099            final Set<T2> seconds = new HashSet<T2>();
100            for (final Pair<T1, T2> pair : pairs) {
101                final T1 pairFirst = pair.getFirst();
102                if (pairFirst == first || pairFirst.equals(first)) {
103                    seconds.add(pair.getSecond());
104                }
105            }
106            return seconds;
107        }
108    
109        /** Put a pair into the table.
110         * @param pair pair to put into the table
111         * @return <code>true</code> if the table did not already contain that <var>pair</var>, otherwise <code>false</code>
112         */
113        public boolean putPair(final Pair<T1,T2> pair) {
114            return pairs.add(pair);
115        }
116    
117        /** Put a pair into the table.
118         * @param t1 first of pair
119         * @param t2 second of pair
120         * @return <code>true</code> if the table did not already contain that <var>pair</var>, otherwise <code>false</code>
121         */
122        public boolean putPair(final T1 t1, final T2 t2) {
123            return pairs.add(new Pair<T1,T2>(t1, t2));
124        }
125    
126        /** Remove all pairs that match a first.
127         * @param first first to match
128         */
129        public void removeAllFirst(final T1 first) {
130            for (final Iterator<Pair<T1,T2>> it = pairs.iterator(); it.hasNext();) {
131                final Pair<T1,T2> pair = it.next();
132                final T1 pairFirst = pair.getFirst();
133                if (pairFirst == first || pairFirst.equals(first)) {
134                    it.remove();
135                }
136            }
137        }
138    
139        /** Remove all pairs that match a second.
140         * @param second second to match
141         */
142        public void removeAllSecond(final T2 second) {
143            for (final Iterator<Pair<T1,T2>> it = pairs.iterator(); it.hasNext();) {
144                final Pair<T1,T2> pair = it.next();
145                final T2 pairSecond = pair.getSecond();
146                if (pairSecond == second || pairSecond.equals(second)) {
147                    it.remove();
148                }
149            }
150        }
151    
152        /** Remove a pair from the table.
153         * @param pair pair to remove
154         * @return <code>true</code> if the table contained the <var>pair</var>, thus the <var>pair</var> was successfully removed, otherwise <code>false</code>
155         */
156        public boolean removePair(final Pair<T1,T2> pair) {
157            return pairs.remove(pair);
158        }
159    
160        /** Remove a pair into the table.
161         * @param t1 first of pair
162         * @param t2 second of pair
163         * @return <code>true</code> if the table did not already contain that <var>pair</var>, otherwise <code>false</code>
164         */
165        public boolean removePair(final T1 t1, final T2 t2) {
166            return pairs.remove(new Pair<T1,T2>(t1, t2));
167        }
168    
169        /** Get the size of the table.
170         * @return size of the table
171         */
172        public int size() {
173            return pairs.size();
174        }
175    
176    } // class Table