initial commit
[jalview.git] / forester / java / src / org / forester / phylogeny / data / BinaryCharacters.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.Iterator;
31 import java.util.SortedSet;
32 import java.util.TreeSet;
33
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 BinaryCharacters implements PhylogenyData {
39
40     public final static int         COUNT_DEFAULT = -1;
41     private final SortedSet<String> _present;
42     private final SortedSet<String> _gained;
43     private final SortedSet<String> _lost;
44     private final int               _present_count;
45     private final int               _gained_count;
46     private final int               _lost_count;
47     private String                  _type;
48
49     public BinaryCharacters() {
50         _present = new TreeSet<String>();
51         _gained = new TreeSet<String>();
52         _lost = new TreeSet<String>();
53         _present_count = COUNT_DEFAULT;
54         _gained_count = COUNT_DEFAULT;
55         _lost_count = COUNT_DEFAULT;
56     }
57
58     public BinaryCharacters( final SortedSet<String> present_characters,
59                              final SortedSet<String> gained_characters,
60                              final SortedSet<String> lost_characters,
61                              final String type ) {
62         _present = present_characters;
63         _gained = gained_characters;
64         _lost = lost_characters;
65         _type = type;
66         _present_count = COUNT_DEFAULT;
67         _gained_count = COUNT_DEFAULT;
68         _lost_count = COUNT_DEFAULT;
69     }
70
71     public BinaryCharacters( final SortedSet<String> present_characters,
72                              final SortedSet<String> gained_characters,
73                              final SortedSet<String> lost_characters,
74                              final String type,
75                              final int present_count,
76                              final int gained_count,
77                              final int lost_count ) {
78         _present = present_characters;
79         _gained = gained_characters;
80         _lost = lost_characters;
81         _type = type;
82         _present_count = present_count;
83         _gained_count = gained_count;
84         _lost_count = lost_count;
85         validate();
86     }
87
88     private void addCharacters( final String indentation, final Writer w, final String[] present ) throws IOException {
89         for( final String string : present ) {
90             PhylogenyDataUtil.appendElement( w, PhyloXmlMapping.BINARY_CHARACTER, string, indentation );
91         }
92     }
93
94     public void addGainedCharacter( final String binary_character ) {
95         if ( getLostCharacters().contains( binary_character ) ) {
96             throw new IllegalArgumentException( "attempt to add binary character [" + binary_character
97                     + "] to gained characters but is already listed as lost" );
98         }
99         getGainedCharacters().add( binary_character );
100     }
101
102     public void addLostCharacter( final String binary_character ) {
103         if ( getPresentCharacters().contains( binary_character ) ) {
104             throw new IllegalArgumentException( "attempt to add binary character [" + binary_character
105                     + "] to lost characters but is already listed as present" );
106         }
107         if ( getGainedCharacters().contains( binary_character ) ) {
108             throw new IllegalArgumentException( "attempt to add binary character [" + binary_character
109                     + "] to lost characters but is already listed as gained" );
110         }
111         getLostCharacters().add( binary_character );
112     }
113
114     public void addPresentCharacter( final String binary_character ) {
115         if ( getLostCharacters().contains( binary_character ) ) {
116             throw new IllegalArgumentException( "attempt to add binary character [" + binary_character
117                     + "] to present characters but is already listed as lost" );
118         }
119         getPresentCharacters().add( binary_character );
120     }
121
122     @Override
123     public StringBuffer asSimpleText() {
124         return asText();
125     }
126
127     @Override
128     public StringBuffer asText() {
129         validate();
130         final StringBuffer sb = new StringBuffer();
131         sb.append( "present [" );
132         sb.append( getPresentCount() );
133         sb.append( "]: " );
134         sb.append( getPresentCharactersAsStringBuffer() );
135         sb.append( ForesterUtil.LINE_SEPARATOR );
136         sb.append( "gained  [ " );
137         sb.append( getGainedCount() );
138         sb.append( "]: " );
139         sb.append( getGainedCharactersAsStringBuffer() );
140         sb.append( ForesterUtil.LINE_SEPARATOR );
141         sb.append( "lost    [" );
142         sb.append( getLostCount() );
143         sb.append( "]: " );
144         sb.append( getLostCharactersAsStringBuffer() );
145         return sb;
146     }
147
148     @Override
149     /**
150      * Not a deep copy.
151      * 
152      */
153     public PhylogenyData copy() {
154         validate();
155         return new BinaryCharacters( getPresentCharacters(),
156                                      getGainedCharacters(),
157                                      getLostCharacters(),
158                                      getType(),
159                                      getPresentCount(),
160                                      getGainedCount(),
161                                      getLostCount() );
162     }
163
164     public SortedSet<String> getGainedCharacters() {
165         return _gained;
166     }
167
168     public String[] getGainedCharactersAsStringArray() {
169         return sortedSetToStringArray( getGainedCharacters() );
170     }
171
172     public StringBuffer getGainedCharactersAsStringBuffer() {
173         return sortedSetToStringBuffer( getGainedCharacters(), " " );
174     }
175
176     public int getGainedCount() {
177         return _gained_count;
178     }
179
180     public SortedSet<String> getLostCharacters() {
181         return _lost;
182     }
183
184     public String[] getLostCharactersAsStringArray() {
185         return sortedSetToStringArray( getLostCharacters() );
186     }
187
188     public StringBuffer getLostCharactersAsStringBuffer() {
189         return sortedSetToStringBuffer( getLostCharacters(), " " );
190     }
191
192     public int getLostCount() {
193         return _lost_count;
194     }
195
196     public SortedSet<String> getPresentCharacters() {
197         return _present;
198     }
199
200     public String[] getPresentCharactersAsStringArray() {
201         return sortedSetToStringArray( getPresentCharacters() );
202     }
203
204     public StringBuffer getPresentCharactersAsStringBuffer() {
205         return sortedSetToStringBuffer( getPresentCharacters(), " " );
206     }
207
208     public int getPresentCount() {
209         return _present_count;
210     }
211
212     public String getType() {
213         return _type;
214     }
215
216     @Override
217     public boolean isEqual( final PhylogenyData data ) {
218         throw new UnsupportedOperationException();
219     }
220
221     public void setType( final String type ) {
222         _type = type;
223     }
224
225     @Override
226     public StringBuffer toNHX() {
227         throw new UnsupportedOperationException();
228     }
229
230     @Override
231     public void toPhyloXML( final Writer writer, final int level, final String indentation ) throws IOException {
232         validate();
233         writer.write( ForesterUtil.LINE_SEPARATOR );
234         writer.write( indentation );
235         PhylogenyDataUtil.appendOpen( writer,
236                                       PhyloXmlMapping.BINARY_CHARACTERS,
237                                       PhyloXmlMapping.BINARY_CHARACTERS_TYPE_ATTR,
238                                       getType(),
239                                       PhyloXmlMapping.BINARY_CHARACTERS_GAINED_COUNT_ATTR,
240                                       getGainedCount() != COUNT_DEFAULT ? String.valueOf( getGainedCount() ) : "",
241                                       PhyloXmlMapping.BINARY_CHARACTERS_LOST_COUNT_ATTR,
242                                       getLostCount() != COUNT_DEFAULT ? String.valueOf( getLostCount() ) : "",
243                                       PhyloXmlMapping.BINARY_CHARACTERS_PRESENT_COUNT_ATTR,
244                                       getPresentCount() != COUNT_DEFAULT ? String.valueOf( getPresentCount() ) : "" );
245         final String my_ind = indentation + PhylogenyWriter.PHYLO_XML_INTENDATION_BASE;
246         if ( getGainedCharacters().size() > 0 ) {
247             writer.write( ForesterUtil.LINE_SEPARATOR );
248             writer.write( my_ind );
249             PhylogenyDataUtil.appendOpen( writer, PhyloXmlMapping.BINARY_CHARACTERS_GAINED );
250             addCharacters( my_ind, writer, getGainedCharactersAsStringArray() );
251             writer.write( ForesterUtil.LINE_SEPARATOR );
252             writer.write( my_ind );
253             PhylogenyDataUtil.appendClose( writer, PhyloXmlMapping.BINARY_CHARACTERS_GAINED );
254         }
255         if ( getLostCharacters().size() > 0 ) {
256             writer.write( ForesterUtil.LINE_SEPARATOR );
257             writer.write( my_ind );
258             PhylogenyDataUtil.appendOpen( writer, PhyloXmlMapping.BINARY_CHARACTERS_LOST );
259             addCharacters( my_ind, writer, getLostCharactersAsStringArray() );
260             writer.write( ForesterUtil.LINE_SEPARATOR );
261             writer.write( my_ind );
262             PhylogenyDataUtil.appendClose( writer, PhyloXmlMapping.BINARY_CHARACTERS_LOST );
263         }
264         if ( getPresentCharacters().size() > 0 ) {
265             writer.write( ForesterUtil.LINE_SEPARATOR );
266             writer.write( my_ind );
267             PhylogenyDataUtil.appendOpen( writer, PhyloXmlMapping.BINARY_CHARACTERS_PRESENT );
268             addCharacters( my_ind, writer, getPresentCharactersAsStringArray() );
269             writer.write( ForesterUtil.LINE_SEPARATOR );
270             writer.write( my_ind );
271             PhylogenyDataUtil.appendClose( writer, PhyloXmlMapping.BINARY_CHARACTERS_PRESENT );
272         }
273         writer.write( ForesterUtil.LINE_SEPARATOR );
274         writer.write( indentation );
275         PhylogenyDataUtil.appendClose( writer, PhyloXmlMapping.BINARY_CHARACTERS );
276     }
277
278     @Override
279     public String toString() {
280         return asText().toString();
281     }
282
283     private void validate() {
284         if ( ( getPresentCount() != COUNT_DEFAULT ) && ( getPresentCharacters().size() > 0 )
285                 && ( getPresentCount() != getPresentCharacters().size() ) ) {
286             throw new RuntimeException( "present characters size and count are unequal" );
287         }
288         if ( ( getGainedCount() != COUNT_DEFAULT ) && ( getGainedCharacters().size() > 0 )
289                 && ( getGainedCount() != getGainedCharacters().size() ) ) {
290             throw new RuntimeException( "gained characters size and count are unequal" );
291         }
292         if ( ( getLostCount() != COUNT_DEFAULT ) && ( getLostCharacters().size() > 0 )
293                 && ( getLostCount() != getLostCharacters().size() ) ) {
294             throw new RuntimeException( "lost characters size and count are unequal" );
295         }
296     }
297
298     private static String[] sortedSetToStringArray( final SortedSet<String> set ) {
299         final String[] chars = new String[ set.size() ];
300         final Iterator<String> it = set.iterator();
301         int i = 0;
302         while ( it.hasNext() ) {
303             chars[ i++ ] = it.next();
304         }
305         return chars;
306     }
307
308     private static StringBuffer sortedSetToStringBuffer( final SortedSet<String> set, final String separator ) {
309         final StringBuffer sb = new StringBuffer();
310         final Iterator<String> it = set.iterator();
311         while ( it.hasNext() ) {
312             sb.append( it.next() );
313             if ( it.hasNext() ) {
314                 sb.append( separator );
315             }
316         }
317         return sb;
318     }
319 }