moved to: https://sites.google.com/site/cmzmasek/home/software/forester
[jalview.git] / forester / java / src / org / forester / phylogeny / data / Sequence.java
1 // $Id:
2 // FORESTER -- software libraries and applications
3 // for evolutionary biology research and applications.
4 //
5 // Copyright (C) 2008-2009 Christian M. Zmasek
6 // Copyright (C) 2008-2009 Burnham Institute for Medical Research
7 // All rights reserved
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 //
23 // Contact: phylosoft @ gmail . com
24 // WWW: https://sites.google.com/site/cmzmasek/home/software/forester
25
26 package org.forester.phylogeny.data;
27
28 import java.io.IOException;
29 import java.io.Writer;
30 import java.util.ArrayList;
31 import java.util.List;
32 import java.util.SortedSet;
33 import java.util.TreeSet;
34
35 import org.forester.io.parsers.nhx.NHXtags;
36 import org.forester.io.parsers.phyloxml.PhyloXmlDataFormatException;
37 import org.forester.io.parsers.phyloxml.PhyloXmlMapping;
38 import org.forester.io.parsers.phyloxml.PhyloXmlUtil;
39 import org.forester.io.writers.PhylogenyWriter;
40 import org.forester.util.ForesterUtil;
41
42 public class Sequence implements PhylogenyData, MultipleUris {
43
44     private String                 _mol_sequence;
45     private boolean                _mol_sequence_is_aligned;
46     private String                 _name;
47     private String                 _source_id;
48     private Accession              _accession;
49     private String                 _symbol;
50     private String                 _location;
51     private String                 _type;
52     private SortedSet<Annotation>  _annotations;
53     private DomainArchitecture     _da;
54     private List<Uri>              _uris;
55     private List<SequenceRelation> _seq_relations;
56
57     public Sequence() {
58         init();
59     }
60
61     public boolean isEmpty() {
62         return ( getAccession() == null ) && ForesterUtil.isEmpty( getName() ) && ForesterUtil.isEmpty( getSymbol() )
63                 && ForesterUtil.isEmpty( getType() ) && ForesterUtil.isEmpty( getLocation() )
64                 && ForesterUtil.isEmpty( getSourceId() ) && ForesterUtil.isEmpty( getMolecularSequence() )
65                 && ( getDomainArchitecture() == null ) && ForesterUtil.isEmpty( _annotations )
66                 && ForesterUtil.isEmpty( _uris ) && ForesterUtil.isEmpty( _seq_relations );
67     }
68
69     public void addAnnotation( final Annotation annotation ) {
70         getAnnotations().add( annotation );
71     }
72
73     @Override
74     public void addUri( final Uri uri ) {
75         if ( getUris() == null ) {
76             setUris( new ArrayList<Uri>() );
77         }
78         getUris().add( uri );
79     }
80
81     public void addSequenceRelation( final SequenceRelation sr ) {
82         _seq_relations.add( sr );
83     }
84
85     @Override
86     public StringBuffer asSimpleText() {
87         final StringBuffer sb = new StringBuffer();
88         if ( getAccession() != null ) {
89             sb.append( "[" );
90             sb.append( getAccession() );
91             sb.append( "] " );
92         }
93         if ( !ForesterUtil.isEmpty( getName() ) ) {
94             sb.append( getName() );
95             sb.append( " " );
96         }
97         if ( !ForesterUtil.isEmpty( getLocation() ) ) {
98             sb.append( getLocation() );
99         }
100         return sb;
101     }
102
103     @Override
104     public StringBuffer asText() {
105         return asSimpleText();
106     }
107
108     /**
109      * Not a deep copy.
110      * 
111      */
112     @Override
113     public PhylogenyData copy() {
114         final Sequence seq = new Sequence();
115         seq.setAnnotations( getAnnotations() );
116         seq.setName( getName() );
117         try {
118             seq.setSymbol( getSymbol() );
119         }
120         catch ( final PhyloXmlDataFormatException e ) {
121             e.printStackTrace();
122         }
123         seq.setMolecularSequence( getMolecularSequence() );
124         seq.setMolecularSequenceAligned( isMolecularSequenceAligned() );
125         seq.setLocation( getLocation() );
126         if ( getAccession() != null ) {
127             seq.setAccession( ( Accession ) getAccession().copy() );
128         }
129         else {
130             seq.setAccession( null );
131         }
132         try {
133             seq.setType( getType() );
134         }
135         catch ( final PhyloXmlDataFormatException e ) {
136             e.printStackTrace();
137         }
138         if ( getUris() != null ) {
139             seq.setUris( new ArrayList<Uri>() );
140             for( final Uri uri : getUris() ) {
141                 if ( uri != null ) {
142                     seq.getUris().add( uri );
143                 }
144             }
145         }
146         if ( getDomainArchitecture() != null ) {
147             seq.setDomainArchitecture( ( DomainArchitecture ) getDomainArchitecture().copy() );
148         }
149         else {
150             seq.setDomainArchitecture( null );
151         }
152         return seq;
153     }
154
155     @Override
156     public boolean equals( final Object o ) {
157         if ( this == o ) {
158             return true;
159         }
160         else if ( o == null ) {
161             return false;
162         }
163         else if ( o.getClass() != this.getClass() ) {
164             throw new IllegalArgumentException( "attempt to check [" + this.getClass() + "] equality to " + o + " ["
165                     + o.getClass() + "]" );
166         }
167         else {
168             return isEqual( ( Sequence ) o );
169         }
170     }
171
172     public Accession getAccession() {
173         return _accession;
174     }
175
176     public Annotation getAnnotation( final int i ) {
177         return ( Annotation ) getAnnotations().toArray()[ i ];
178     }
179
180     public SortedSet<Annotation> getAnnotations() {
181         if ( _annotations == null ) {
182             _annotations = new TreeSet<Annotation>();
183         }
184         return _annotations;
185     }
186
187     public DomainArchitecture getDomainArchitecture() {
188         return _da;
189     }
190
191     public String getLocation() {
192         return _location;
193     }
194
195     public String getMolecularSequence() {
196         return _mol_sequence;
197     }
198
199     public boolean isMolecularSequenceAligned() {
200         return _mol_sequence_is_aligned;
201     }
202
203     public String getName() {
204         return _name;
205     }
206
207     public List<SequenceRelation> getSequenceRelations() {
208         if ( _seq_relations == null ) {
209             _seq_relations = new ArrayList<SequenceRelation>();
210         }
211         return _seq_relations;
212     }
213
214     private void setSequenceRelations( final List<SequenceRelation> seq_relations ) {
215         _seq_relations = seq_relations;
216     }
217
218     public String getSourceId() {
219         return _source_id;
220     }
221
222     public String getSymbol() {
223         return _symbol;
224     }
225
226     public String getType() {
227         return _type;
228     }
229
230     @Override
231     public List<Uri> getUris() {
232         return _uris;
233     }
234
235     @Override
236     public Uri getUri( final int index ) {
237         return getUris().get( index );
238     }
239
240     @Override
241     public int hashCode() {
242         if ( getAccession() != null ) {
243             return getAccession().hashCode();
244         }
245         int result = getSymbol().hashCode();
246         if ( getName().length() > 0 ) {
247             result ^= getName().hashCode();
248         }
249         if ( getMolecularSequence().length() > 0 ) {
250             result ^= getMolecularSequence().hashCode();
251         }
252         return result;
253     }
254
255     public boolean hasSequenceRelations() {
256         return _seq_relations.size() > 0;
257     }
258
259     public void init() {
260         setAnnotations( null );
261         setName( "" );
262         setMolecularSequence( "" );
263         setMolecularSequenceAligned( false );
264         setLocation( "" );
265         setAccession( null );
266         try {
267             setSymbol( "" );
268         }
269         catch ( final PhyloXmlDataFormatException e ) {
270             e.printStackTrace();
271         }
272         try {
273             setType( "" );
274         }
275         catch ( final PhyloXmlDataFormatException e ) {
276             e.printStackTrace();
277         }
278         setDomainArchitecture( null );
279         setUris( null );
280         setSequenceRelations( null );
281         setSourceId( null );
282     }
283
284     @Override
285     public boolean isEqual( final PhylogenyData data ) {
286         if ( this == data ) {
287             return true;
288         }
289         final Sequence s = ( Sequence ) data;
290         if ( ( getAccession() != null ) && ( s.getAccession() != null ) ) {
291             return getAccession().isEqual( s.getAccession() );
292         }
293         return s.getMolecularSequence().equals( getMolecularSequence() ) && s.getName().equals( getName() )
294                 && s.getSymbol().equals( getSymbol() );
295     }
296
297     public void setAccession( final Accession accession ) {
298         _accession = accession;
299     }
300
301     private void setAnnotations( final SortedSet<Annotation> annotations ) {
302         _annotations = annotations;
303     }
304
305     public void setDomainArchitecture( final DomainArchitecture ds ) {
306         _da = ds;
307     }
308
309     public void setLocation( final String description ) {
310         _location = description;
311     }
312
313     public void setMolecularSequence( final String mol_sequence ) {
314         _mol_sequence = mol_sequence;
315     }
316
317     public void setMolecularSequenceAligned( final boolean aligned ) {
318         _mol_sequence_is_aligned = aligned;
319     }
320
321     public void setName( final String name ) {
322         _name = name;
323     }
324
325     public void setSourceId( final String source_id ) {
326         _source_id = source_id;
327     }
328
329     public void setSymbol( final String symbol ) throws PhyloXmlDataFormatException {
330         if ( !ForesterUtil.isEmpty( symbol ) && !PhyloXmlUtil.SEQUENCE_SYMBOL_PATTERN.matcher( symbol ).matches() ) {
331             throw new PhyloXmlDataFormatException( "illegal sequence symbol: [" + symbol + "]" );
332         }
333         _symbol = symbol;
334     }
335
336     public void setType( final String type ) throws PhyloXmlDataFormatException {
337         if ( !ForesterUtil.isEmpty( type ) && !PhyloXmlUtil.SEQUENCE_TYPES.contains( type ) ) {
338             throw new PhyloXmlDataFormatException( "illegal sequence type: [" + type + "]" );
339         }
340         _type = type;
341     }
342
343     @Override
344     public void setUris( final List<Uri> uris ) {
345         _uris = uris;
346     }
347
348     @Override
349     public StringBuffer toNHX() {
350         final StringBuffer sb = new StringBuffer();
351         if ( getName().length() > 0 ) {
352             sb.append( ":" );
353             sb.append( NHXtags.GENE_NAME );
354             sb.append( ForesterUtil.replaceIllegalNhxCharacters( getName() ) );
355         }
356         if ( getAccession() != null ) {
357             getAccession().toNHX();
358         }
359         if ( getDomainArchitecture() != null ) {
360             sb.append( getDomainArchitecture().toNHX() );
361         }
362         return sb;
363     }
364
365     @Override
366     public void toPhyloXML( final Writer writer, final int level, final String indentation ) throws IOException {
367         if ( isEmpty() ) {
368             return;
369         }
370         final String my_ind = indentation + PhylogenyWriter.PHYLO_XML_INTENDATION_BASE;
371         writer.write( ForesterUtil.LINE_SEPARATOR );
372         writer.write( indentation );
373         PhylogenyDataUtil.appendOpen( writer, PhyloXmlMapping.SEQUENCE, PhyloXmlMapping.SEQUENCE_TYPE, getType() );
374         if ( !ForesterUtil.isEmpty( getSymbol() ) ) {
375             PhylogenyDataUtil.appendElement( writer, PhyloXmlMapping.SEQUENCE_SYMBOL, getSymbol(), indentation );
376         }
377         if ( ( getAccession() != null ) && !ForesterUtil.isEmpty( getAccession().getValue() ) ) {
378             getAccession().toPhyloXML( writer, level, indentation );
379         }
380         if ( !ForesterUtil.isEmpty( getName() ) ) {
381             PhylogenyDataUtil.appendElement( writer, PhyloXmlMapping.SEQUENCE_NAME, getName(), indentation );
382         }
383         if ( !ForesterUtil.isEmpty( getLocation() ) ) {
384             PhylogenyDataUtil.appendElement( writer, PhyloXmlMapping.SEQUENCE_LOCATION, getLocation(), indentation );
385         }
386         if ( !ForesterUtil.isEmpty( getMolecularSequence() ) ) {
387             PhylogenyDataUtil.appendElement( writer,
388                                              PhyloXmlMapping.SEQUENCE_MOL_SEQ,
389                                              getMolecularSequence(),
390                                              PhyloXmlMapping.SEQUENCE_MOL_SEQ_ALIGNED_ATTR,
391                                              String.valueOf( isMolecularSequenceAligned() ),
392                                              indentation );
393         }
394         if ( getUris() != null ) {
395             for( final Uri uri : getUris() ) {
396                 if ( uri != null ) {
397                     uri.toPhyloXML( writer, level, indentation );
398                 }
399             }
400         }
401         if ( _annotations != null ) {
402             for( final PhylogenyData annotation : getAnnotations() ) {
403                 annotation.toPhyloXML( writer, level, my_ind );
404             }
405         }
406         if ( getDomainArchitecture() != null ) {
407             getDomainArchitecture().toPhyloXML( writer, level, my_ind );
408         }
409         writer.write( ForesterUtil.LINE_SEPARATOR );
410         writer.write( indentation );
411         PhylogenyDataUtil.appendClose( writer, PhyloXmlMapping.SEQUENCE );
412     }
413
414     @Override
415     public String toString() {
416         return asText().toString();
417     }
418 }