// $Id: // FORESTER -- software libraries and applications // for evolutionary biology research and applications. // // Copyright (C) 2008-2009 Christian M. Zmasek // Copyright (C) 2008-2009 Burnham Institute for Medical Research // All rights reserved // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA // // Contact: phylosoft @ gmail . com // WWW: https://sites.google.com/site/cmzmasek/home/software/forester package org.forester.phylogeny.data; import java.io.IOException; import java.io.Writer; import java.util.Iterator; import java.util.SortedSet; import java.util.TreeSet; import org.forester.io.parsers.phyloxml.PhyloXmlMapping; import org.forester.io.writers.PhylogenyWriter; import org.forester.util.ForesterUtil; public class BinaryCharacters implements PhylogenyData { public final static int COUNT_DEFAULT = -1; private final SortedSet _present; private final SortedSet _gained; private final SortedSet _lost; private final int _present_count; private final int _gained_count; private final int _lost_count; private String _type; public BinaryCharacters() { _present = new TreeSet(); _gained = new TreeSet(); _lost = new TreeSet(); _present_count = COUNT_DEFAULT; _gained_count = COUNT_DEFAULT; _lost_count = COUNT_DEFAULT; } public BinaryCharacters( final SortedSet present_characters, final SortedSet gained_characters, final SortedSet lost_characters, final String type ) { _present = present_characters; _gained = gained_characters; _lost = lost_characters; _type = type; _present_count = COUNT_DEFAULT; _gained_count = COUNT_DEFAULT; _lost_count = COUNT_DEFAULT; } public BinaryCharacters( final SortedSet present_characters, final SortedSet gained_characters, final SortedSet lost_characters, final String type, final int present_count, final int gained_count, final int lost_count ) { _present = present_characters; _gained = gained_characters; _lost = lost_characters; _type = type; _present_count = present_count; _gained_count = gained_count; _lost_count = lost_count; validate(); } private void addCharacters( final String indentation, final Writer w, final String[] present ) throws IOException { for( final String string : present ) { PhylogenyDataUtil.appendElement( w, PhyloXmlMapping.BINARY_CHARACTER, string, indentation ); } } public void addGainedCharacter( final String binary_character ) { if ( getLostCharacters().contains( binary_character ) ) { throw new IllegalArgumentException( "attempt to add binary character [" + binary_character + "] to gained characters but is already listed as lost" ); } getGainedCharacters().add( binary_character ); } public void addLostCharacter( final String binary_character ) { if ( getPresentCharacters().contains( binary_character ) ) { throw new IllegalArgumentException( "attempt to add binary character [" + binary_character + "] to lost characters but is already listed as present" ); } if ( getGainedCharacters().contains( binary_character ) ) { throw new IllegalArgumentException( "attempt to add binary character [" + binary_character + "] to lost characters but is already listed as gained" ); } getLostCharacters().add( binary_character ); } public void addPresentCharacter( final String binary_character ) { if ( getLostCharacters().contains( binary_character ) ) { throw new IllegalArgumentException( "attempt to add binary character [" + binary_character + "] to present characters but is already listed as lost" ); } getPresentCharacters().add( binary_character ); } @Override public StringBuffer asSimpleText() { return asText(); } @Override public StringBuffer asText() { validate(); final StringBuffer sb = new StringBuffer(); sb.append( "present [" ); sb.append( getPresentCount() ); sb.append( "]: " ); sb.append( getPresentCharactersAsStringBuffer() ); sb.append( ForesterUtil.LINE_SEPARATOR ); sb.append( "gained [ " ); sb.append( getGainedCount() ); sb.append( "]: " ); sb.append( getGainedCharactersAsStringBuffer() ); sb.append( ForesterUtil.LINE_SEPARATOR ); sb.append( "lost [" ); sb.append( getLostCount() ); sb.append( "]: " ); sb.append( getLostCharactersAsStringBuffer() ); return sb; } @Override /** * Not a deep copy. * */ public PhylogenyData copy() { validate(); return new BinaryCharacters( getPresentCharacters(), getGainedCharacters(), getLostCharacters(), getType(), getPresentCount(), getGainedCount(), getLostCount() ); } public SortedSet getGainedCharacters() { return _gained; } public String[] getGainedCharactersAsStringArray() { return sortedSetToStringArray( getGainedCharacters() ); } public StringBuffer getGainedCharactersAsStringBuffer() { return sortedSetToStringBuffer( getGainedCharacters(), " " ); } public int getGainedCount() { return _gained_count; } public SortedSet getLostCharacters() { return _lost; } public String[] getLostCharactersAsStringArray() { return sortedSetToStringArray( getLostCharacters() ); } public StringBuffer getLostCharactersAsStringBuffer() { return sortedSetToStringBuffer( getLostCharacters(), " " ); } public int getLostCount() { return _lost_count; } public SortedSet getPresentCharacters() { return _present; } public String[] getPresentCharactersAsStringArray() { return sortedSetToStringArray( getPresentCharacters() ); } public StringBuffer getPresentCharactersAsStringBuffer() { return sortedSetToStringBuffer( getPresentCharacters(), " " ); } public int getPresentCount() { return _present_count; } public String getType() { return _type; } @Override public boolean isEqual( final PhylogenyData data ) { throw new UnsupportedOperationException(); } public void setType( final String type ) { _type = type; } @Override public StringBuffer toNHX() { throw new UnsupportedOperationException(); } @Override public void toPhyloXML( final Writer writer, final int level, final String indentation ) throws IOException { validate(); writer.write( ForesterUtil.LINE_SEPARATOR ); writer.write( indentation ); PhylogenyDataUtil.appendOpen( writer, PhyloXmlMapping.BINARY_CHARACTERS, PhyloXmlMapping.BINARY_CHARACTERS_TYPE_ATTR, getType(), PhyloXmlMapping.BINARY_CHARACTERS_GAINED_COUNT_ATTR, getGainedCount() != COUNT_DEFAULT ? String.valueOf( getGainedCount() ) : "", PhyloXmlMapping.BINARY_CHARACTERS_LOST_COUNT_ATTR, getLostCount() != COUNT_DEFAULT ? String.valueOf( getLostCount() ) : "", PhyloXmlMapping.BINARY_CHARACTERS_PRESENT_COUNT_ATTR, getPresentCount() != COUNT_DEFAULT ? String.valueOf( getPresentCount() ) : "" ); final String my_ind = indentation + PhylogenyWriter.PHYLO_XML_INTENDATION_BASE; if ( getGainedCharacters().size() > 0 ) { writer.write( ForesterUtil.LINE_SEPARATOR ); writer.write( my_ind ); PhylogenyDataUtil.appendOpen( writer, PhyloXmlMapping.BINARY_CHARACTERS_GAINED ); addCharacters( my_ind, writer, getGainedCharactersAsStringArray() ); writer.write( ForesterUtil.LINE_SEPARATOR ); writer.write( my_ind ); PhylogenyDataUtil.appendClose( writer, PhyloXmlMapping.BINARY_CHARACTERS_GAINED ); } if ( getLostCharacters().size() > 0 ) { writer.write( ForesterUtil.LINE_SEPARATOR ); writer.write( my_ind ); PhylogenyDataUtil.appendOpen( writer, PhyloXmlMapping.BINARY_CHARACTERS_LOST ); addCharacters( my_ind, writer, getLostCharactersAsStringArray() ); writer.write( ForesterUtil.LINE_SEPARATOR ); writer.write( my_ind ); PhylogenyDataUtil.appendClose( writer, PhyloXmlMapping.BINARY_CHARACTERS_LOST ); } if ( getPresentCharacters().size() > 0 ) { writer.write( ForesterUtil.LINE_SEPARATOR ); writer.write( my_ind ); PhylogenyDataUtil.appendOpen( writer, PhyloXmlMapping.BINARY_CHARACTERS_PRESENT ); addCharacters( my_ind, writer, getPresentCharactersAsStringArray() ); writer.write( ForesterUtil.LINE_SEPARATOR ); writer.write( my_ind ); PhylogenyDataUtil.appendClose( writer, PhyloXmlMapping.BINARY_CHARACTERS_PRESENT ); } writer.write( ForesterUtil.LINE_SEPARATOR ); writer.write( indentation ); PhylogenyDataUtil.appendClose( writer, PhyloXmlMapping.BINARY_CHARACTERS ); } @Override public String toString() { return asText().toString(); } private void validate() { if ( ( getPresentCount() != COUNT_DEFAULT ) && ( getPresentCharacters().size() > 0 ) && ( getPresentCount() != getPresentCharacters().size() ) ) { throw new RuntimeException( "present characters size and count are unequal" ); } if ( ( getGainedCount() != COUNT_DEFAULT ) && ( getGainedCharacters().size() > 0 ) && ( getGainedCount() != getGainedCharacters().size() ) ) { throw new RuntimeException( "gained characters size and count are unequal" ); } if ( ( getLostCount() != COUNT_DEFAULT ) && ( getLostCharacters().size() > 0 ) && ( getLostCount() != getLostCharacters().size() ) ) { throw new RuntimeException( "lost characters size and count are unequal" ); } } private static String[] sortedSetToStringArray( final SortedSet set ) { final String[] chars = new String[ set.size() ]; final Iterator it = set.iterator(); int i = 0; while ( it.hasNext() ) { chars[ i++ ] = it.next(); } return chars; } private static StringBuffer sortedSetToStringBuffer( final SortedSet set, final String separator ) { final StringBuffer sb = new StringBuffer(); final Iterator it = set.iterator(); while ( it.hasNext() ) { sb.append( it.next() ); if ( it.hasNext() ) { sb.append( separator ); } } return sb; } }