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;
023
024import java.util.Iterator;
025import java.util.List;
026
027import org.biojava.bio.Annotatable;
028import org.biojava.bio.Annotation;
029import org.biojava.bio.BioException;
030import org.biojava.bio.SimpleAnnotation;
031import org.biojava.bio.seq.impl.NewAssembledSymbolList;
032import org.biojava.bio.symbol.Alphabet;
033import org.biojava.bio.symbol.Edit;
034import org.biojava.bio.symbol.IllegalAlphabetException;
035import org.biojava.bio.symbol.Location;
036import org.biojava.bio.symbol.Symbol;
037import org.biojava.bio.symbol.SymbolList;
038import org.biojava.utils.AbstractChangeable;
039import org.biojava.utils.ChangeForwarder;
040import org.biojava.utils.ChangeSupport;
041import org.biojava.utils.ChangeType;
042import org.biojava.utils.ChangeVetoException;
043
044/**
045 * A Sequence which is assembled from other sequences contained
046 * in a set of ComponentFeature objects.
047 * <p>
048 * The class has been extended to handle overlapping
049 * component sequences.  It is assumed that the overlaps
050 * are consistent between components: this will not be checked.
051 * <p>
052 * There is still some potential for optimising SymbolList
053 * operations on this class.
054 * </p>
055 *
056 * @author Thomas Down
057 * @author Matthew Pocock
058 * @author David Huen
059 * @since 1.1
060 */
061
062public class NewSimpleAssembly
063  extends
064    AbstractChangeable
065  implements
066    Sequence,
067    RealizingFeatureHolder
068{
069    private String name;
070    private String uri;
071    private Annotation annotation = new SimpleAnnotation();
072    private SimpleFeatureHolder features;
073    private NewAssembledSymbolList assembly;
074
075    private FeatureRealizer featureRealizer = org.biojava.bio.seq.impl.FeatureImpl.DEFAULT;
076    protected transient ChangeForwarder annotationForwarder;
077
078    {
079        assembly = new NewAssembledSymbolList();
080        features = new SimpleFeatureHolder();
081    }
082
083    /**
084     * Construct a new SimpleAssembly using the DNA alphabet.
085     * Initially, the sequence will just contain a list of `N's.
086     * Sequence data can be added by adding one or more
087     * ComponentFeatures.
088     *
089     * @param length The length of the sequence
090     * @param name The name of the sequence (returned by getName())
091     * @param uri The identifier of the sequence (returned by getURN());
092     */
093
094    public NewSimpleAssembly(int length, String name, String uri) {
095        this.name = name;
096        this.uri = uri;
097        assembly.setLength(length);
098    }
099
100    /**
101     * Construct a new NewSimpleAssembly using the DNA alphabet.
102     * Initially, the sequence will just contain a list of `N's.
103     * Sequence data can be added by adding one or more
104     * ComponentFeatures.
105     *
106     * @param name The name of the sequence (returned by getName())
107     * @param uri The identifier of the sequence (returned by getURN());
108     */
109
110    public NewSimpleAssembly(String name, String uri) {
111        this.name = name;
112        this.uri = uri;
113    }
114
115    //
116    // SymbolList
117    //
118
119    public Alphabet getAlphabet() {
120        return assembly.getAlphabet();
121    }
122
123    public int length() {
124        return assembly.length();
125    }
126
127    public Symbol symbolAt(int pos) {
128        return assembly.symbolAt(pos);
129    }
130
131    public SymbolList subList(int start, int end) {
132        return assembly.subList(start, end);
133    }
134
135    public String seqString() {
136        return assembly.seqString();
137    }
138
139    public String subStr(int start, int end) {
140        return assembly.subStr(start, end);
141    }
142
143    public Iterator iterator() {
144        return assembly.iterator();
145    }
146
147    public List toList() {
148        return assembly.toList();
149    }
150
151    public void edit(Edit e)
152        throws IllegalAlphabetException, ChangeVetoException
153    {
154        assembly.edit(e);
155    }
156
157    //
158    // Sequence identification
159    //
160
161    public String getName() {
162        return name;
163    }
164
165    public String getURN() {
166        return uri;
167    }
168
169    //
170    // Annotatable
171    //
172
173    public Annotation getAnnotation() {
174        return annotation;
175    }
176
177    //
178    // FeatureHolder
179    //
180
181    public Iterator features() {
182        return features.features();
183    }
184
185    public int countFeatures() {
186        return features.countFeatures();
187    }
188
189    public FeatureHolder filter(FeatureFilter ff, boolean recurse) {
190            return features.filter(ff, recurse);
191    }
192
193    public FeatureHolder filter(FeatureFilter ff) {
194            return features.filter(ff);
195    }
196
197    public boolean containsFeature(Feature f) {
198      return features.containsFeature(f);
199    }
200
201    public Feature createFeature(Feature.Template temp)
202        throws BioException, ChangeVetoException
203    {
204        if (temp.location.getMin() < 1)
205            throw new BioException("Coordinates out of range");
206
207        Feature f = realizeFeature(this, temp);
208        features.addFeature(f);
209        if (f instanceof ComponentFeature) {
210            ComponentFeature cf = (ComponentFeature) f;
211            Location loc = cf.getLocation();
212            if (loc.getMax() > assembly.length()) {
213                assembly.setLength(loc.getMax());
214            }
215            assembly.putComponent(cf);
216//            System.out.println(assembly.getComponentLocationSet());
217        }
218        return f;
219    }
220
221
222    public void removeFeature(Feature f)
223    throws ChangeVetoException {
224      if (f instanceof ComponentFeature) {
225        assembly.removeComponent((ComponentFeature) f);
226      }
227      features.removeFeature(f);
228    }
229
230    //
231    // Feature realization
232    //
233
234    public Feature realizeFeature(FeatureHolder fh, Feature.Template temp)
235        throws BioException
236    {
237        if (temp instanceof ComponentFeature.Template) {
238            if (fh != this) {
239                throw new BioException("ComponentFeatures can only be attached directly to SimpleAssembly objects");
240            }
241            ComponentFeature.Template cft = (ComponentFeature.Template) temp;
242            return new SimpleComponentFeature(this, cft);
243        } else {
244            FeatureHolder gopher = fh;
245            while (gopher instanceof Feature) {
246                if (gopher instanceof ComponentFeature) {
247                    throw new BioException("Cannot [currently] realize features on components of SimpleAssemblies");
248                }
249                gopher = ((Feature) gopher).getParent();
250            }
251            return featureRealizer.realizeFeature(this, fh, temp);
252        }
253    }
254
255    protected ChangeSupport getChangeSupport(ChangeType ct){
256      ChangeSupport cs = super.getChangeSupport(ct);
257
258      if(annotationForwarder == null &&
259        (ct == null || ct == Annotatable.ANNOTATION)){
260        annotationForwarder =
261                new ChangeForwarder.Retyper(this, cs, Annotation.PROPERTY);
262        getAnnotation().addChangeListener(
263            annotationForwarder,
264            Annotatable.ANNOTATION);
265      }
266      return cs;
267    }
268
269    public FeatureFilter getSchema() {
270        return FeatureFilter.top_level;
271    }
272}