in progress (special coloring is still true)
[jalview.git] / forester / java / src / org / forester / phylogeny / data / Event.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.StringTokenizer;
31
32 import org.forester.io.parsers.nhx.NHXFormatException;
33 import org.forester.io.parsers.nhx.NHXtags;
34 import org.forester.io.parsers.phyloxml.PhyloXmlMapping;
35 import org.forester.io.writers.PhylogenyWriter;
36 import org.forester.util.ForesterUtil;
37
38 public class Event implements PhylogenyData {
39
40     public final static int     DEFAULT_VALUE = -1;
41     private static final String NHX_SEPARATOR = ">";
42     private int                 _duplications;
43     private int                 _speciations;
44     private int                 _gene_losses;
45     private EventType           _event_type;
46     private Confidence          _confidence;
47
48     public Event() {
49         _duplications = DEFAULT_VALUE;
50         _speciations = DEFAULT_VALUE;
51         _gene_losses = DEFAULT_VALUE;
52         _event_type = EventType.unassigned;
53     }
54
55     public Event( final EventType type ) {
56         _duplications = DEFAULT_VALUE;
57         _speciations = DEFAULT_VALUE;
58         _gene_losses = DEFAULT_VALUE;
59         _event_type = type;
60     }
61
62     public Event( final int duplications, final int speciations, final int gene_losses ) {
63         _duplications = duplications;
64         _speciations = speciations;
65         _gene_losses = gene_losses;
66         _event_type = EventType.mixed;
67     }
68
69     public Event( final int duplications, final int speciations, final int gene_losses, final String type ) {
70         _duplications = duplications;
71         _speciations = speciations;
72         _gene_losses = gene_losses;
73         _event_type = EventType.valueOf( type );
74     }
75
76     public Event( final String nhx ) throws NHXFormatException {
77         if ( ForesterUtil.isEmpty( nhx ) ) {
78             _duplications = DEFAULT_VALUE;
79             _speciations = DEFAULT_VALUE;
80             _gene_losses = DEFAULT_VALUE;
81             _event_type = EventType.unassigned;
82         }
83         else {
84             final StringTokenizer st = new StringTokenizer( nhx, NHX_SEPARATOR );
85             if ( st.countTokens() != 4 ) {
86                 throw new NHXFormatException( "malformed NHX format for event [" + nhx + "]" );
87             }
88             final String duplications = ( String ) st.nextElement();
89             final String speciations = ( String ) st.nextElement();
90             final String losses = ( String ) st.nextElement();
91             final String event_type = ( String ) st.nextElement();
92             int d = 0;
93             int s = 0;
94             int l = 0;
95             try {
96                 d = Integer.parseInt( duplications );
97                 s = Integer.parseInt( speciations );
98                 l = Integer.parseInt( losses );
99                 _duplications = d;
100                 _speciations = s;
101                 _gene_losses = l;
102                 _event_type = EventType.valueOf( event_type );
103             }
104             catch ( final Exception e ) {
105                 throw new NHXFormatException( "malformed NHX format for event [" + nhx + "]:" + e.getMessage() );
106             }
107         }
108     }
109
110     @Override
111     public StringBuffer asSimpleText() {
112         final StringBuffer sb = new StringBuffer();
113         if ( isUnassigned() ) {
114         }
115         else if ( isSpeciationOrDuplication() ) {
116             sb.append( "?" );
117         }
118         else if ( isOther() || isRoot() || isTransfer() || isFusion() ) {
119             sb.append( getEventType().toString() );
120         }
121         else {
122             if ( getNumberOfDuplications() > 0 ) {
123                 if ( getNumberOfDuplications() > 1 ) {
124                     sb.append( getNumberOfDuplications() );
125                 }
126                 sb.append( "D" );
127             }
128             if ( getNumberOfSpeciations() > 0 ) {
129                 if ( getNumberOfSpeciations() > 1 ) {
130                     sb.append( getNumberOfSpeciations() );
131                 }
132                 sb.append( "S" );
133             }
134             if ( getNumberOfGeneLosses() > 0 ) {
135                 if ( getNumberOfGeneLosses() > 1 ) {
136                     sb.append( getNumberOfGeneLosses() );
137                 }
138                 sb.append( "L" );
139             }
140         }
141         return sb;
142     }
143
144     @Override
145     public StringBuffer asText() {
146         final StringBuffer sb = new StringBuffer();
147         if ( isUnassigned() || isSpeciationOrDuplication() || isOther() || isRoot() || isTransfer() || isFusion() ) {
148             sb.append( getEventType().toString() );
149         }
150         else {
151             if ( isDuplication() ) {
152                 if ( getNumberOfDuplications() == 1 ) {
153                     sb.append( "duplication" );
154                 }
155                 else {
156                     sb.append( "duplications [" + getNumberOfDuplications() + "]" );
157                 }
158             }
159             else if ( isSpeciation() ) {
160                 if ( getNumberOfSpeciations() == 1 ) {
161                     sb.append( "speciation" );
162                 }
163                 else {
164                     sb.append( "speciations [" + getNumberOfSpeciations() + "]" );
165                 }
166             }
167             else if ( isGeneLoss() ) {
168                 if ( getNumberOfGeneLosses() == 1 ) {
169                     sb.append( "gene-loss" );
170                 }
171                 else {
172                     sb.append( "gene-losses [" + getNumberOfGeneLosses() + "]" );
173                 }
174             }
175             else {
176                 sb.append( "duplications [" + getNumberOfDuplications() + "] " );
177                 sb.append( "speciations [" + getNumberOfSpeciations() + "] " );
178                 sb.append( "gene-losses [" + getNumberOfGeneLosses() + "]" );
179             }
180         }
181         return sb;
182     }
183
184     @Override
185     public PhylogenyData copy() {
186         if ( isUnassigned() ) {
187             return new Event();
188         }
189         else if ( _event_type != EventType.mixed ) {
190             return new Event( _event_type );
191         }
192         else {
193             return new Event( _duplications, _speciations, _gene_losses );
194         }
195     }
196
197     public Confidence getConfidence() {
198         return _confidence;
199     }
200
201     public EventType getEventType() {
202         return _event_type;
203     }
204
205     public int getNumberOfDuplications() {
206         return _duplications;
207     }
208
209     public int getNumberOfGeneLosses() {
210         return _gene_losses;
211     }
212
213     public int getNumberOfSpeciations() {
214         return _speciations;
215     }
216
217     /**
218      * Returns true if this event contains one or more duplications events only
219      * 
220      * @return true if this event contains one or more duplications events only
221      */
222     public boolean isDuplication() {
223         return ( _duplications > 0 ) && ( _gene_losses < 1 ) && ( _speciations < 1 );
224     }
225
226     @Override
227     public boolean isEqual( final PhylogenyData event ) {
228         if ( ( event == null ) || !( event instanceof Event ) ) {
229             return false;
230         }
231         final Event e = ( Event ) event;
232         if ( getEventType().compareTo( e.getEventType() ) != 0 ) {
233             return false;
234         }
235         if ( getNumberOfDuplications() != e.getNumberOfDuplications() ) {
236             return false;
237         }
238         if ( getNumberOfSpeciations() != e.getNumberOfSpeciations() ) {
239             return false;
240         }
241         if ( getNumberOfGeneLosses() != e.getNumberOfGeneLosses() ) {
242             return false;
243         }
244         return true;
245     }
246
247     public boolean isFusion() {
248         return _event_type == EventType.fusion;
249     }
250
251     /**
252      * Returns true if this event contains one or more gene loss events only
253      * 
254      * @return true if this event contains one or more gene loss events only
255      */
256     public boolean isGeneLoss() {
257         return ( _duplications < 1 ) && ( _gene_losses > 0 ) && ( _speciations < 1 );
258     }
259
260     public boolean isOther() {
261         return _event_type == EventType.other;
262     }
263
264     public boolean isRoot() {
265         return _event_type == EventType.root;
266     }
267
268     /**
269      * Returns true if this event contains one or more speciation events only
270      * 
271      * @return true if this event contains one or more speciation events only
272      */
273     public boolean isSpeciation() {
274         return ( _duplications < 1 ) && ( _gene_losses < 1 ) && ( _speciations > 0 );
275     }
276
277     public boolean isSpeciationOrDuplication() {
278         return _event_type == EventType.speciation_or_duplication;
279     }
280
281     public boolean isTransfer() {
282         return _event_type == EventType.transfer;
283     }
284
285     public boolean isUnassigned() {
286         return ( _duplications == DEFAULT_VALUE ) && ( _event_type == EventType.unassigned );
287     }
288
289     public void setConfidence( final Confidence confidence ) {
290         _confidence = confidence;
291     }
292
293     public void setDuplications( final int duplications ) {
294         _duplications = duplications;
295         _event_type = EventType.mixed;
296     }
297
298     public void setGeneLosses( final int gene_losses ) {
299         _gene_losses = gene_losses;
300         _event_type = EventType.mixed;
301     }
302
303     public void setSpeciations( final int speciations ) {
304         _speciations = speciations;
305         _event_type = EventType.mixed;
306     }
307
308     @Override
309     public StringBuffer toNHX() {
310         final StringBuffer sb = new StringBuffer();
311         if ( !isUnassigned() && ( isSpeciationOrDuplication() || isDuplication() || isSpeciation() ) ) {
312             sb.append( ":" );
313             sb.append( NHXtags.IS_DUPLICATION );
314             if ( isSpeciationOrDuplication() ) {
315                 sb.append( "?" );
316             }
317             else if ( isDuplication() ) {
318                 sb.append( "Y" );
319             }
320             else if ( isSpeciation() ) {
321                 sb.append( "N" );
322             }
323         }
324         return sb;
325     }
326
327     @Override
328     public void toPhyloXML( final Writer writer, final int level, final String indentation ) throws IOException {
329         writer.write( ForesterUtil.LINE_SEPARATOR );
330         writer.write( indentation );
331         PhylogenyDataUtil.appendOpen( writer, PhyloXmlMapping.EVENTS );
332         if ( ( getEventType() != EventType.unassigned ) && ( getEventType() != EventType.mixed ) ) {
333             PhylogenyDataUtil
334                     .appendElement( writer, PhyloXmlMapping.EVENT_TYPE, getEventType().toString(), indentation );
335         }
336         if ( getNumberOfDuplications() > 0 ) {
337             PhylogenyDataUtil.appendElement( writer,
338                                              PhyloXmlMapping.EVENT_DUPLICATIONS,
339                                              getNumberOfDuplications() + "",
340                                              indentation );
341         }
342         if ( getNumberOfSpeciations() > 0 ) {
343             PhylogenyDataUtil.appendElement( writer,
344                                              PhyloXmlMapping.EVENT_SPECIATIONS,
345                                              getNumberOfSpeciations() + "",
346                                              indentation );
347         }
348         if ( getNumberOfGeneLosses() > 0 ) {
349             PhylogenyDataUtil.appendElement( writer,
350                                              PhyloXmlMapping.EVENT_LOSSES,
351                                              getNumberOfGeneLosses() + "",
352                                              indentation );
353         }
354         if ( getConfidence() != null ) {
355             getConfidence().toPhyloXML( writer, level, indentation + PhylogenyWriter.PHYLO_XML_INTENDATION_BASE );
356         }
357         writer.write( ForesterUtil.LINE_SEPARATOR );
358         writer.write( indentation );
359         PhylogenyDataUtil.appendClose( writer, PhyloXmlMapping.EVENTS );
360     }
361
362     @Override
363     public String toString() {
364         return asText().toString();
365     }
366
367     public static Event createSingleDuplicationEvent() {
368         return new Event( 1, 0, 0 );
369     }
370
371     public static Event createSingleSpeciationEvent() {
372         return new Event( 0, 1, 0 );
373     }
374
375     public static Event createSingleSpeciationOrDuplicationEvent() {
376         return new Event( EventType.speciation_or_duplication );
377     }
378
379     public static enum EventType {
380         transfer, fusion, root, speciation_or_duplication, other, mixed, unassigned
381     }
382 }