1   package org.crosswire.jsword.passage;
2   
3   /**
4    * Distribution License:
5    * JSword is free software; you can redistribute it and/or modify it under
6    * the terms of the GNU Lesser General Public License, version 2.1 as published by
7    * the Free Software Foundation. This program is distributed in the hope
8    * that it will be useful, but WITHOUT ANY WARRANTY; without even the
9    * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10   * See the GNU Lesser General Public License for more details.
11   *
12   * The License is available on the internet at:
13   *       http://www.gnu.org/copyleft/lgpl.html
14   * or by writing to:
15   *      Free Software Foundation, Inc.
16   *      59 Temple Place - Suite 330
17   *      Boston, MA 02111-1307, USA
18   *
19   * Copyright: 2005
20   *     The copyright to this program is held by it's authors.
21   *
22   * ID: $Id: TreeKey.java 2114 2011-03-12 16:35:31Z dmsmith $
23   */
24  import java.util.ArrayList;
25  import java.util.Iterator;
26  import java.util.List;
27  
28  import org.crosswire.common.util.Logger;
29  
30  /**
31   * A Key that knows where the data is in the real file.
32   * 
33   * @see gnu.lgpl.License for license details.<br>
34   *      The copyright to this program is held by it's authors.
35   * @author DM Smith [dmsmith555 at yahoo dot com]
36   */
37  public class TreeKey extends AbstractKeyList {
38      /**
39       * Setup with the key name and positions of data in the file
40       */
41      public TreeKey(String name, Key parent) {
42          super(name);
43          this.parent = parent;
44          this.children = new ArrayList<Key>();
45      }
46  
47      /**
48       * Setup with the key name. Use solely for searching.
49       */
50      public TreeKey(String text) {
51          this(text, null);
52      }
53  
54      /* (non-Javadoc)
55       * @see org.crosswire.jsword.passage.Key#canHaveChildren()
56       */
57      public boolean canHaveChildren() {
58          return true;
59      }
60  
61      /* (non-Javadoc)
62       * @see org.crosswire.jsword.passage.Key#getChildCount()
63       */
64      public int getChildCount() {
65          return children.size();
66      }
67  
68      /* (non-Javadoc)
69       * @see org.crosswire.jsword.passage.Key#getCardinality()
70       */
71      public int getCardinality() {
72          int cardinality = 1; // count this node
73          for (Key child : children) {
74              cardinality += child.getCardinality();
75          }
76  
77          return cardinality;
78      }
79  
80      @Override
81      public boolean isEmpty() {
82          return children.isEmpty();
83      }
84  
85      @Override
86      public boolean contains(Key key) {
87          if (children.contains(key)) {
88              return true;
89          }
90  
91          for (Key child : children) {
92              if (child.contains(key)) {
93                  return true;
94              }
95          }
96  
97          return false;
98      }
99  
100     /* (non-Javadoc)
101      * @see java.lang.Iterable#iterator()
102      */
103     public Iterator<Key> iterator() {
104         return new KeyIterator(this);
105     }
106 
107     /* (non-Javadoc)
108      * @see org.crosswire.jsword.passage.Key#addAll(org.crosswire.jsword.passage.Key)
109      */
110     public void addAll(Key key) {
111         children.add(key);
112     }
113 
114     /* (non-Javadoc)
115      * @see org.crosswire.jsword.passage.Key#removeAll(org.crosswire.jsword.passage.Key)
116      */
117     public void removeAll(Key key) {
118         children.remove(key);
119     }
120 
121     /* (non-Javadoc)
122      * @see org.crosswire.jsword.passage.Key#clear()
123      */
124     public void clear() {
125         children.clear();
126     }
127 
128     /* (non-Javadoc)
129      * @see org.crosswire.jsword.passage.Key#get(int)
130      */
131     public Key get(int index) {
132         return children.get(index);
133     }
134 
135     /* (non-Javadoc)
136      * @see org.crosswire.jsword.passage.Key#indexOf(org.crosswire.jsword.passage.Key)
137      */
138     public int indexOf(Key that) {
139         return children.indexOf(that);
140     }
141 
142     /* (non-Javadoc)
143      * @see org.crosswire.jsword.passage.Key#getParent()
144      */
145     public Key getParent() {
146         return parent;
147     }
148 
149     /* (non-Javadoc)
150      * @see org.crosswire.jsword.passage.Key#blur(int, org.crosswire.jsword.passage.RestrictionType)
151      */
152     public void blur(int by, RestrictionType restrict) {
153         log.warn("attempt to blur a non-blur-able list");
154     }
155 
156     @Override
157     public TreeKey clone() {
158         return (TreeKey) super.clone();
159     }
160 
161     @Override
162     public String getRootName() {
163         String rootName = getName();
164         for (Key parentKey = this; parentKey != null && parentKey.getName().length() > 0; parentKey = parentKey.getParent()) {
165             rootName = parentKey.getName();
166         }
167         return rootName;
168     }
169 
170     @Override
171     public String getOsisRef() {
172         return getOsisID();
173     }
174 
175     @Override
176     public String getOsisID() {
177         StringBuilder b = new StringBuilder(100);
178         b.append(osisify(getName()));
179         for (Key parentKey = this.getParent(); parentKey != null && parentKey.getName().length() > 0; parentKey = parentKey.getParent()) {
180             b.insert(0, ".");
181             b.insert(0, osisify(parentKey.getName()));
182         }
183         // Remove the leading .
184         return b.toString();
185     }
186 
187     private String osisify(String str) {
188         // FIXME(DMS): An osisID cannot have lots of stuff that a name can have.
189         // It can only have _, a-z, A-Z, 0-9.
190         // Need to normalize the name by
191         // replacing ' ' with '_'
192         // Stripping punctuation, accents, ...
193         // ...
194         return str.replace(' ', '_');
195     }
196 
197     /**
198      * The parent of this key.
199      */
200     private Key parent;
201 
202     /**
203      * The immediate children of this tree node.
204      */
205     private List<Key> children;
206 
207     /**
208      * Serialization ID
209      */
210     private static final long serialVersionUID = -6560408145705717977L;
211 
212     /**
213      * The log stream
214      */
215     private static final Logger log = Logger.getLogger(TreeKey.class);
216 }
217