2fe049735d23e07ac4a091add7a9b614ee78123d
[jalview.git] / forester / java / src / org / forester / phylogeny / data / Taxonomy.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
33 import org.forester.io.parsers.nhx.NHXtags;
34 import org.forester.io.parsers.phyloxml.PhyloXmlDataFormatException;
35 import org.forester.io.parsers.phyloxml.PhyloXmlMapping;
36 import org.forester.io.parsers.phyloxml.PhyloXmlUtil;
37 import org.forester.util.ForesterConstants;
38 import org.forester.util.ForesterUtil;
39
40 public class Taxonomy implements PhylogenyData, MultipleUris, Comparable<Taxonomy> {
41
42     
43     
44     private String       _scientific_name;
45     private String       _common_name;
46     private List<String> _synonyms;
47     private String       _authority;
48     private Identifier   _identifier;
49     private String       _taxonomy_code;
50     private String       _rank;
51     private List<Uri>    _uris;
52     private List<String> _lineage;
53
54     public Taxonomy() {
55         init();
56     }
57
58     @Override
59     public StringBuffer asSimpleText() {
60         return asText();
61     }
62
63     @Override
64     public Uri getUri( final int index ) {
65         return getUris().get( index );
66     }
67
68     @Override
69     public void addUri( final Uri uri ) {
70         if ( getUris() == null ) {
71             setUris( new ArrayList<Uri>() );
72         }
73         getUris().add( uri );
74     }
75
76     @Override
77     public StringBuffer asText() {
78         final StringBuffer sb = new StringBuffer();
79         if ( getIdentifier() != null ) {
80             sb.append( "[" );
81             sb.append( getIdentifier().asSimpleText() );
82             sb.append( "]" );
83         }
84         if ( !ForesterUtil.isEmpty( getTaxonomyCode() ) ) {
85             if ( sb.length() > 0 ) {
86                 sb.append( " " );
87             }
88             sb.append( "[" );
89             sb.append( getTaxonomyCode() );
90             sb.append( "]" );
91         }
92         if ( !ForesterUtil.isEmpty( getScientificName() ) ) {
93             if ( sb.length() > 0 ) {
94                 sb.append( " " );
95             }
96             sb.append( getScientificName() );
97             if ( !ForesterUtil.isEmpty( getAuthority() ) ) {
98                 sb.append( " (" );
99                 sb.append( getAuthority() );
100                 sb.append( ")" );
101             }
102         }
103         if ( !ForesterUtil.isEmpty( getCommonName() ) ) {
104             if ( sb.length() > 0 ) {
105                 sb.append( " " );
106             }
107             sb.append( getCommonName() );
108         }
109         return sb;
110     }
111
112     @Override
113     public PhylogenyData copy() {
114         final Taxonomy t = new Taxonomy();
115         try {
116             t.setTaxonomyCode( getTaxonomyCode() );
117         }
118         catch ( final PhyloXmlDataFormatException e ) {
119             e.printStackTrace();
120         }
121         t.setScientificName( getScientificName() );
122         t.setCommonName( getCommonName() );
123         t.setAuthority( getAuthority() );
124         for( final String syn : getSynonyms() ) {
125             t.getSynonyms().add( syn );
126         }
127         if ( getIdentifier() != null ) {
128             t.setIdentifier( ( Identifier ) getIdentifier().copy() );
129         }
130         else {
131             t.setIdentifier( null );
132         }
133         try {
134             t.setRank( new String( getRank() ) );
135         }
136         catch ( final PhyloXmlDataFormatException e ) {
137             e.printStackTrace();
138         }
139         if ( getUris() != null ) {
140             t.setUris( new ArrayList<Uri>() );
141             for( final Uri uri : getUris() ) {
142                 if ( uri != null ) {
143                     t.getUris().add( uri );
144                 }
145             }
146         }
147         if ( getLineage() != null ) {
148             t.setLineage( new ArrayList<String>() );
149             for( final String l : getLineage() ) {
150                 if ( l != null ) {
151                     t.getLineage().add( l );
152                 }
153             }
154         }
155         return t;
156     }
157
158     @Override
159     public boolean equals( final Object o ) {
160         if ( this == o ) {
161             return true;
162         }
163         else if ( o == null ) {
164             return false;
165         }
166         else if ( o.getClass() != this.getClass() ) {
167             throw new IllegalArgumentException( "attempt to check [" + this.getClass() + "] equality to " + o + " ["
168                     + o.getClass() + "]" );
169         }
170         else {
171             return isEqual( ( Taxonomy ) o );
172         }
173     }
174
175     public String getAuthority() {
176         return _authority;
177     }
178
179     public String getCommonName() {
180         return _common_name;
181     }
182
183     public Identifier getIdentifier() {
184         return _identifier;
185     }
186
187     public String getRank() {
188         return _rank;
189     }
190
191     public String getScientificName() {
192         return _scientific_name;
193     }
194
195     public List<String> getSynonyms() {
196         if ( _synonyms == null ) {
197             _synonyms = new ArrayList<String>();
198         }
199         return _synonyms;
200     }
201
202     public String getTaxonomyCode() {
203         return _taxonomy_code;
204     }
205
206     @Override
207     public List<Uri> getUris() {
208         return _uris;
209     }
210
211     @Override
212     public int hashCode() {
213         if ( ( getIdentifier() != null ) && !ForesterUtil.isEmpty( getIdentifier().getValue() ) ) {
214             return getIdentifier().hashCode();
215         }
216         else if ( !ForesterUtil.isEmpty( getTaxonomyCode() ) ) {
217             return getTaxonomyCode().hashCode();
218         }
219         else if ( !ForesterUtil.isEmpty( getScientificName() ) ) {
220             if ( !ForesterUtil.isEmpty( getAuthority() ) ) {
221                 return ( getScientificName().toLowerCase() + getAuthority().toLowerCase() ).hashCode();
222             }
223             return getScientificName().toLowerCase().hashCode();
224         }
225         else {
226             return getCommonName().toLowerCase().hashCode();
227         }
228     }
229
230     public void init() {
231         setScientificName( "" );
232         setCommonName( "" );
233         setIdentifier( null );
234         try {
235             setRank( "" );
236         }
237         catch ( final PhyloXmlDataFormatException e ) {
238             e.printStackTrace();
239         }
240         try {
241             setTaxonomyCode( "" );
242         }
243         catch ( final PhyloXmlDataFormatException e ) {
244             e.printStackTrace();
245         }
246         setAuthority( "" );
247         setSynonyms( null );
248         setUris( null );
249         setLineage( null );
250     }
251
252     public boolean isEmpty() {
253         return ( ( getIdentifier() == null ) && ForesterUtil.isEmpty( getTaxonomyCode() )
254                 && ForesterUtil.isEmpty( getCommonName() ) && ForesterUtil.isEmpty( getScientificName() )
255                 && ForesterUtil.isEmpty( getRank() ) && ForesterUtil.isEmpty( _uris )
256                 && ForesterUtil.isEmpty( getAuthority() ) && ForesterUtil.isEmpty( _synonyms ) && ForesterUtil
257                 .isEmpty( _lineage ) );
258     }
259
260     /**
261      * 
262      * If this and taxonomy 'data' has an identifier, comparison will be based on that.
263      * Otherwise,  if this and taxonomy 'data' has a code, comparison will be based on that.
264      * Otherwise,  if Taxonomy 'data' has a scientific name, comparison will be
265      * based on that (case insensitive!).
266      * Otherwise,  if Taxonomy 'data' has a common  name, comparison will be
267      * based on that (case insensitive!).
268      * (Note. This is important and should not be change without a very good reason.)
269      * 
270      */
271     @Override
272     public boolean isEqual( final PhylogenyData data ) {
273         if ( this == data ) {
274             return true;
275         }
276         final Taxonomy tax = ( Taxonomy ) data;
277         if ( ( getIdentifier() != null ) && ( tax.getIdentifier() != null )
278                 && !ForesterUtil.isEmpty( getIdentifier().getValue() )
279                 && !ForesterUtil.isEmpty( tax.getIdentifier().getValue() ) ) {
280             return getIdentifier().isEqual( tax.getIdentifier() );
281         }
282         else if ( !ForesterUtil.isEmpty( getTaxonomyCode() ) && !ForesterUtil.isEmpty( tax.getTaxonomyCode() ) ) {
283             return getTaxonomyCode().equals( tax.getTaxonomyCode() );
284         }
285         else if ( !ForesterUtil.isEmpty( getScientificName() ) && !ForesterUtil.isEmpty( tax.getScientificName() ) ) {
286             if ( !ForesterUtil.isEmpty( getAuthority() ) && !ForesterUtil.isEmpty( tax.getAuthority() ) ) {
287                 return ( getScientificName().equalsIgnoreCase( tax.getScientificName() ) )
288                         && ( getAuthority().equalsIgnoreCase( tax.getAuthority() ) );
289             }
290             return getScientificName().equalsIgnoreCase( tax.getScientificName() );
291         }
292         else if ( !ForesterUtil.isEmpty( getCommonName() ) && !ForesterUtil.isEmpty( tax.getCommonName() ) ) {
293             return getCommonName().equalsIgnoreCase( tax.getCommonName() );
294         }
295         else if ( !ForesterUtil.isEmpty( getScientificName() ) && !ForesterUtil.isEmpty( tax.getCommonName() ) ) {
296             return getScientificName().equalsIgnoreCase( tax.getCommonName() );
297         }
298         else if ( !ForesterUtil.isEmpty( getCommonName() ) && !ForesterUtil.isEmpty( tax.getScientificName() ) ) {
299             return getCommonName().equalsIgnoreCase( tax.getScientificName() );
300         }
301         throw new RuntimeException( "comparison not possible with empty fields" );
302     }
303
304     public void setAuthority( final String authority ) {
305         _authority = authority;
306     }
307
308     public void setCommonName( final String common_name ) {
309         _common_name = common_name;
310     }
311
312     public void setIdentifier( final Identifier identifier ) {
313         _identifier = identifier;
314     }
315
316     public void setRank( final String rank ) throws PhyloXmlDataFormatException {
317         if ( !ForesterUtil.isEmpty( rank ) && !PhyloXmlUtil.TAXONOMY_RANKS_SET.contains( rank ) ) {
318             throw new PhyloXmlDataFormatException( "illegal rank: [" + rank + "]" );
319         }
320         _rank = rank;
321     }
322
323     public void setScientificName( final String scientific_name ) {
324         _scientific_name = scientific_name;
325     }
326
327     private void setSynonyms( final List<String> synonyms ) {
328         _synonyms = synonyms;
329     }
330
331     public void setTaxonomyCode( final String taxonomy_code ) throws PhyloXmlDataFormatException {
332       
333             if ( !ForesterUtil.isEmpty( taxonomy_code )
334                     && !PhyloXmlUtil.TAXOMONY_CODE_PATTERN.matcher( taxonomy_code ).matches() ) {
335                 throw new PhyloXmlDataFormatException( "illegal taxonomy code: [" + taxonomy_code + "]" );
336             }
337        
338         _taxonomy_code = taxonomy_code;
339     }
340
341     @Override
342     public void setUris( final List<Uri> uris ) {
343         _uris = uris;
344     }
345
346     @Override
347     public StringBuffer toNHX() {
348         final StringBuffer sb = new StringBuffer();
349         if ( getIdentifier() != null ) {
350             sb.append( ':' + NHXtags.TAXONOMY_ID );
351             sb.append( ForesterUtil.replaceIllegalNhxCharacters( getIdentifier().getValue() ) );
352         }
353         final StringBuffer species = new StringBuffer();
354         if ( !ForesterUtil.isEmpty( getTaxonomyCode() ) ) {
355             species.append( ForesterUtil.replaceIllegalNhxCharacters( getTaxonomyCode() ) );
356         }
357         if ( !ForesterUtil.isEmpty( getScientificName() ) ) {
358             ForesterUtil.appendSeparatorIfNotEmpty( species, '|' );
359             species.append( ForesterUtil.replaceIllegalNhxCharacters( getScientificName() ) );
360         }
361         if ( !ForesterUtil.isEmpty( getCommonName() ) ) {
362             ForesterUtil.appendSeparatorIfNotEmpty( species, '|' );
363             species.append( ForesterUtil.replaceIllegalNhxCharacters( getCommonName() ) );
364         }
365         if ( species.length() > 0 ) {
366             sb.append( ':' + NHXtags.SPECIES_NAME );
367             sb.append( species );
368         }
369         return sb;
370     }
371
372     @Override
373     public void toPhyloXML( final Writer writer, final int level, final String indentation ) throws IOException {
374         if ( isEmpty() ) {
375             return;
376         }
377         writer.write( ForesterUtil.LINE_SEPARATOR );
378         writer.write( indentation );
379         PhylogenyDataUtil.appendOpen( writer, PhyloXmlMapping.TAXONOMY );
380         if ( ( getIdentifier() != null ) && !ForesterUtil.isEmpty( getIdentifier().getValue() ) ) {
381             getIdentifier().toPhyloXML( writer, level, indentation );
382         }
383         if ( !ForesterUtil.isEmpty( getTaxonomyCode() ) ) {
384             PhylogenyDataUtil.appendElement( writer, PhyloXmlMapping.TAXONOMY_CODE, getTaxonomyCode(), indentation );
385         }
386         if ( !ForesterUtil.isEmpty( getScientificName() ) ) {
387             PhylogenyDataUtil.appendElement( writer,
388                                              PhyloXmlMapping.TAXONOMY_SCIENTIFIC_NAME,
389                                              getScientificName(),
390                                              indentation );
391         }
392         if ( !ForesterUtil.isEmpty( getAuthority() ) ) {
393             PhylogenyDataUtil.appendElement( writer, PhyloXmlMapping.TAXONOMY_AUTHORITY, getAuthority(), indentation );
394         }
395         if ( !ForesterUtil.isEmpty( getCommonName() ) ) {
396             PhylogenyDataUtil
397                     .appendElement( writer, PhyloXmlMapping.TAXONOMY_COMMON_NAME, getCommonName(), indentation );
398         }
399         if ( _synonyms != null ) {
400             for( final String syn : getSynonyms() ) {
401                 if ( !ForesterUtil.isEmpty( syn ) ) {
402                     PhylogenyDataUtil.appendElement( writer, PhyloXmlMapping.TAXONOMY_SYNONYM, syn, indentation );
403                 }
404             }
405         }
406         if ( !ForesterUtil.isEmpty( getRank() ) ) {
407             PhylogenyDataUtil.appendElement( writer, PhyloXmlMapping.TAXONOMY_RANK, getRank(), indentation );
408         }
409         if ( getUris() != null ) {
410             for( final Uri uri : getUris() ) {
411                 if ( uri != null ) {
412                     uri.toPhyloXML( writer, level, indentation );
413                 }
414             }
415         }
416         writer.write( ForesterUtil.LINE_SEPARATOR );
417         writer.write( indentation );
418         PhylogenyDataUtil.appendClose( writer, PhyloXmlMapping.TAXONOMY );
419     }
420
421     @Override
422     public String toString() {
423         return asText().toString();
424     }
425
426     @Override
427     public int compareTo( final Taxonomy o ) {
428         if ( equals( o ) ) {
429             return 0;
430         }
431         else if ( !ForesterUtil.isEmpty( getScientificName() ) && !ForesterUtil.isEmpty( o.getScientificName() ) ) {
432             return getScientificName().compareToIgnoreCase( o.getScientificName() );
433         }
434         else if ( !ForesterUtil.isEmpty( getCommonName() ) && !ForesterUtil.isEmpty( o.getCommonName() ) ) {
435             return getCommonName().compareToIgnoreCase( o.getCommonName() );
436         }
437         else if ( !ForesterUtil.isEmpty( getTaxonomyCode() ) && !ForesterUtil.isEmpty( o.getTaxonomyCode() ) ) {
438             return getTaxonomyCode().compareToIgnoreCase( o.getTaxonomyCode() );
439         }
440         return 0;
441     }
442
443     public void setLineage( final List<String> lineage ) {
444         _lineage = lineage;
445     }
446
447     public List<String> getLineage() {
448         return _lineage;
449     }
450 }