001/*
002 *                    BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 */
021package org.biojavax.bio.phylo.io.nexus;
022
023import org.biojava.bio.seq.io.ParseException;
024import org.biojavax.bio.phylo.io.nexus.TreesBlock.NewickTreeString;
025
026/**
027 * Parses Nexus taxa blocks.
028 * 
029 * @author Richard Holland
030 * @author Tobias Thierer
031 * @author Jim Balhoff
032 * @author Tiago Antao
033 * @since 1.6
034 */
035public class TreesBlockParser extends NexusBlockParser.Abstract {
036
037        public void beginComment() {
038                if (!this.expectingTreeRooted)
039                        super.beginComment();
040        }
041
042        public void commentText(String comment) throws ParseException {
043                if (this.expectingTreeRooted)
044                        this.currentTreeRoot.append(comment);
045                else
046                        super.commentText(comment);
047        }
048
049        public void endComment() {
050                if (!this.expectingTreeRooted)
051                        super.endComment();
052        }
053
054        private boolean expectingTranslate;
055
056        private boolean expectingTaxLabel;
057
058        private boolean expectingTaxName;
059
060        private boolean expectingTree;
061
062        private boolean expectingTreeName;
063
064        private boolean expectingTreeEquals;
065
066        private boolean expectingTreeContent;
067
068        private boolean expectingTreeRooted;
069
070        private String currentTaxLabel;
071
072        private String currentTreeName;
073
074        private boolean currentTreeStarred;
075
076        private StringBuffer currentTreeRoot = new StringBuffer();
077
078        private StringBuffer currentTreeContent = new StringBuffer();
079
080        /**
081         * Delegates to NexusBlockParser.Abstract.
082         * 
083         * @param blockListener
084         *            the listener to send parse events to.
085         */
086        public TreesBlockParser(TreesBlockListener blockListener) {
087                super(blockListener);
088        }
089
090        public void resetStatus() {
091                this.expectingTranslate = true;
092                this.expectingTaxLabel = false;
093                this.expectingTaxName = false;
094                this.expectingTree = true;
095                this.expectingTreeName = false;
096                this.expectingTreeEquals = false;
097                this.expectingTreeRooted = false;
098                this.expectingTreeContent = false;
099                this.currentTaxLabel = null;
100                this.currentTreeStarred = false;
101                this.currentTreeName = null;
102                this.currentTreeRoot.setLength(0);
103                this.currentTreeContent.setLength(0);
104        }
105
106        public void parseToken(String token) throws ParseException {
107                if (token.trim().length() == 0) {
108                        return;
109                }
110                if ( token != null) {
111                        if (this.expectingTaxLabel == true && "tree".equalsIgnoreCase(token)) {
112                                this.expectingTaxLabel = false;
113                                this.expectingTree = true;
114                        }
115                }
116                if (this.expectingTranslate && "TRANSLATE".equalsIgnoreCase(token)) {
117                        this.expectingTranslate = false;
118                        this.expectingTaxLabel = true;
119                        this.expectingTree = false;
120                } else if (this.expectingTaxLabel) {
121                        this.currentTaxLabel = token; // In case it includes spaces.
122                        this.expectingTaxLabel = false;
123                        this.expectingTaxName = true;
124                } else if (this.expectingTaxName) {
125                        final boolean endsWithComma = token.endsWith(",");
126                        final String taxName = endsWithComma ? token.substring(0, token
127                                        .length() - 1) : token;
128                        ((TreesBlockListener) this.getBlockListener()).addTranslation(
129                                        this.currentTaxLabel, taxName);
130                        this.expectingTaxName = false;
131                        if (!endsWithComma) {
132                                this.expectingTree = true;
133                        } else {
134                                this.expectingTaxLabel = true;
135                        }
136                } else if (this.expectingTree && "TREE".equalsIgnoreCase(token)) {
137                        this.expectingTree = false;
138                        this.expectingTreeName = true;
139                } else if (this.expectingTreeName) {
140                        if ("*".equals(token))
141                                this.currentTreeStarred = true;
142                        else {
143                                this.expectingTreeName = false;
144                                if (token.indexOf("=") >= 0) {
145                                        final String parts[] = token.split("=");
146                                        this.currentTreeName = parts[0];
147                                        if (parts.length > 1) {
148                                                this.currentTreeContent.append(token);
149                                                this.expectingTreeRooted = false;
150                                        }
151                                        this.expectingTreeContent = true;
152                                } else {
153                                        this.currentTreeName = token;
154                                        this.expectingTreeEquals = true;
155                                }
156                        }
157                } else if (this.expectingTreeEquals && token.startsWith("=")) {
158                        this.expectingTreeEquals = false;
159                        final String parts[] = token.split("=");
160                        if (parts.length > 1) {
161                                this.currentTreeContent.append(parts[1]);
162                                this.expectingTreeRooted = false;
163                        } else
164                                this.expectingTreeRooted = true;
165                        this.expectingTreeContent = true;
166                } else if (this.expectingTreeContent) {
167                        this.currentTreeContent.append(token); // In case it includes
168                        // spaces.
169                        this.expectingTreeRooted = false;
170                } else
171                        throw new ParseException("Found unexpected token " + token
172                                        + " in TREES block");
173        }
174
175        public void endTokenGroup() {
176                if (this.expectingTreeContent) {
177                        final NewickTreeString tree = new NewickTreeString();
178                        tree.setRootType(this.currentTreeRoot.toString());
179                        tree.setTreeString(this.currentTreeContent.toString());
180                        tree.setStarred(this.currentTreeStarred);
181                        ((TreesBlockListener) this.getBlockListener()).addTree(
182                                        this.currentTreeName, tree);
183                        this.currentTreeContent.setLength(0);
184                        this.currentTreeName = null;
185                        this.currentTreeRoot.setLength(0);
186                        this.currentTreeStarred = false;
187                        this.expectingTreeRooted = false;
188                        this.expectingTreeContent = false;
189                        this.expectingTree = true;
190                } else
191                        super.endTokenGroup();
192        }
193
194}