(no commit message)
[jalview.git] / forester / java / src / org / forester / io / parsers / nexus / NexusBinaryStatesMatrixParser.java
1 // $Id:
2 // Exp $
3 //
4 // FORESTER -- software libraries and applications
5 // for evolutionary biology research and applications.
6 //
7 // Copyright (C) 2009-2010 Christian M. Zmasek
8 // Copyright (C) 2009-2010 Burnham Institute for Medical Research
9 // All rights reserved
10 //
11 // This library is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU Lesser General Public
13 // License as published by the Free Software Foundation; either
14 // version 2.1 of the License, or (at your option) any later version.
15 //
16 // This library is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 // Lesser General Public License for more details.
20 //
21 // You should have received a copy of the GNU Lesser General Public
22 // License along with this library; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 //
25 // Contact: phylosoft @ gmail . com
26 // WWW: https://sites.google.com/site/cmzmasek/home/software/forester/
27
28 package org.forester.io.parsers.nexus;
29
30 import java.io.BufferedReader;
31 import java.io.IOException;
32
33 import org.forester.evoinference.matrix.character.BasicCharacterStateMatrix;
34 import org.forester.evoinference.matrix.character.CharacterStateMatrix;
35 import org.forester.evoinference.matrix.character.CharacterStateMatrix.BinaryStates;
36 import org.forester.io.parsers.util.ParserUtils;
37 import org.forester.io.parsers.util.PhylogenyParserException;
38
39 public class NexusBinaryStatesMatrixParser {
40
41     private Object                             _nexus_source;
42     private CharacterStateMatrix<BinaryStates> _matrix;
43     private int                                _nchar;
44     private int                                _ntax;
45
46     public CharacterStateMatrix<BinaryStates> getMatrix() {
47         return _matrix;
48     }
49
50     public int getNChar() {
51         return _nchar;
52     }
53
54     private Object getNexusSource() {
55         return _nexus_source;
56     }
57
58     public int getNTax() {
59         return _ntax;
60     }
61
62     public void parse() throws IOException {
63         reset();
64         final BufferedReader reader = ParserUtils.createReader( getNexusSource() );
65         String line;
66         boolean in_matrix = false;
67         int identifier_index = 0;
68         int max_character_index = -1;
69         while ( ( line = reader.readLine() ) != null ) {
70             line = line.trim();
71             if ( ( line.length() > 0 ) && !line.startsWith( "#" ) && !line.startsWith( ">" ) ) {
72                 if ( line.toLowerCase().indexOf( NexusConstants.NCHAR.toLowerCase() ) >= 0 ) {
73                     final int i = line.toLowerCase().indexOf( NexusConstants.NCHAR.toLowerCase() );
74                     String s = line.toLowerCase().substring( i + 6 );
75                     s = s.replace( ';', ' ' ).trim();
76                     setNChar( Integer.parseInt( s ) );
77                 }
78                 else if ( line.toLowerCase().indexOf( NexusConstants.NTAX.toLowerCase() ) >= 0 ) {
79                     final int i = line.toLowerCase().indexOf( NexusConstants.NTAX.toLowerCase() );
80                     String s = line.toLowerCase().substring( i + 5 );
81                     s = s.replace( ';', ' ' ).trim();
82                     setNTax( Integer.parseInt( s ) );
83                 }
84                 else if ( line.toLowerCase().startsWith( NexusConstants.MATRIX.toLowerCase() ) ) {
85                     in_matrix = true;
86                     if ( getNTax() < 1 ) {
87                         throw new NexusFormatException( "did not encounter " + NexusConstants.NTAX );
88                     }
89                     if ( getNChar() < 1 ) {
90                         throw new NexusFormatException( "did not encounter " + NexusConstants.NCHAR );
91                     }
92                     if ( getMatrix() != null ) {
93                         throw new NexusFormatException( "more than one matrix present" );
94                     }
95                     setMatrix( new BasicCharacterStateMatrix<BinaryStates>( getNTax(), getNChar() ) );
96                 }
97                 else if ( line.toLowerCase().startsWith( NexusConstants.END.toLowerCase() ) ) {
98                     in_matrix = false;
99                 }
100                 else if ( in_matrix ) {
101                     final String[] line_ary = line.split( "\\s+" );
102                     final String label = line_ary[ 0 ].trim();
103                     String states_str = line_ary[ 1 ].trim();
104                     if ( states_str.endsWith( ";" ) ) {
105                         in_matrix = false;
106                         states_str = states_str.substring( 0, states_str.length() - 1 );
107                     }
108                     final char[] states = states_str.toCharArray();
109                     getMatrix().setIdentifier( identifier_index, label );
110                     int character_index = 0;
111                     for( final char state : states ) {
112                         if ( state == BinaryStates.PRESENT.toChar() ) {
113                             try {
114                                 getMatrix().setState( identifier_index, character_index, BinaryStates.PRESENT );
115                             }
116                             catch ( final ArrayIndexOutOfBoundsException ex ) {
117                                 throw new NexusFormatException( "problem at line " + line + " [" + ex + "]" );
118                             }
119                         }
120                         else if ( state == BinaryStates.ABSENT.toChar() ) {
121                             try {
122                                 getMatrix().setState( identifier_index, character_index, BinaryStates.ABSENT );
123                             }
124                             catch ( final ArrayIndexOutOfBoundsException ex ) {
125                                 throw new NexusFormatException( "problem at line " + line + " [" + ex + "]" );
126                             }
127                         }
128                         else {
129                             throw new NexusFormatException( "illegal state " + state );
130                         }
131                         ++character_index;
132                     }
133                     if ( ( max_character_index > 0 ) && ( max_character_index != character_index ) ) {
134                         throw new NexusFormatException( "unequal number of characters at line " + line );
135                     }
136                     max_character_index = character_index;
137                     ++identifier_index;
138                 }
139             }
140         }
141     }
142
143     private void reset() {
144         setMatrix( null );
145         setNChar( -1 );
146         setNTax( -1 );
147     }
148
149     private void setMatrix( final CharacterStateMatrix<BinaryStates> matrix ) {
150         _matrix = matrix;
151     }
152
153     private void setNChar( final int nchar ) {
154         _nchar = nchar;
155     }
156
157     private void setNTax( final int ntax ) {
158         _ntax = ntax;
159     }
160
161     public void setSource( final Object nexus_source ) throws PhylogenyParserException, IOException {
162         if ( nexus_source == null ) {
163             throw new PhylogenyParserException( getClass() + ": attempt to parse null object." );
164         }
165         _nexus_source = nexus_source;
166     }
167 }