initial commit
[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     public StringBuffer asSimpleText() {
100         final StringBuffer sb = new StringBuffer();
101         for( int i = 0; i < getDomains().size(); ++i ) {
102             if ( i > 0 ) {
103                 sb.append( "~" );
104             }
105             sb.append( getDomain( i ).asSimpleText() );
106         }
107         return sb;
108     }
109
110     public StringBuffer asText() {
111         final StringBuffer sb = new StringBuffer();
112         for( int i = 0; i < getDomains().size(); ++i ) {
113             if ( i > 0 ) {
114                 sb.append( "~" );
115             }
116             sb.append( getDomain( i ).asText() );
117         }
118         return sb;
119     }
120
121     public PhylogenyData copy() {
122         final List<PhylogenyData> domains = new ArrayList<PhylogenyData>( getDomains().size() );
123         for( int i = 0; i < getDomains().size(); ++i ) {
124             domains.add( getDomain( i ).copy() );
125         }
126         return new DomainArchitecture( domains, getTotalLength() );
127     }
128
129     public ProteinDomain getDomain( final int i ) {
130         return ( ProteinDomain ) _domains.values().toArray()[ i ];
131     }
132
133     public SortedMap<Double, ProteinDomain> getDomains() {
134         return _domains;
135     }
136
137     public int getNumberOfDomains() {
138         return _domains.size();
139     }
140
141     public int getTotalLength() {
142         return _total_length;
143     }
144
145     private void init() {
146         _domains = new TreeMap<Double, ProteinDomain>();
147         _total_length = 0;
148     }
149
150     /**
151      * Returns true if the names and the order of the domains match (domain and
152      * linker lengths are ignored).
153      * 
154      * 
155      */
156     public boolean isEqual( final PhylogenyData domain_architecture ) {
157         if ( domain_architecture == null ) {
158             return false;
159         }
160         if ( !( domain_architecture instanceof DomainArchitecture ) ) {
161             return false;
162         }
163         final DomainArchitecture d = ( DomainArchitecture ) domain_architecture;
164         if ( getDomains().size() != d.getDomains().size() ) {
165             return false;
166         }
167         for( int i = 0; i < getDomains().size(); ++i ) {
168             if ( !getDomain( i ).getName().equals( d.getDomain( i ).getName() ) ) {
169                 return false;
170             }
171         }
172         return true;
173     }
174
175     public void setTotalLength( final int total_length ) {
176         _total_length = total_length;
177     }
178
179     public StringBuffer toNHX() {
180         final StringBuffer sb = new StringBuffer();
181         sb.append( ":" );
182         sb.append( NHXtags.DOMAIN_STRUCTURE );
183         sb.append( getTotalLength() );
184         if ( getDomains() != null ) {
185             for( int i = 0; i < getDomains().size(); ++i ) {
186                 sb.append( DomainArchitecture.NHX_SEPARATOR );
187                 sb.append( getDomain( i ).getFrom() );
188                 sb.append( DomainArchitecture.NHX_SEPARATOR );
189                 sb.append( getDomain( i ).getTo() );
190                 sb.append( DomainArchitecture.NHX_SEPARATOR );
191                 sb.append( getDomain( i ).getConfidence() );
192                 sb.append( DomainArchitecture.NHX_SEPARATOR );
193                 sb.append( ForesterUtil.replaceIllegalNhxCharacters( getDomain( i ).getName() ) );
194             }
195         }
196         return sb;
197     }
198
199     public void toPhyloXML( final Writer writer, final int level, final String indentation ) throws IOException {
200         writer.write( ForesterUtil.LINE_SEPARATOR );
201         writer.write( indentation );
202         PhylogenyDataUtil.appendOpen( writer,
203                                       PhyloXmlMapping.SEQUENCE_DOMAIN_ARCHITECURE,
204                                       PhyloXmlMapping.SEQUENCE_DOMAIN_ARCHITECTURE_LENGTH,
205                                       getTotalLength() + "" );
206         if ( getDomains() != null ) {
207             final String ind = indentation + PhylogenyWriter.PHYLO_XML_INTENDATION_BASE;
208             for( int i = 0; i < getDomains().size(); ++i ) {
209                 getDomain( i ).toPhyloXML( writer, level, ind );
210             }
211         }
212         writer.write( ForesterUtil.LINE_SEPARATOR );
213         writer.write( indentation );
214         PhylogenyDataUtil.appendClose( writer, PhyloXmlMapping.SEQUENCE_DOMAIN_ARCHITECURE );
215     }
216
217     @Override
218     public String toString() {
219         return asText().toString();
220     }
221 }