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 java.io.IOException;
024import java.io.Writer;
025import java.util.ArrayList;
026import java.util.Iterator;
027import java.util.List;
028
029import org.biojava.bio.seq.io.ParseException;
030
031/**
032 * Builds a Nexus file by listening to events.
033 * 
034 * @author Richard Holland
035 * @author Tobias Thierer
036 * @author Jim Balhoff
037 * @since 1.6
038 */
039public class NexusFileBuilder extends NexusFileListener.Abstract {
040
041        private NexusFile file;
042
043        private NexusComment comment;
044
045        public void setDefaultBlockParsers() {
046                this.setBlockParser(NexusBlockParser.UNKNOWN_BLOCK,
047                                new UnknownBlockParser());
048                this.setBlockParser(TaxaBlock.TAXA_BLOCK, new TaxaBlockParser(
049                                new TaxaBlockBuilder()));
050                this.setBlockParser(TreesBlock.TREES_BLOCK, new TreesBlockParser(
051                                new TreesBlockBuilder()));
052                this.setBlockParser(CharactersBlock.CHARACTERS_BLOCK,
053                                new CharactersBlockParser(new CharactersBlockBuilder()));
054                this.setBlockParser(DataBlock.DATA_BLOCK, new DataBlockParser(
055                                new DataBlockBuilder()));
056                this.setBlockParser(DistancesBlock.DISTANCES_BLOCK,
057                                new DistancesBlockParser(new DistancesBlockBuilder()));
058        }
059
060        protected void blockEnded(final NexusBlockParser blockParser) {
061                final NexusBlockListener listener = blockParser.getBlockListener();
062                if (listener instanceof NexusBlockBuilder)
063                        file.addObject(((NexusBlockBuilder) listener).getNexusBlock());
064        }
065
066        public void startFile() {
067                this.file = new NexusFile();
068        }
069
070        public void endFile() {
071                // We don't care.
072        }
073
074        /**
075         * Obtain the constructed file.
076         * 
077         * @return the constructed file.
078         */
079        public NexusFile getNexusFile() {
080                return this.file;
081        }
082
083        public void beginFileComment() {
084                if (this.comment != null)
085                        this.comment.openSubComment();
086                else
087                        this.comment = new NexusComment();
088        }
089
090        public void fileCommentText(String comment) {
091                this.comment.addCommentText(comment);
092        }
093
094        public void endFileComment() {
095                if (this.comment != null && this.comment.hasOpenSubComment())
096                        this.comment.closeSubComment();
097                else {
098                        this.file.addObject(this.comment);
099                        this.comment = null;
100                }
101        }
102
103        // This class builds unknown blocks by remembering all tokens and
104        // comments in the order they were received, and writing them out
105        // again in that order when requested.
106        private static class UnknownBlockParser extends NexusBlockParser.Abstract {
107                private UnknownBlockParser() {
108                        super(new UnknownBlockBuilder());
109                }
110
111                public void resetStatus() {
112                        // Ignore.
113                }
114
115                public boolean wantsBracketsAndBraces() {
116                        return false;
117                }
118
119                public void parseToken(final String token) throws ParseException {
120                        ((UnknownBlockBuilder) this.getBlockListener()).getComponents()
121                                        .add(token);
122                }
123
124                private static class UnknownBlockBuilder extends
125                                NexusBlockBuilder.Abstract {
126
127                        private UnknownBlock block;
128
129                        private List getComponents() {
130                                return this.block.getComponents();
131                        }
132
133                        public void endTokenGroup() {
134                                // Only write not-first, as we also receive the one
135                                // from after the BEGIN statement.
136                                if (this.getComponents().size() > 0)
137                                        this.getComponents().add(";");
138                        }
139
140                        public boolean wantsBracketsAndBraces() {
141                                return false;
142                        }
143
144                        public void endBlock() {
145                                // We don't care.
146                        }
147
148                        public void addComment(NexusComment comment) {
149                                this.getComponents().add(comment);
150                        }
151
152                        public NexusBlock startBlockObject() {
153                                this.block = new UnknownBlock(this.getBlockName());
154                                return this.block;
155                        }
156
157                        // Holds unknown block data.
158                        private static class UnknownBlock extends NexusBlock.Abstract {
159
160                                private List components = new ArrayList();
161
162                                private UnknownBlock(String blockName) {
163                                        super(blockName);
164                                }
165
166                                private List getComponents() {
167                                        return this.components;
168                                }
169
170                                public void writeBlockContents(final Writer writer)
171                                                throws IOException {
172                                        for (final Iterator i = this.components.iterator(); i
173                                                        .hasNext();) {
174                                                final Object obj = (Object) i.next();
175                                                if (obj instanceof NexusComment)
176                                                        ((NexusComment) obj).writeObject(writer);
177                                                else
178                                                        this.writeToken(writer, (String) obj);
179                                        }
180                                }
181                        }
182                }
183        }
184}