1/*
2 * Copyright (C) 2007 Esmertec AG.
3 * Copyright (C) 2007 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package com.android.mms.dom;
19
20import java.util.ArrayList;
21
22import org.w3c.dom.Node;
23import org.w3c.dom.NodeList;
24
25public class NodeListImpl implements NodeList {
26    private ArrayList<Node> mSearchNodes;
27    private ArrayList<Node> mStaticNodes;
28    private Node mRootNode;
29    private String mTagName;
30    private boolean mDeepSearch;
31
32    /*
33     * Internal Interface
34     */
35
36    /**
37     * Constructs a NodeList by searching for all descendants or the direct
38     * children of a root node with a given tag name.
39     * @param rootNode The root <code>Node</code> of the search.
40     * @param tagName The tag name to be searched for. If null, all descendants
41     *              will be returned.
42     * @param deep Limit the search to the direct children of rootNode if false,
43     *              to all descendants otherwise.
44     */
45    public NodeListImpl(Node rootNode, String tagName, boolean deepSearch) {
46        mRootNode = rootNode;
47        mTagName  = tagName;
48        mDeepSearch = deepSearch;
49    }
50
51    /**
52     * Constructs a NodeList for a given static node list.
53     * @param nodes The static node list.
54     */
55    public NodeListImpl(ArrayList<Node> nodes) {
56        mStaticNodes = nodes;
57    }
58
59    /*
60     * NodeListImpl Interface
61     */
62
63    public int getLength() {
64        if (mStaticNodes == null) {
65            fillList(mRootNode);
66            return mSearchNodes.size();
67        } else {
68            return mStaticNodes.size();
69        }
70    }
71
72    public Node item(int index) {
73        Node node = null;
74        if (mStaticNodes == null) {
75            fillList(mRootNode);
76            try {
77                node = mSearchNodes.get(index);
78            } catch (IndexOutOfBoundsException e) {
79                // Do nothing and return null
80            }
81        } else {
82            try {
83                node = mStaticNodes.get(index);
84            } catch (IndexOutOfBoundsException e) {
85                // Do nothing and return null
86            }
87        }
88        return node;
89    }
90
91    /**
92     * A preorder traversal is done in the following order:
93     * <ul>
94     *   <li> Visit root.
95     *   <li> Traverse children from left to right in preorder.
96     * </ul>
97     * This method fills the live node list.
98     * @param The root of preorder traversal
99     * @return The next match
100     */
101    private void fillList(Node node) {
102        // (Re)-initialize the container if this is the start of the search.
103        // Visit the root of this iteration otherwise.
104        if (node == mRootNode) {
105            mSearchNodes = new ArrayList<Node>();
106        } else {
107            if ((mTagName == null) || node.getNodeName().equals(mTagName)) {
108                mSearchNodes.add(node);
109            }
110        }
111
112        // Descend one generation...
113        node = node.getFirstChild();
114
115        // ...and visit in preorder the children if we are in deep search
116        // or directly add the children to the list otherwise.
117        while (node != null) {
118            if (mDeepSearch) {
119                fillList(node);
120            } else {
121                if ((mTagName == null) || node.getNodeName().equals(mTagName)) {
122                    mSearchNodes.add(node);
123                }
124            }
125            node = node.getNextSibling();
126        }
127    }
128}
129