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.seq.impl;
023
024import java.util.Iterator;
025
026import org.biojava.bio.Annotation;
027import org.biojava.bio.BioException;
028import org.biojava.bio.seq.Feature;
029import org.biojava.bio.seq.FeatureFilter;
030import org.biojava.bio.seq.FeatureHolder;
031import org.biojava.bio.seq.GappedSequence;
032import org.biojava.bio.seq.MergeFeatureHolder;
033import org.biojava.bio.seq.Sequence;
034import org.biojava.bio.seq.SimpleFeatureHolder;
035import org.biojava.bio.seq.projection.ProjectedFeatureHolder;
036import org.biojava.bio.seq.projection.ReparentContext;
037import org.biojava.bio.symbol.Alphabet;
038import org.biojava.bio.symbol.Location;
039import org.biojava.bio.symbol.SimpleGappedSymbolList;
040import org.biojava.utils.AssertionFailure;
041import org.biojava.utils.ChangeVetoException;
042
043/**
044 * Simple implementation of GappedSequence. Please note that this is a view onto
045 * another Sequence. Gaps created and removed are only in the view not the
046 * underlying original. This means that any gaps present in the original cannot
047 * be manipulated in this view. To manipulate the original you would need to use
048 * Edit objects.
049 * 
050 * @author Thomas Down
051 * @author Matthew Pocock
052 * @since 1.3
053 */
054
055public class SimpleGappedSequence extends SimpleGappedSymbolList implements
056                GappedSequence {
057        /**
058         * Generated Serial Verion ID.
059         */
060        private static final long serialVersionUID = -791305118810523245L;
061
062        private Sequence sequence;
063
064        private MergeFeatureHolder features;
065        private SimpleFeatureHolder localFeatures;
066        private FeatureHolder projectedFeatures;
067
068        private boolean createOnUnderlying;
069
070        public SimpleGappedSequence(Alphabet alpha) {
071                super(alpha);
072        }
073        
074        public SimpleGappedSequence(Sequence seq) {
075                super(seq);
076                this.sequence = seq;
077                createOnUnderlying = false;
078        }
079
080        public SimpleGappedSequence(GappedSequence seq) {
081                super(seq);
082                this.sequence = seq;
083                createOnUnderlying = false;
084        }
085
086        public boolean getCreateOnUnderlyingSequence() {
087                return createOnUnderlying;
088        }
089
090        public void setCreateOnUnderlyingSequence(boolean underlying) {
091                this.createOnUnderlying = underlying;
092        }
093
094        public Annotation getAnnotation() {
095                return sequence.getAnnotation();
096        }
097
098        public String getName() {
099                return sequence.getName();
100        }
101
102        public String getURN() {
103                return sequence.getURN();
104        }
105
106        private FeatureHolder getFeatures() {
107                if (features == null) {
108                        features = makeFeatures();
109                }
110                return features;
111        }
112
113        private MergeFeatureHolder makeFeatures() {
114                projectedFeatures = new ProjectedFeatureHolder(new GappedContext());
115
116                localFeatures = new SimpleFeatureHolder();
117
118                features = new MergeFeatureHolder();
119
120                try {
121                        features.addFeatureHolder(projectedFeatures);
122                        features.addFeatureHolder(localFeatures);
123                } catch (ChangeVetoException cve) {
124                        throw new AssertionFailure(
125                                        "Assertion Failure: Should be able to do this", cve);
126                }
127
128                return features;
129        }
130
131        public Iterator<Feature> features() {
132                return getFeatures().features();
133        }
134
135        public FeatureHolder filter(FeatureFilter ff) {
136                return getFeatures().filter(ff);
137        }
138
139        public FeatureHolder filter(FeatureFilter ff, boolean recurse) {
140                return getFeatures().filter(ff, recurse);
141        }
142
143        public int countFeatures() {
144                return getFeatures().countFeatures();
145        }
146
147        public boolean containsFeature(Feature f) {
148                return getFeatures().containsFeature(f);
149        }
150
151        public FeatureFilter getSchema() {
152                return getFeatures().getSchema();
153        }
154
155        public void removeFeature(Feature f) throws ChangeVetoException,
156                        BioException {
157                getFeatures();
158                if (localFeatures.containsFeature(f)) {
159                        localFeatures.removeFeature(f);
160                } else {
161                        projectedFeatures.removeFeature(f);
162                }
163        }
164
165        public Feature createFeature(Feature.Template templ)
166                        throws ChangeVetoException, BioException {
167                getFeatures();
168                if (createOnUnderlying) {
169                        return projectedFeatures.createFeature(templ);
170                } else {
171                        Feature f = FeatureImpl.DEFAULT.realizeFeature(this, this, templ);
172                        localFeatures.addFeature(f);
173                        return f;
174                }
175        }
176
177        public class GappedContext extends ReparentContext {
178                /**
179                 * Generated Serial Version ID.
180                 */
181                private static final long serialVersionUID = 8878073952684354286L;
182
183                public GappedContext() {
184                        super(SimpleGappedSequence.this, sequence);
185                }
186
187                public Location projectLocation(Location loc) {
188                        return loc.newInstance(locationToGapped(loc));
189                }
190
191                public Location mapLocation(Location loc) {
192                        return loc.newInstance(locationToGapped(loc));
193                }
194
195                public Location revertLocation(Location oldLoc) {
196                        return gappedToLocation(oldLoc);
197                }
198        }
199}