| AbstractKeyList.java |
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: AbstractKeyList.java 2110 2011-03-08 13:55:32Z dmsmith $
21 */
22 package org.crosswire.jsword.passage;
23
24 import java.util.Iterator;
25
26 /**
27 * An implementation of some of the easier methods from Key.
28 *
29 * @see gnu.lgpl.License for license details.<br>
30 * The copyright to this program is held by it's authors.
31 * @author Joe Walker [joe at eireneh dot com]
32 */
33 public abstract class AbstractKeyList implements Key {
34 /**
35 * Build an AbstractKeyList with the given name.
36 *
37 * @param name
38 */
39 protected AbstractKeyList(String name) {
40 this.name = name;
41 }
42
43 /* (non-Javadoc)
44 * @see org.crosswire.jsword.passage.Key#isEmpty()
45 */
46 public boolean isEmpty() {
47 return getCardinality() == 0;
48 }
49
50 /* (non-Javadoc)
51 * @see org.crosswire.jsword.passage.Key#contains(org.crosswire.jsword.passage.Key)
52 */
53 public boolean contains(Key key) {
54 return indexOf(key) >= 0;
55 }
56
57 /* (non-Javadoc)
58 * @see org.crosswire.jsword.passage.Key#retainAll(org.crosswire.jsword.passage.Key)
59 */
60 public void retainAll(Key key) {
61 Key shared = new DefaultKeyList();
62 shared.addAll(key);
63 retain(this, shared);
64 }
65
66 /**
67 * Utility to remove all the keys from alter that are not in base
68 *
69 * @param alter
70 * The key to remove keys from
71 * @param base
72 * The check key
73 */
74 protected static void retain(Key alter, Key base) {
75 Iterator<Key> it = alter.iterator();
76 while (it.hasNext()) {
77 Key sublist = it.next();
78 if (sublist.canHaveChildren()) {
79 retain(sublist, base);
80 if (sublist.isEmpty()) {
81 it.remove();
82 }
83 } else {
84 if (!base.contains(sublist)) {
85 it.remove();
86 }
87 }
88 }
89 }
90
91 @Override
92 public String toString() {
93 return getName();
94 }
95
96 /**
97 * Override the default name with a custom name. If the name is null then a
98 * name will be generated by concatenating the names of all the elements of
99 * this node.
100 */
101 public void setName(String name) {
102 this.name = name;
103 }
104
105 /* (non-Javadoc)
106 * @see org.crosswire.jsword.passage.Key#getName()
107 */
108 public String getName() {
109 if (name != null) {
110 return name;
111 }
112
113 DefaultKeyVisitor visitor = new NameVisitor();
114 KeyUtil.visit(this, visitor);
115 return visitor.toString();
116 }
117
118 /* (non-Javadoc)
119 * @see org.crosswire.jsword.passage.Key#getName(org.crosswire.jsword.passage.Key)
120 */
121 public String getName(Key base) {
122 return getName();
123 }
124
125 /* (non-Javadoc)
126 * @see org.crosswire.jsword.passage.Key#getRootName()
127 */
128 public String getRootName() {
129 return getName();
130 }
131
132 /* (non-Javadoc)
133 * @see org.crosswire.jsword.passage.Key#getOsisRef()
134 */
135 public String getOsisRef() {
136 DefaultKeyVisitor visitor = new OsisRefVisitor();
137 KeyUtil.visit(this, visitor);
138 return visitor.toString();
139 }
140
141 /* (non-Javadoc)
142 * @see org.crosswire.jsword.passage.Key#getOsisID()
143 */
144 public String getOsisID() {
145 DefaultKeyVisitor visitor = new OsisIDVisitor();
146 KeyUtil.visit(this, visitor);
147 return visitor.toString();
148 }
149
150 @Override
151 public boolean equals(Object obj) {
152 // Since this can not be null
153 if (obj == null) {
154 return false;
155 }
156
157 // Check that that is the same as this
158 // Don't use instanceOf since that breaks inheritance
159 if (!obj.getClass().equals(this.getClass())) {
160 return false;
161 }
162
163 return compareTo((Key) obj) == 0;
164 }
165
166 @Override
167 public int hashCode() {
168 return getName().hashCode();
169 }
170
171 /* (non-Javadoc)
172 * @see java.lang.Comparable#compareTo(java.lang.Object)
173 */
174 public int compareTo(Key that) {
175
176 if (this == that) {
177 return 0;
178 }
179
180 if (that == null) {
181 // he is empty, we are not so he is greater
182 return -1;
183 }
184
185 int ret = this.getName().compareTo(that.getName());
186
187 if (ret != 0) {
188 return ret;
189 }
190
191 // Compare the contents.
192 Iterator<Key> thisIter = this.iterator();
193 Iterator<Key> thatIter = that.iterator();
194
195 Key thisfirst = null;
196 Key thatfirst = null;
197
198 if (thisIter.hasNext()) {
199 thisfirst = thisIter.next();
200 }
201
202 if (thatIter.hasNext()) {
203 thatfirst = thatIter.next();
204 }
205
206 if (thisfirst == null) {
207 if (thatfirst == null) {
208 // we are both empty, and rank the same
209 return 0;
210 }
211 // i am empty, he is not so we are greater
212 return 1;
213 }
214
215 if (thatfirst == null) {
216 // he is empty, we are not so he is greater
217 return -1;
218 }
219
220 return thisfirst.getName().compareTo(thatfirst.getName());
221 }
222
223 @Override
224 public AbstractKeyList clone() {
225 AbstractKeyList clone = null;
226 try {
227 clone = (AbstractKeyList) super.clone();
228 } catch (CloneNotSupportedException e) {
229 assert false : e;
230 }
231 return clone;
232 }
233
234 /**
235 * The <code>NameVisitor</code> constructs a readable representation of the
236 * Passage.
237 */
238 static class NameVisitor extends DefaultKeyVisitor {
239 /**
240 * Create a <code>NameVisitor</code>.
241 */
242 public NameVisitor() {
243 buffer = new StringBuilder();
244 }
245
246 @Override
247 public void visitLeaf(Key key) {
248 buffer.append(key.getName());
249 buffer.append(AbstractPassage.REF_PREF_DELIM);
250 }
251
252 @Override
253 public String toString() {
254 String reply = buffer.toString();
255 if (reply.length() > 0) {
256 // strip off the final ", "
257 reply = reply.substring(0, reply.length() - AbstractPassage.REF_PREF_DELIM.length());
258 }
259
260 return reply;
261 }
262
263 protected StringBuilder buffer;
264 }
265
266 /**
267 * The <code>OsisRefVisitor</code> constructs a readable representation of
268 * the Passage, using OSIS names.
269 */
270 static class OsisRefVisitor extends NameVisitor {
271 @Override
272 public void visitLeaf(Key key) {
273 buffer.append(key.getOsisRef());
274 buffer.append(AbstractPassage.REF_PREF_DELIM);
275 }
276 }
277
278 /**
279 * The <code>OsisRefVisitor</code> constructs a readable representation of
280 * the Passage, using OSIS names.
281 */
282 static class OsisIDVisitor extends NameVisitor {
283 @Override
284 public void visitLeaf(Key key) {
285 buffer.append(key.getOsisID());
286 buffer.append(AbstractPassage.REF_OSIS_DELIM);
287 }
288
289 @Override
290 public String toString() {
291 String reply = super.toString();
292 if (reply.length() > 0) {
293 // strip off the final " "
294 reply = reply.substring(0, reply.length() - AbstractPassage.REF_OSIS_DELIM.length());
295 }
296
297 return reply;
298 }
299 }
300
301 /**
302 * The common user visible name for this work
303 */
304 private String name;
305
306 /**
307 * Serialization ID
308 */
309 private static final long serialVersionUID = 3858640507828137034L;
310 }
311