clean up
[jalview.git] / forester / java / src / org / forester / phylogeny / data / DomainArchitecture.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.ArrayList;
31 import java.util.List;
32 import java.util.SortedMap;
33 import java.util.StringTokenizer;
34 import java.util.TreeMap;
35
36 import org.forester.io.parsers.nhx.NHXtags;
37 import org.forester.io.parsers.phyloxml.PhyloXmlMapping;
38 import org.forester.io.writers.PhylogenyWriter;
39 import org.forester.util.ForesterUtil;
40
41 public class DomainArchitecture implements PhylogenyData {
42
43     public final static String               NHX_SEPARATOR = ">";
44     private static final double              INCREASE_KEY  = 0.0001;
45     private SortedMap<Double, ProteinDomain> _domains;
46     private int                              _total_length;
47
48     public DomainArchitecture() {
49         init();
50     }
51
52     public DomainArchitecture( final List<PhylogenyData> domains, final int total_length ) {
53         init();
54         for( final PhylogenyData phylogenyData : domains ) {
55             final ProteinDomain pd = ( ProteinDomain ) phylogenyData;
56             addDomain( pd );
57         }
58         _total_length = total_length;
59     }
60
61     public DomainArchitecture( final String da_str ) {
62         init();
63         int total_length = 0;
64         int to = -1;
65         try {
66             final StringTokenizer st = new StringTokenizer( da_str, DomainArchitecture.NHX_SEPARATOR );
67             final String length_str = ( String ) st.nextElement();
68             total_length = new Integer( length_str ).intValue();
69             while ( st.hasMoreElements() ) {
70                 final String from_str = ( String ) st.nextElement();
71                 final String to_str = ( String ) st.nextElement();
72                 final String support_str = ( String ) st.nextElement();
73                 final String name = ( String ) st.nextElement();
74                 to = new Integer( to_str ).intValue();
75                 final int from = new Integer( from_str ).intValue();
76                 final double support = new Double( support_str ).doubleValue();
77                 final ProteinDomain pd = new ProteinDomain( name, from, to, support );
78                 addDomain( pd );
79             }
80         }
81         catch ( final Exception e ) {
82             throw new IllegalArgumentException( "Malformed format for domain structure \"" + da_str + "\": "
83                     + e.getMessage() );
84         }
85         if ( to > total_length ) {
86             throw new IllegalArgumentException( "total length of domain structure is too short" );
87         }
88         _total_length = total_length;
89     }
90
91     public void addDomain( final ProteinDomain pd ) {
92         Double key = new Double( pd.getFrom() );
93         while ( _domains.containsKey( key ) ) {
94             key = new Double( key.doubleValue() + DomainArchitecture.INCREASE_KEY );
95         }
96         _domains.put( key, pd );
97     }
98
99     @Override
100     public StringBuffer asSimpleText() {
101         final StringBuffer sb = new StringBuffer();
102         for( int i = 0; i < getDomains().size(); ++i ) {
103             if ( i > 0 ) {
104                 sb.append( "~" );
105             }
106             sb.append( getDomain( i ).asSimpleText() );
107         }
108         return sb;
109     }
110
111     @Override
112     public StringBuffer asText() {
113         final StringBuffer sb = new StringBuffer();
114         for( int i = 0; i < getDomains().size(); ++i ) {
115             if ( i > 0 ) {
116                 sb.append( "~" );
117             }
118             sb.append( getDomain( i ).asText() );
119         }
120         return sb;
121     }
122
123     @Override
124     public PhylogenyData copy() {
125         final List<PhylogenyData> domains = new ArrayList<PhylogenyData>( getDomains().size() );
126         for( int i = 0; i < getDomains().size(); ++i ) {
127             domains.add( getDomain( i ).copy() );
128         }
129         return new DomainArchitecture( domains, getTotalLength() );
130     }
131
132     public ProteinDomain getDomain( final int i ) {
133         return ( ProteinDomain ) _domains.values().toArray()[ i ];
134     }
135
136     public SortedMap<Double, ProteinDomain> getDomains() {
137         return _domains;
138     }
139
140     public int getNumberOfDomains() {
141         return _domains.size();
142     }
143
144     public int getTotalLength() {
145         return _total_length;
146     }
147
148     private void init() {
149         _domains = new TreeMap<Double, ProteinDomain>();
150         _total_length = 0;
151     }
152
153     /**
154      * Returns true if the names and the order of the domains match (domain and
155      * linker lengths are ignored).
156      * 
157      * 
158      */
159     @Override
160     public boolean isEqual( final PhylogenyData domain_architecture ) {
161         if ( domain_architecture == null ) {
162             return false;
163         }
164         if ( !( domain_architecture instanceof DomainArchitecture ) ) {
165             return false;
166         }
167         final DomainArchitecture d = ( DomainArchitecture ) domain_architecture;
168         if ( getDomains().size() != d.getDomains().size() ) {
169             return false;
170         }
171         for( int i = 0; i < getDomains().size(); ++i ) {
172             if ( !getDomain( i ).getName().equals( d.getDomain( i ).getName() ) ) {
173                 return false;
174             }
175         }
176         return true;
177     }
178
179     public void setTotalLength( final int total_length ) {
180         _total_length = total_length;
181     }
182
183     @Override
184     public StringBuffer toNHX() {
185         final StringBuffer sb = new StringBuffer();
186         sb.append( ":" );
187         sb.append( NHXtags.DOMAIN_STRUCTURE );
188         sb.append( getTotalLength() );
189         if ( getDomains() != null ) {
190             for( int i = 0; i < getDomains().size(); ++i ) {
191                 sb.append( DomainArchitecture.NHX_SEPARATOR );
192                 sb.append( getDomain( i ).getFrom() );
193                 sb.append( DomainArchitecture.NHX_SEPARATOR );
194                 sb.append( getDomain( i ).getTo() );
195                 sb.append( DomainArchitecture.NHX_SEPARATOR );
196                 sb.append( getDomain( i ).getConfidence() );
197                 sb.append( DomainArchitecture.NHX_SEPARATOR );
198                 sb.append( ForesterUtil.replaceIllegalNhxCharacters( getDomain( i ).getName() ) );
199             }
200         }
201         return sb;
202     }
203
204     @Override
205     public void toPhyloXML( final Writer writer, final int level, final String indentation ) throws IOException {
206         writer.write( ForesterUtil.LINE_SEPARATOR );
207         writer.write( indentation );
208         PhylogenyDataUtil.appendOpen( writer,
209                                       PhyloXmlMapping.SEQUENCE_DOMAIN_ARCHITECURE,
210                                       PhyloXmlMapping.SEQUENCE_DOMAIN_ARCHITECTURE_LENGTH,
211                                       getTotalLength() + "" );
212         if ( getDomains() != null ) {
213             final String ind = indentation + PhylogenyWriter.PHYLO_XML_INTENDATION_BASE;
214             for( int i = 0; i < getDomains().size(); ++i ) {
215                 getDomain( i ).toPhyloXML( writer, level, ind );
216             }
217         }
218         writer.write( ForesterUtil.LINE_SEPARATOR );
219         writer.write( indentation );
220         PhylogenyDataUtil.appendClose( writer, PhyloXmlMapping.SEQUENCE_DOMAIN_ARCHITECURE );
221     }
222
223     @Override
224     public String toString() {
225         return asText().toString();
226     }
227 }