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.Node;
022    
023    /**
024     * this class is used to store typical information about a xml-node.
025     * 
026     * @version $Revision: 0b66106c7ff7 $
027     * 
028     */
029    public abstract class AbstractBiNode implements IBiNode {
030    
031        /** previous node, null if node is root. */
032        private IBiNode previous;
033    
034        /** sibling node, can be null. */
035        private IBiNode sibling;
036    
037        /** reference to node in DOM-tree. */
038        private Node node;
039    
040        /** length of node in characters. */
041        private int length;
042    
043        /**
044         * get previous node, null if node is root.
045         * 
046         * @return previous
047         */
048        public final IBiNode getPrevious() {
049            return this.previous;
050        }
051    
052        /**
053         * set previous for this node.
054         * 
055         * @param prev
056         *            previous node for this node
057         */
058        public final void setPrevious(final IBiNode prev) {
059            this.previous = prev;
060        }
061    
062        /**
063         * get parent node for this node.
064         * 
065         * @return parent
066         */
067        public final BiNode getParent() {
068            // check if previous isn't a "real parent"
069            if (this.previous != null && this.previous.getSibling() == this) {
070                return this.previous.getParent();
071            } else {
072                // previous is "real parent" or null
073                return (BiNode) this.previous;
074            }
075        }
076    
077        /**
078         * get sibling node, can be null.
079         * 
080         * @return sibling
081         */
082        public final IBiNode getSibling() {
083            return this.sibling;
084        }
085    
086        /**
087         * set sibling for this node and set previous of sibling to this.
088         * 
089         * @param sibl
090         *            new sibling for this node
091         */
092        public final void setSibling(final IBiNode sibl) {
093            if (sibl != null) {
094                sibl.setPrevious(this);
095            }
096    
097            this.sibling = sibl;
098        }
099    
100        /**
101         * add sibling to a node, not possible at a textnode. if node already has a
102         * sibling, forward to sibling.
103         * 
104         * @param sibl
105         *            new sibling for this node
106         */
107        public final void addSibling(final IBiNode sibl) {
108            if (this.sibling == null) {
109                // 2nd child
110                this.setSibling(sibl);
111            } else {
112                // forward(3rd - nth child)
113                this.sibling.addSibling(sibl);
114            }
115        }
116    
117        /**
118         * get reference to node in DOM-tree.
119         * 
120         * @return node in DOM-tree
121         */
122        public final Node getNode() {
123            return this.node;
124        }
125    
126        /**
127         * set reference to node in DOM-tree.
128         * 
129         * @param n
130         *            reference in DOM-tree
131         */
132        public final void setNode(final Node n) {
133            this.node = n;
134        }
135    
136        /**
137         * get length of node (number of characters).
138         * 
139         * @return length of node
140         */
141        public final int getLength() {
142            return this.length;
143        }
144    
145        /**
146         * set length of node.
147         * 
148         * @param len
149         *            to set
150         */
151        public final void setLength(final int len) {
152            this.length = len;
153        }
154    
155        /**
156         * change length of node and recursive of all parents.
157         * 
158         * @param change
159         *            changevalue (can be positive or negative)
160         */
161        public final void changeLengthRec(final int change) {
162            if (change == 0) {
163                return;
164            }
165    
166            this.length += change;
167    
168            if (this.getParent() != null) {
169                this.getParent().changeLengthRec(change);
170            }
171        }
172    
173        /**
174         * helper method to insert or remove characters.
175         * 
176         * @param insert
177         *            if true call insert-method else remove-method
178         * @param biTree
179         *            reference to BiTree to which this node contains
180         * @param offset
181         *            position to insert/remove characters
182         * @param len
183         *            number of characters to insert/remove
184         * @param totalOffset
185         *            offset of node to begin of text
186         * @throws ReparseException
187         *             if a reparse at upper level is needed
188         * @throws NonIncrementalElementException
189         *             if the subtree contains an element which cannot be
190         *             incrementally updated.
191         */
192        public void forwardToSibling(final boolean insert, final BiTree biTree,
193                final int offset, final int len, final int totalOffset)
194                throws ReparseException, NonIncrementalElementException {
195    
196            if (this.getSibling() == null) {
197                // reparsing
198                throw new ReparseException();
199            } else {
200                if (insert) {
201                    this.getSibling().insert(biTree, offset, len, totalOffset);
202                } else {
203                    this.getSibling().remove(biTree, offset, len, totalOffset);
204                }
205            }
206        }
207    
208        /**
209         * search a DOM node in this node. if nodes are equal return offset to begin
210         * of inputtext, else null
211         * 
212         * @param n
213         *            DOM node to search for
214         * @param totalOffset
215         *            offset of node to begin of inputtext
216         * @return position of node in inputtext
217         */
218        public TextPosition searchNode(final Node n, final int totalOffset) {
219            if (this.node != null && this.node.equals(n)) {
220                return new TextPosition(totalOffset, this.length);
221            }
222    
223            return null;
224        }
225    
226        /**
227         * helper method for outputting the length of node.
228         * 
229         * @return formatted output of length
230         */
231        public String formatLength() {
232            int i;
233            final int max = 3;
234            final StringBuffer sb = new StringBuffer();
235    
236            for (i = 1; i <= max && 1 > this.getLength() / Math.pow(10, max - i); i++) {
237    
238                if (i == 1 && this.getLength() == 0) {
239                    continue;
240                }
241                sb.append(' ');
242            }
243    
244            sb.append(this.length);
245    
246            return sb.toString();
247        }
248    }