001    /*
002     * Copyright 2009 - 2010 JEuclid, http://jeuclid.sf.net
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    /* $Id $ */
018    
019    package net.sourceforge.jeuclid.biparser;
020    
021    import java.util.ArrayList;
022    import java.util.List;
023    
024    import net.sourceforge.jeuclid.elements.JEuclidElementFactory;
025    
026    import org.xml.sax.Attributes;
027    import org.xml.sax.SAXParseException;
028    
029    /**
030     * this class if for creating a BiTree with ABiNodes while parsing a text.
031     * 
032     * @version $Revision: 0b66106c7ff7 $
033     */
034    public class BiTreeCreationHelper {
035    
036        /** current position in tree. */
037        private IBiNode currentBiNode;
038        /** root of tree. */
039        private IBiNode root;
040        /** save positions of open tags. */
041        private final List<Integer> startPositions;
042    
043        /**
044         * create a new BiTreeHelper. get result (tree of ABiNodes) with getRoot()
045         */
046        public BiTreeCreationHelper() {
047            this.startPositions = new ArrayList<Integer>();
048        }
049    
050        /**
051         * get root of BiTree.
052         * 
053         * @return root of BiTree
054         */
055        public final IBiNode getRoot() {
056            return this.root;
057        }
058    
059        /**
060         * create and append a new BiNode at current position in BiTree.
061         * 
062         * @param totalOffset
063         *            of node in text
064         * @param childOffset
065         *            position of first child (length of open tag)
066         * @param namespaceURI
067         *            namespace
068         * @param eName
069         *            name of node
070         * @param attrs
071         *            attributes of node
072         * @throws SAXParseException 
073         *            if the element cannot be recognized by JEuclid.
074         */
075        public final void createBiNode(final int totalOffset,
076                final int childOffset, final String namespaceURI,
077                final String eName, final Attributes attrs) throws SAXParseException {
078    
079            if (JEuclidElementFactory.getJEuclidElementConstructor(namespaceURI,
080                    eName) == null) {
081                throw new NonIncrementalElementException(eName);
082            }
083            BiNode biNode;
084    
085            this.startPositions.add(totalOffset);
086    
087            // new root node
088            if (this.root == null) {
089                this.root = new BiNode(childOffset, namespaceURI, eName, attrs);
090                this.currentBiNode = this.root;
091            } else {
092                biNode = new BiNode(childOffset, namespaceURI, eName, attrs);
093    
094                // append child (only possible at start
095                if (this.currentBiNode.getType() == BiType.EMPTY) {
096                    this.currentBiNode.addSibling(biNode);
097                } else {
098                    // add child (default case)
099                    ((BiNode) this.currentBiNode).addChild(biNode);
100                }
101    
102                this.currentBiNode = biNode;
103            }
104        }
105    
106        /**
107         * close BiNode (set length of node).
108         * 
109         * @param length
110         *            length of node
111         */
112        public final void closeBiNode(final int length) {
113            BiNode parent;
114            final int last = this.startPositions.size() - 1;
115    
116            this.currentBiNode.setLength(length - this.startPositions.get(last));
117    
118            // move current position to parent
119            parent = this.currentBiNode.getParent();
120            if (parent != null) {
121                this.currentBiNode = parent;
122            }
123    
124            this.startPositions.remove(last);
125        }
126    
127        /**
128         * check if current position in BiTree allows a TextNode as child.
129         * 
130         * @return true if a TextNode is allowed
131         */
132        public final boolean allowNewTextNode() {
133            return ((BiNode) this.currentBiNode).getChild() == null;
134        }
135    
136        /**
137         * create a new TextNode at current position.
138         * 
139         * @param length
140         *            length of TextNode
141         * @param t
142         *            text of TextNode
143         */
144        public final void createTextNode(final int length, final String t) {
145            ((BiNode) this.currentBiNode).addChild(new TextNode(length, t));
146        }
147    
148        /**
149         * create a new EmptyNode at current position in BiTree.
150         * 
151         * @param length
152         *            length of EmtpyNode
153         */
154        public final void createEmtpyNode(final int length) {
155            // EmptyNode is new root
156            if (this.root == null) {
157                this.root = new EmptyNode(length);
158                this.currentBiNode = this.root;
159            } else {
160                ((BiNode) this.currentBiNode).addChild(new EmptyNode(length));
161            }
162        }
163    }