27b3b0c4c2dcfd4fddf2e1fc2ce866de0604e3ef
[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: www.phylosoft.org/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     public void addUri( final Uri uri ) {
74         if ( getUris() == null ) {
75             setUris( new ArrayList<Uri>() );
76         }
77         getUris().add( uri );
78     }
79
80     public void addSequenceRelation( final SequenceRelation sr ) {
81         _seq_relations.add( sr );
82     }
83
84     public StringBuffer asSimpleText() {
85         final StringBuffer sb = new StringBuffer();
86         if ( getAccession() != null ) {
87             sb.append( "[" );
88             sb.append( getAccession() );
89             sb.append( "] " );
90         }
91         if ( !ForesterUtil.isEmpty( getName() ) ) {
92             sb.append( getName() );
93             sb.append( " " );
94         }
95         if ( !ForesterUtil.isEmpty( getLocation() ) ) {
96             sb.append( getLocation() );
97         }
98         return sb;
99     }
100
101     public StringBuffer asText() {
102         return asSimpleText();
103     }
104
105     /**
106      * Not a deep copy.
107      * 
108      */
109     public PhylogenyData copy() {
110         final Sequence seq = new Sequence();
111         seq.setAnnotations( getAnnotations() );
112         seq.setName( getName() );
113         seq.setSymbol( getSymbol() );
114         seq.setMolecularSequence( getMolecularSequence() );
115         seq.setMolecularSequenceAligned( isMolecularSequenceAligned() );
116         seq.setLocation( getLocation() );
117         if ( getAccession() != null ) {
118             seq.setAccession( ( Accession ) getAccession().copy() );
119         }
120         else {
121             seq.setAccession( null );
122         }
123         seq.setType( getType() );
124         if ( getUris() != null ) {
125             seq.setUris( new ArrayList<Uri>() );
126             for( final Uri uri : getUris() ) {
127                 if ( uri != null ) {
128                     seq.getUris().add( uri );
129                 }
130             }
131         }
132         if ( getDomainArchitecture() != null ) {
133             seq.setDomainArchitecture( ( DomainArchitecture ) getDomainArchitecture().copy() );
134         }
135         else {
136             seq.setDomainArchitecture( null );
137         }
138         return seq;
139     }
140
141     @Override
142     public boolean equals( final Object o ) {
143         if ( this == o ) {
144             return true;
145         }
146         else if ( o == null ) {
147             return false;
148         }
149         else if ( o.getClass() != this.getClass() ) {
150             throw new IllegalArgumentException( "attempt to check [" + this.getClass() + "] equality to " + o + " ["
151                     + o.getClass() + "]" );
152         }
153         else {
154             return isEqual( ( Sequence ) o );
155         }
156     }
157
158     public Accession getAccession() {
159         return _accession;
160     }
161
162     public Annotation getAnnotation( final int i ) {
163         return ( Annotation ) getAnnotations().toArray()[ i ];
164     }
165
166     public SortedSet<Annotation> getAnnotations() {
167         if ( _annotations == null ) {
168             _annotations = new TreeSet<Annotation>();
169         }
170         return _annotations;
171     }
172
173     public DomainArchitecture getDomainArchitecture() {
174         return _da;
175     }
176
177     public String getLocation() {
178         return _location;
179     }
180
181     public String getMolecularSequence() {
182         return _mol_sequence;
183     }
184
185     public boolean isMolecularSequenceAligned() {
186         return _mol_sequence_is_aligned;
187     }
188
189     public String getName() {
190         return _name;
191     }
192
193     public List<SequenceRelation> getSequenceRelations() {
194         if ( _seq_relations == null ) {
195             _seq_relations = new ArrayList<SequenceRelation>();
196         }
197         return _seq_relations;
198     }
199
200     private void setSequenceRelations( final List<SequenceRelation> seq_relations ) {
201         _seq_relations = seq_relations;
202     }
203
204     public String getSourceId() {
205         return _source_id;
206     }
207
208     public String getSymbol() {
209         return _symbol;
210     }
211
212     public String getType() {
213         return _type;
214     }
215
216     public List<Uri> getUris() {
217         return _uris;
218     }
219
220     public Uri getUri( final int index ) {
221         return getUris().get( index );
222     }
223
224     @Override
225     public int hashCode() {
226         if ( getAccession() != null ) {
227             return getAccession().hashCode();
228         }
229         int result = getSymbol().hashCode();
230         if ( getName().length() > 0 ) {
231             result ^= getName().hashCode();
232         }
233         if ( getMolecularSequence().length() > 0 ) {
234             result ^= getMolecularSequence().hashCode();
235         }
236         return result;
237     }
238
239     public boolean hasSequenceRelations() {
240         return _seq_relations.size() > 0;
241     }
242
243     public void init() {
244         setAnnotations( null );
245         setName( "" );
246         setMolecularSequence( "" );
247         setMolecularSequenceAligned( false );
248         setLocation( "" );
249         setAccession( null );
250         setSymbol( "" );
251         setType( "" );
252         setDomainArchitecture( null );
253         setUris( null );
254         setSequenceRelations( null );
255         setSourceId( null );
256     }
257
258     public boolean isEqual( final PhylogenyData data ) {
259         if ( this == data ) {
260             return true;
261         }
262         final Sequence s = ( Sequence ) data;
263         if ( ( getAccession() != null ) && ( s.getAccession() != null ) ) {
264             return getAccession().isEqual( s.getAccession() );
265         }
266         return s.getMolecularSequence().equals( getMolecularSequence() ) && s.getName().equals( getName() )
267                 && s.getSymbol().equals( getSymbol() );
268     }
269
270     public void setAccession( final Accession accession ) {
271         _accession = accession;
272     }
273
274     private void setAnnotations( final SortedSet<Annotation> annotations ) {
275         _annotations = annotations;
276     }
277
278     public void setDomainArchitecture( final DomainArchitecture ds ) {
279         _da = ds;
280     }
281
282     public void setLocation( final String description ) {
283         _location = description;
284     }
285
286     public void setMolecularSequence( final String mol_sequence ) {
287         _mol_sequence = mol_sequence;
288     }
289
290     public void setMolecularSequenceAligned( final boolean aligned ) {
291         _mol_sequence_is_aligned = aligned;
292     }
293
294     public void setName( final String name ) {
295         _name = name;
296     }
297
298     public void setSourceId( final String source_id ) {
299         _source_id = source_id;
300     }
301
302     public void setSymbol( final String symbol ) {
303         if ( !ForesterUtil.isEmpty( symbol ) && !PhyloXmlUtil.SEQUENCE_SYMBOL_PATTERN.matcher( symbol ).matches() ) {
304             throw new PhyloXmlDataFormatException( "illegal sequence symbol: [" + symbol + "]" );
305         }
306         _symbol = symbol;
307     }
308
309     public void setType( final String type ) {
310         if ( !ForesterUtil.isEmpty( type ) && !PhyloXmlUtil.SEQUENCE_TYPES.contains( type ) ) {
311             throw new PhyloXmlDataFormatException( "illegal sequence type: [" + type + "]" );
312         }
313         _type = type;
314     }
315
316     public void setUris( final List<Uri> uris ) {
317         _uris = uris;
318     }
319
320     public StringBuffer toNHX() {
321         final StringBuffer sb = new StringBuffer();
322         if ( getName().length() > 0 ) {
323             sb.append( ":" );
324             sb.append( NHXtags.GENE_NAME );
325             sb.append( ForesterUtil.replaceIllegalNhxCharacters( getName() ) );
326         }
327         if ( getAccession() != null ) {
328             getAccession().toNHX();
329         }
330         if ( getDomainArchitecture() != null ) {
331             sb.append( getDomainArchitecture().toNHX() );
332         }
333         return sb;
334     }
335
336     public void toPhyloXML( final Writer writer, final int level, final String indentation ) throws IOException {
337         if ( isEmpty() ) {
338             return;
339         }
340         final String my_ind = indentation + PhylogenyWriter.PHYLO_XML_INTENDATION_BASE;
341         writer.write( ForesterUtil.LINE_SEPARATOR );
342         writer.write( indentation );
343         PhylogenyDataUtil.appendOpen( writer, PhyloXmlMapping.SEQUENCE, PhyloXmlMapping.SEQUENCE_TYPE, getType() );
344         if ( !ForesterUtil.isEmpty( getSymbol() ) ) {
345             PhylogenyDataUtil.appendElement( writer, PhyloXmlMapping.SEQUENCE_SYMBOL, getSymbol(), indentation );
346         }
347         if ( ( getAccession() != null ) && !ForesterUtil.isEmpty( getAccession().getValue() ) ) {
348             getAccession().toPhyloXML( writer, level, indentation );
349         }
350         if ( !ForesterUtil.isEmpty( getName() ) ) {
351             PhylogenyDataUtil.appendElement( writer, PhyloXmlMapping.SEQUENCE_NAME, getName(), indentation );
352         }
353         if ( !ForesterUtil.isEmpty( getLocation() ) ) {
354             PhylogenyDataUtil.appendElement( writer, PhyloXmlMapping.SEQUENCE_LOCATION, getLocation(), indentation );
355         }
356         if ( !ForesterUtil.isEmpty( getMolecularSequence() ) ) {
357             PhylogenyDataUtil.appendElement( writer,
358                                              PhyloXmlMapping.SEQUENCE_MOL_SEQ,
359                                              getMolecularSequence(),
360                                              PhyloXmlMapping.SEQUENCE_MOL_SEQ_ALIGNED_ATTR,
361                                              String.valueOf( isMolecularSequenceAligned() ),
362                                              indentation );
363         }
364         if ( getUris() != null ) {
365             for( final Uri uri : getUris() ) {
366                 if ( uri != null ) {
367                     uri.toPhyloXML( writer, level, indentation );
368                 }
369             }
370         }
371         if ( _annotations != null ) {
372             for( final PhylogenyData annotation : getAnnotations() ) {
373                 annotation.toPhyloXML( writer, level, my_ind );
374             }
375         }
376         if ( getDomainArchitecture() != null ) {
377             getDomainArchitecture().toPhyloXML( writer, level, my_ind );
378         }
379         writer.write( ForesterUtil.LINE_SEPARATOR );
380         writer.write( indentation );
381         PhylogenyDataUtil.appendClose( writer, PhyloXmlMapping.SEQUENCE );
382     }
383
384     @Override
385     public String toString() {
386         return asText().toString();
387     }
388 }