001    /*
002     * Copyright (c) 2007 Henri Sivonen
003     *
004     * Permission is hereby granted, free of charge, to any person obtaining a 
005     * copy of this software and associated documentation files (the "Software"), 
006     * to deal in the Software without restriction, including without limitation 
007     * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
008     * and/or sell copies of the Software, and to permit persons to whom the 
009     * Software is furnished to do so, subject to the following conditions:
010     *
011     * The above copyright notice and this permission notice shall be included in 
012     * all copies or substantial portions of the Software.
013     *
014     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
015     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
016     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
017     * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
018     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
019     * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
020     * DEALINGS IN THE SOFTWARE.
021     */
022    
023    package nu.validator.saxtree;
024    
025    import org.xml.sax.Locator;
026    
027    public abstract class ParentNode extends Node {
028    
029        protected Locator endLocator;
030        
031        private Node firstChild = null;
032        
033        private Node lastChild = null;
034        
035        ParentNode(Locator locator) {
036            super(locator);
037        }
038    
039        /**
040         * Sets the endLocator.
041         * 
042         * @param endLocator the endLocator to set
043         */
044        public void setEndLocator(Locator endLocator) {
045            this.endLocator = new LocatorImpl(endLocator);
046        }
047    
048        /**
049         * Copies the endLocator from another node.
050         * 
051         * @param another the another node
052         */
053        public void copyEndLocator(ParentNode another) {
054            this.endLocator = another.endLocator;
055        }
056        
057        /**
058         * Returns the firstChild.
059         * 
060         * @return the firstChild
061         */
062        public final Node getFirstChild() {
063            return firstChild;
064        }
065    
066        /**
067         * Returns the lastChild.
068         * 
069         * @return the lastChild
070         */
071        public final Node getLastChild() {
072            return lastChild;
073        }
074    
075        public Node insertBefore(Node child, Node sibling) {
076            assert sibling == null || this == sibling.getParentNode();
077            if (sibling == null) {
078                return appendChild(child);
079            }
080            child.detach();
081            child.setParentNode(this);
082            if (firstChild == sibling) {
083                child.setNextSibling(sibling);
084                firstChild = child;
085            } else {
086                Node prev = firstChild;
087                Node next = firstChild.getNextSibling();
088                while (next != sibling) {
089                    prev = next;
090                    next = next.getNextSibling();
091                }
092                prev.setNextSibling(child);
093                child.setNextSibling(next);
094            }
095            return child;
096        }
097        
098        public Node appendChild(Node child) {
099            child.detach();
100            child.setParentNode(this);
101            if (firstChild == null) {
102                firstChild = child;
103            } else {
104                lastChild.setNextSibling(child);
105            }
106            lastChild = child;
107            return child;
108        }
109        
110        public void appendChildren(Node parent) {
111            Node child = parent.getFirstChild();
112            if (child == null) {
113                return;
114            }
115            ParentNode another = (ParentNode) parent;
116            if (firstChild == null) {
117                firstChild = child;
118            } else {
119                lastChild.setNextSibling(child);
120            }
121            lastChild = another.lastChild;
122            do {
123                child.setParentNode(this);
124            } while ((child = child.getNextSibling()) != null);
125            another.firstChild = null;
126            another.lastChild = null;
127        }
128    
129        void removeChild(Node node) {
130            assert this == node.getParentNode();
131            if (firstChild == node) {
132                firstChild = node.getNextSibling();
133                if (lastChild == node) {
134                    lastChild = null;
135                }
136            } else {
137                Node prev = firstChild;
138                Node next = firstChild.getNextSibling();
139                while (next != node) {
140                    prev = next;
141                    next = next.getNextSibling();
142                }
143                prev.setNextSibling(node.getNextSibling());
144                if (lastChild == node) {
145                    lastChild = prev;
146                }            
147            }
148        }
149    }