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