initial commit
[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: 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.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     public StringBuffer asSimpleText() {
111         final StringBuffer sb = new StringBuffer();
112         if ( isUnassigned() ) {
113         }
114         else if ( isSpeciationOrDuplication() ) {
115             sb.append( "?" );
116         }
117         else if ( isOther() || isRoot() || isTransfer() || isFusion() ) {
118             sb.append( getEventType().toString() );
119         }
120         else {
121             if ( getNumberOfDuplications() > 0 ) {
122                 if ( getNumberOfDuplications() > 1 ) {
123                     sb.append( getNumberOfDuplications() );
124                 }
125                 sb.append( "D" );
126             }
127             if ( getNumberOfSpeciations() > 0 ) {
128                 if ( getNumberOfSpeciations() > 1 ) {
129                     sb.append( getNumberOfSpeciations() );
130                 }
131                 sb.append( "S" );
132             }
133             if ( getNumberOfGeneLosses() > 0 ) {
134                 if ( getNumberOfGeneLosses() > 1 ) {
135                     sb.append( getNumberOfGeneLosses() );
136                 }
137                 sb.append( "L" );
138             }
139         }
140         return sb;
141     }
142
143     public StringBuffer asText() {
144         final StringBuffer sb = new StringBuffer();
145         if ( isUnassigned() || isSpeciationOrDuplication() || isOther() || isRoot() || isTransfer() || isFusion() ) {
146             sb.append( getEventType().toString() );
147         }
148         else {
149             if ( isDuplication() ) {
150                 if ( getNumberOfDuplications() == 1 ) {
151                     sb.append( "duplication" );
152                 }
153                 else {
154                     sb.append( "duplications [" + getNumberOfDuplications() + "]" );
155                 }
156             }
157             else if ( isSpeciation() ) {
158                 if ( getNumberOfSpeciations() == 1 ) {
159                     sb.append( "speciation" );
160                 }
161                 else {
162                     sb.append( "speciations [" + getNumberOfSpeciations() + "]" );
163                 }
164             }
165             else if ( isGeneLoss() ) {
166                 if ( getNumberOfGeneLosses() == 1 ) {
167                     sb.append( "gene-loss" );
168                 }
169                 else {
170                     sb.append( "gene-losses [" + getNumberOfGeneLosses() + "]" );
171                 }
172             }
173             else {
174                 sb.append( "duplications [" + getNumberOfDuplications() + "] " );
175                 sb.append( "speciations [" + getNumberOfSpeciations() + "] " );
176                 sb.append( "gene-losses [" + getNumberOfGeneLosses() + "]" );
177             }
178         }
179         return sb;
180     }
181
182     public PhylogenyData copy() {
183         if ( isUnassigned() ) {
184             return new Event();
185         }
186         else if ( _event_type != EventType.mixed ) {
187             return new Event( _event_type );
188         }
189         else {
190             return new Event( _duplications, _speciations, _gene_losses );
191         }
192     }
193
194     public Confidence getConfidence() {
195         return _confidence;
196     }
197
198     public EventType getEventType() {
199         return _event_type;
200     }
201
202     public int getNumberOfDuplications() {
203         return _duplications;
204     }
205
206     public int getNumberOfGeneLosses() {
207         return _gene_losses;
208     }
209
210     public int getNumberOfSpeciations() {
211         return _speciations;
212     }
213
214     /**
215      * Returns true if this event contains one or more duplications events only
216      * 
217      * @return true if this event contains one or more duplications events only
218      */
219     public boolean isDuplication() {
220         return ( _duplications > 0 ) && ( _gene_losses < 1 ) && ( _speciations < 1 );
221     }
222
223     public boolean isEqual( final PhylogenyData event ) {
224         if ( ( event == null ) || !( event instanceof Event ) ) {
225             return false;
226         }
227         final Event e = ( Event ) event;
228         if ( getEventType().compareTo( e.getEventType() ) != 0 ) {
229             return false;
230         }
231         if ( getNumberOfDuplications() != e.getNumberOfDuplications() ) {
232             return false;
233         }
234         if ( getNumberOfSpeciations() != e.getNumberOfSpeciations() ) {
235             return false;
236         }
237         if ( getNumberOfGeneLosses() != e.getNumberOfGeneLosses() ) {
238             return false;
239         }
240         return true;
241     }
242
243     public boolean isFusion() {
244         return _event_type == EventType.fusion;
245     }
246
247     /**
248      * Returns true if this event contains one or more gene loss events only
249      * 
250      * @return true if this event contains one or more gene loss events only
251      */
252     public boolean isGeneLoss() {
253         return ( _duplications < 1 ) && ( _gene_losses > 0 ) && ( _speciations < 1 );
254     }
255
256     public boolean isOther() {
257         return _event_type == EventType.other;
258     }
259
260     public boolean isRoot() {
261         return _event_type == EventType.root;
262     }
263
264     /**
265      * Returns true if this event contains one or more speciation events only
266      * 
267      * @return true if this event contains one or more speciation events only
268      */
269     public boolean isSpeciation() {
270         return ( _duplications < 1 ) && ( _gene_losses < 1 ) && ( _speciations > 0 );
271     }
272
273     public boolean isSpeciationOrDuplication() {
274         return _event_type == EventType.speciation_or_duplication;
275     }
276
277     public boolean isTransfer() {
278         return _event_type == EventType.transfer;
279     }
280
281     public boolean isUnassigned() {
282         return ( _duplications == DEFAULT_VALUE ) && ( _event_type == EventType.unassigned );
283     }
284
285     public void setConfidence( final Confidence confidence ) {
286         _confidence = confidence;
287     }
288
289     public void setDuplications( final int duplications ) {
290         _duplications = duplications;
291         _event_type = EventType.mixed;
292     }
293
294     public void setGeneLosses( final int gene_losses ) {
295         _gene_losses = gene_losses;
296         _event_type = EventType.mixed;
297     }
298
299     public void setSpeciations( final int speciations ) {
300         _speciations = speciations;
301         _event_type = EventType.mixed;
302     }
303
304     public StringBuffer toNHX() {
305         final StringBuffer sb = new StringBuffer();
306         if ( !isUnassigned() && ( isSpeciationOrDuplication() || isDuplication() || isSpeciation() ) ) {
307             sb.append( ":" );
308             sb.append( NHXtags.IS_DUPLICATION );
309             if ( isSpeciationOrDuplication() ) {
310                 sb.append( "?" );
311             }
312             else if ( isDuplication() ) {
313                 sb.append( "Y" );
314             }
315             else if ( isSpeciation() ) {
316                 sb.append( "N" );
317             }
318         }
319         return sb;
320     }
321
322     public void toPhyloXML( final Writer writer, final int level, final String indentation ) throws IOException {
323         writer.write( ForesterUtil.LINE_SEPARATOR );
324         writer.write( indentation );
325         PhylogenyDataUtil.appendOpen( writer, PhyloXmlMapping.EVENTS );
326         if ( ( getEventType() != EventType.unassigned ) && ( getEventType() != EventType.mixed ) ) {
327             PhylogenyDataUtil
328                     .appendElement( writer, PhyloXmlMapping.EVENT_TYPE, getEventType().toString(), indentation );
329         }
330         if ( getNumberOfDuplications() > 0 ) {
331             PhylogenyDataUtil.appendElement( writer,
332                                              PhyloXmlMapping.EVENT_DUPLICATIONS,
333                                              getNumberOfDuplications() + "",
334                                              indentation );
335         }
336         if ( getNumberOfSpeciations() > 0 ) {
337             PhylogenyDataUtil.appendElement( writer,
338                                              PhyloXmlMapping.EVENT_SPECIATIONS,
339                                              getNumberOfSpeciations() + "",
340                                              indentation );
341         }
342         if ( getNumberOfGeneLosses() > 0 ) {
343             PhylogenyDataUtil.appendElement( writer,
344                                              PhyloXmlMapping.EVENT_LOSSES,
345                                              getNumberOfGeneLosses() + "",
346                                              indentation );
347         }
348         if ( getConfidence() != null ) {
349             getConfidence().toPhyloXML( writer, level, indentation + PhylogenyWriter.PHYLO_XML_INTENDATION_BASE );
350         }
351         writer.write( ForesterUtil.LINE_SEPARATOR );
352         writer.write( indentation );
353         PhylogenyDataUtil.appendClose( writer, PhyloXmlMapping.EVENTS );
354     }
355
356     @Override
357     public String toString() {
358         return asText().toString();
359     }
360
361     public static Event createSingleDuplicationEvent() {
362         return new Event( 1, 0, 0 );
363     }
364
365     public static Event createSingleSpeciationEvent() {
366         return new Event( 0, 1, 0 );
367     }
368
369     public static Event createSingleSpeciationOrDuplicationEvent() {
370         return new Event( EventType.speciation_or_duplication );
371     }
372
373     public static enum EventType {
374         transfer, fusion, root, speciation_or_duplication, other, mixed, unassigned
375     }
376 }