001/*
002 *                    BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 */
021
022package org.biojava.bio;
023
024import java.util.AbstractMap;
025import java.util.AbstractSet;
026import java.util.Iterator;
027import java.util.Map;
028import java.util.Set;
029
030import org.biojava.bio.program.tagvalue.PropertyChanger;
031
032/**
033 * <code>AnnotationRenamer</code> remaps the keys of an
034 * <code>Annotation</code> to new keys specified by a
035 * <code>TagMapper</code>. This will rename properties, but not alter their
036 * values.
037 * For writing light-weigth adaptors to project one type of
038 * Annotation to another using a TagMapper.
039 * @since 1.3
040 * @author Matthew Pocock
041 * @author <a href="mailto:kdj@sanger.ac.uk">Keith James</a> (docs)
042 *
043 */
044public class AnnotationRenamer extends AbstractAnnotation
045{
046    private final Annotation wrapped;
047    private final PropertyChanger mapper;
048    private final Map properties;
049  
050    /**
051     * Creates a new <code>AnnotationRenamer</code> using the
052     * specified <code>TagMapper</code> to remap its keys.
053     *
054     * @param wrapped an <code>Annotation</code>.
055     * @param mapper a <code>TagMapper</code>.
056     */
057    public AnnotationRenamer(Annotation wrapped, PropertyChanger mapper) {
058        this.wrapped = wrapped;
059        this.mapper = mapper;
060        this.properties = new MappedHash();
061    }
062
063    /**
064     * <code>getWrapped</code> returns the <code>Annotation</code>
065     * being remapped.
066     *
067     * @return an <code>Annotation</code>.
068     */
069    public Annotation getWrapped() {
070        return wrapped;
071    }
072
073    /**
074     * <code>getMapper</code> returns the <code>TagMapper</code> being
075     * used to remap the <code>Annotation</code>.
076     *
077     * @return a <code>TagMapper</code>.
078     */
079    public PropertyChanger getMapper() {
080        return mapper;
081    }
082
083    /**
084     * <code>getProperties</code> returns the mapped contents of the
085     * underlying <code>Annotation</code> as a <code>Map</code>.
086     *
087     * @return a <code>Map</code>.
088     */
089    public Map getProperties() {
090        return properties;
091    }
092
093    /**
094     * <code>propertiesAllocated</code> Javadoc FIXME - this overrides
095     * a protected method and I'm not sure why (KJ).
096     *
097     * @return a <code>boolean</code>.
098     */
099    public boolean propertiesAllocated() {
100        return true;
101    }
102
103    private class MappedHash extends AbstractMap {
104        public int size() {
105            return wrapped.asMap().size();
106        }
107
108        public Set entrySet() {
109            return new WrappedSet(wrapped.asMap().entrySet());
110        }
111    }
112
113    private class WrappedSet extends AbstractSet {
114        private Set entrySet;
115
116        public WrappedSet(Set entrySet) {
117            this.entrySet = entrySet;
118        }
119
120        public int size() {
121            return entrySet.size();
122        }
123
124        public Iterator iterator() {
125            return new Iterator() {
126                    Iterator i = entrySet.iterator();
127
128                    public boolean hasNext() {
129                        return i.hasNext();
130                    }
131
132                    public Object next() {
133                        final Map.Entry entry = (Map.Entry) i.next();
134
135                        return new Map.Entry() {
136                                public Object getKey() {
137                                    return mapper.getNewTag(entry.getKey());
138                                }
139
140                                public Object getValue() {
141                                    return entry.getValue();
142                                }
143
144                                public Object setValue(Object value) {
145                                    return entry.setValue(value);
146                                }
147                            };
148                    }
149        
150                    public void remove() {
151                        i.remove();
152                    }
153                };
154        }
155    }
156}