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