1   /**
2    * Distribution License:
3    * JSword is free software; you can redistribute it and/or modify it under
4    * the terms of the GNU Lesser General Public License, version 2.1 as published by
5    * the Free Software Foundation. This program is distributed in the hope
6    * that it will be useful, but WITHOUT ANY WARRANTY; without even the
7    * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8    * See the GNU Lesser General Public License for more details.
9    *
10   * The License is available on the internet at:
11   *       http://www.gnu.org/copyleft/lgpl.html
12   * or by writing to:
13   *      Free Software Foundation, Inc.
14   *      59 Temple Place - Suite 330
15   *      Boston, MA 02111-1307, USA
16   *
17   * Copyright: 2005
18   *     The copyright to this program is held by it's authors.
19   *
20   * ID: $Id: KeyIterator.java 2050 2010-12-09 15:31:45Z dmsmith $
21   */
22  package org.crosswire.jsword.passage;
23  
24  import java.util.Iterator;
25  import java.util.NoSuchElementException;
26  import java.util.Stack;
27  
28  /**
29   * This KeyIterator performs a depth first iteration over the subkeys in the
30   * key.
31   * 
32   * @see gnu.lgpl.License for license details.<br>
33   *      The copyright to this program is held by it's authors.
34   * @author DM Smith [dmsmith555 at yahoo dot com]
35   */
36  public class KeyIterator implements Iterator<Key> {
37      public KeyIterator(Key key) {
38          stack = new Stack<Locator>();
39          stack.push(new Locator(key));
40      }
41  
42      protected void prepare() {
43          // If there is nothing on the stack we have nothing to do.
44          if (stack.size() == 0) {
45              return;
46          }
47  
48          // Check to see if there are more children to process
49          Locator peek = stack.peek();
50  
51          if (peek.getParent().getChildCount() > peek.getPosition()) {
52              return;
53          }
54  
55          // There are no more so we are done with this Locator.
56          stack.pop();
57  
58          // Try the next
59          prepare();
60      }
61  
62      public boolean hasNext() {
63          prepare();
64          return stack.size() != 0;
65      }
66  
67      public Key next() {
68          if (!hasNext()) {
69              throw new NoSuchElementException();
70          }
71  
72          Locator peek = stack.peek();
73  
74          // Determine which child in the list of children to consider
75          int childNum = peek.getPosition();
76  
77          // Advance to the next potential child
78          peek.setPosition(childNum + 1);
79  
80          // If we have exhausted all the children,
81          // then return the parent key
82          if (childNum == -1) {
83              return peek.getParent();
84          }
85  
86          stack.push(new Locator(peek.getParent().get(childNum)));
87  
88          return next();
89      }
90  
91      public void remove() {
92          throw new UnsupportedOperationException();
93      }
94  
95      /**
96       * A helper class that remembers where we've been and where we are.
97       */
98      public static class Locator {
99          private Key parent;
100         private int position;
101 
102         public Locator(Key parent) {
103             this.parent = parent;
104             this.position = -1;
105         }
106 
107         /**
108          * @return the parent
109          */
110         public Key getParent() {
111             return parent;
112         }
113 
114         /**
115          * @param parent
116          *            the parent to set
117          */
118         public void setParent(Key parent) {
119             this.parent = parent;
120         }
121 
122         /**
123          * @return the position
124          */
125         public int getPosition() {
126             return position;
127         }
128 
129         /**
130          * @param position
131          *            the position to set
132          */
133         public void setPosition(int position) {
134             this.position = position;
135         }
136 
137     }
138 
139     private Stack<Locator> stack;
140 }
141