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 org.w3c.dom.Document;
022    import org.w3c.dom.Node;
023    
024    /**
025     * this class is used to store specific information about a empty node. the node
026     * cannot have children, but a sibling
027     * 
028     * @version $Revision: 0b66106c7ff7 $
029     */
030    public final class EmptyNode extends AbstractBiNode {
031    
032        /**
033         * create a new EmptyNode.
034         * 
035         * @param length
036         *            of EmptyNode
037         */
038        public EmptyNode(final int length) {
039            this.setLength(length);
040        }
041    
042        /**
043         * get the type of node.
044         * 
045         * @return EMPTY
046         */
047        public BiType getType() {
048            return BiType.EMPTY;
049        }
050    
051    /**
052         * insert characters in EmptyNode, reparse if characters contain '<' or '>'.
053         * else change length of EmptyNode
054         * {@inheritDoc}
055         */
056        public void insert(final BiTree biTree, final int offset, final int length,
057                final int totalOffset) throws ReparseException,
058                NonIncrementalElementException {
059            int position;
060            String insert;
061    
062            // System.out.println("insert " + toString() + " offset=" +
063            // offset + " length=" + length);
064    
065            // start position in this node
066            if (offset <= this.getLength()) {
067    
068                position = totalOffset + offset;
069                insert = biTree.getText().substring(position, position + length);
070    
071                if (insert.contains("<") || insert.contains(">")) {
072                    // reparsing
073                    throw new ReparseException();
074                }
075    
076                this.changeLengthRec(length);
077    
078            } else {
079                // start position outside this node
080                this.forwardToSibling(true, biTree, offset - this.getLength(),
081                        length, totalOffset + this.getLength());
082            }
083        }
084    
085        /**
086         * remove characters from EmptyNode, reparse if length gets 0. {@inheritDoc}
087         */
088        public void remove(final BiTree biTree, final int offset, final int length,
089                final int totalOffset) throws ReparseException,
090                NonIncrementalElementException {
091            // System.out.println("remove " + toString() + " offset=" +
092            // offset + " length=" + length);
093    
094            // start position in this node
095            if (offset <= this.getLength()) {
096    
097                if (offset == 0 && length >= this.getLength()) {
098                    // remove this node
099                    throw new ReparseException();
100    
101                } else {
102                    // change length
103                    // end position in this node
104                    if (offset + length <= this.getLength()) {
105                        this.changeLengthRec(-length);
106    
107                    } else {
108                        // end position outside this node
109                        this.changeLengthRec(offset - this.getLength());
110    
111                        // forward remainder to sibling
112                        this.forwardToSibling(false, biTree, 0, offset + length
113                                - this.getLength(), totalOffset + this.getLength());
114                    }
115                }
116            } else {
117                // start position outside this node
118                this.forwardToSibling(false, biTree, offset - this.getLength(),
119                        length, totalOffset + this.getLength());
120            }
121        }
122    
123        /**
124         * don't create a DOM-tree from EmptyNode (EmptyNode has no DOM node).
125         * 
126         * @param doc
127         *            Document to create DOM-tree
128         * @return null
129         */
130        public Node createDOMSubtree(final Document doc) {
131            return null;
132        }
133    
134        /** {@inheritDoc} */
135        @Override
136        public TextPosition searchNode(final Node node, final int totalOffset) {
137            // forward to sibling
138            if (this.getSibling() != null) {
139                return this.getSibling().searchNode(node,
140                        totalOffset + this.getLength());
141            }
142    
143            return null;
144        }
145    
146        @Override
147        public String toString() {
148            final StringBuffer sb = new StringBuffer(32);
149    
150            sb.append("[EMTPY length: ");
151            sb.append(this.getLength());
152            sb.append(']');
153    
154            return sb.toString();
155        }
156    
157        /** {@inheritDoc} */
158        public String toString(final int level) {
159            final StringBuffer sb = new StringBuffer(32);
160            final String nl = System.getProperty("line.separator");
161    
162            sb.append(this.formatLength());
163            sb.append(':');
164            for (int i = 0; i <= level; i++) {
165                sb.append(' ');
166            }
167    
168            sb.append("EMTPY");
169    
170            if (this.getSibling() != null) {
171                sb.append(nl);
172                sb.append(this.getSibling().toString(level));
173            }
174    
175            return sb.toString();
176        }
177    }