1
20 package org.crosswire.jsword.passage;
21
22 import java.io.IOException;
23 import java.io.ObjectInputStream;
24 import java.io.ObjectOutputStream;
25 import java.util.Iterator;
26 import java.util.NoSuchElementException;
27 import java.util.Set;
28 import java.util.TreeSet;
29
30 import org.crosswire.jsword.versification.Versification;
31
32
57 public class RangedPassage extends AbstractPassage {
58
65 public RangedPassage(Versification refSystem) {
66 super(refSystem);
67 store = new TreeSet<VerseRange>();
68 }
69
70
89 protected RangedPassage(Versification v11n, String refs, Key basis) throws NoSuchVerseException {
90 super(v11n, refs);
91
92 store = new TreeSet<VerseRange>();
93 addVerses(refs, basis);
94 normalize();
95 }
96
97 protected RangedPassage(Versification v11n, String refs) throws NoSuchVerseException {
98 this(v11n, refs, null);
99 }
100
101 @Override
102 public RangedPassage clone() {
103 RangedPassage copy = (RangedPassage) super.clone();
105
106 copy.store = new TreeSet<VerseRange>();
111 copy.store.addAll(store);
112
113 return copy;
114 }
115
116 @Override
117 public int countRanges(RestrictionType restrict) {
118 if (restrict.equals(RestrictionType.NONE)) {
119 return store.size();
120 }
121
122 return super.countRanges(restrict);
123 }
124
125 @Override
126 public int countVerses() {
127 Iterator<VerseRange> it = rangeIterator(RestrictionType.NONE);
128 int count = 0;
129
130 while (it.hasNext()) {
131 VerseRange range = it.next();
132 count += range.getCardinality();
133 }
134
135 return count;
136 }
137
138
141 public Iterator<Key> iterator() {
142 return new VerseIterator(getVersification(), rangeIterator(RestrictionType.NONE));
143 }
144
145 @Override
146 public final Iterator<VerseRange> rangeIterator(RestrictionType restrict) {
147 if (restrict.equals(RestrictionType.NONE)) {
148 return store.iterator();
149 }
150
151 return new VerseRangeIterator(store.iterator(), restrict);
152 }
153
154 @Override
155 public boolean isEmpty() {
156 return store.isEmpty();
157 }
158
159 @Override
160 public boolean contains(Key obj) {
161
165 VerseRange thatRange = toVerseRange(getVersification(), obj);
166
167 Iterator<VerseRange> it = rangeIterator(RestrictionType.NONE);
168 while (it.hasNext()) {
169 VerseRange thisRange = it.next();
170 if (thisRange.contains(thatRange)) {
171 return true;
172 }
173 }
174
175 return false;
178 }
179
180
183 public void add(Key obj) {
184 optimizeWrites();
185
186 VerseRange thatRange = toVerseRange(getVersification(), obj);
187 store.add(thatRange);
188
189 normalize();
190
191 if (suppressEvents == 0) {
194 fireIntervalAdded(this, thatRange.getStart(), thatRange.getEnd());
195 }
196 }
197
198 @Override
199 public void clear() {
200 optimizeWrites();
201
202 store.clear();
203 fireIntervalRemoved(this, null, null);
204 }
205
206
209 public void remove(Key obj) {
210 optimizeWrites();
211
212 VerseRange thatRange = toVerseRange(getVersification(), obj);
213 boolean removed = false;
214
215 Set<Key> newStore = new TreeSet<Key>();
217 newStore.addAll(store);
218
219 for (Key aKey : newStore) {
221 VerseRange thisRange = (VerseRange) aKey;
223 if (thisRange.overlaps(thatRange)) {
224 store.remove(thisRange);
226 VerseRange[] vra = VerseRange.remainder(thisRange, thatRange);
227
228 for (int i = 0; i < vra.length; i++) {
229 store.add(vra[i]);
230 }
231
232 removed = true;
233 }
234 }
235
236 if (removed) {
237 normalize();
238 }
239
240 if (suppressEvents == 0) {
243 fireIntervalRemoved(this, thatRange.getStart(), thatRange.getEnd());
244 }
245 }
246
247 @Override
248 public void retainAll(Key key) {
249 optimizeWrites();
250
251 Set<VerseRange> newStore = new TreeSet<VerseRange>();
252
253 if (key instanceof RangedPassage) {
254 Iterator<VerseRange> thatIter = ((RangedPassage) key).rangeIterator(RestrictionType.CHAPTER);
255 while (thatIter.hasNext()) {
256 VerseRange thatRange = thatIter.next();
257
258 Iterator<VerseRange> thisIter = rangeIterator(RestrictionType.NONE);
260 while (thisIter.hasNext()) {
261 VerseRange thisRange = thisIter.next();
263 if (thisRange.overlaps(thatRange)) {
264 VerseRange interstect = VerseRange.intersection(thisRange, thatRange);
266 if (interstect != null) {
267 newStore.add(interstect);
268 }
269 }
270 }
271 }
272 } else {
273 Iterator<Key> thatIter = key.iterator();
274 while (thatIter.hasNext()) {
275 VerseRange thatRange = toVerseRange(getVersification(), thatIter.next());
276
277 Iterator<VerseRange> thisIter = rangeIterator(RestrictionType.NONE);
279 while (thisIter.hasNext()) {
280 VerseRange thisRange = thisIter.next();
282 if (thisRange.overlaps(thatRange)) {
283 VerseRange interstect = VerseRange.intersection(thisRange, thatRange);
285 if (interstect != null) {
286 newStore.add(interstect);
287 }
288 }
289 }
290 }
291 }
292
293
294 store = newStore;
295 normalize();
296
297 fireIntervalRemoved(this, null, null);
298 }
299
300
308 @Override
309 final void normalize() {
310 if (skipNormalization != 0) {
311 return;
312 }
313
314 VerseRange last = null;
315 VerseRange next = null;
316 Set<VerseRange> newStore = new TreeSet<VerseRange>();
317
318 Iterator<VerseRange> it = rangeIterator(RestrictionType.NONE);
319 while (it.hasNext()) {
320 next = it.next();
321
322 if (last != null && next.adjacentTo(last)) {
323 VerseRange merge = new VerseRange(last, next);
324
325 newStore.remove(last);
326 newStore.add(merge);
327
328 last = merge;
329 } else {
330 newStore.add(next);
331 last = next;
332 }
333 }
334
335 store = newStore;
336 }
337
338
347 private static final class VerseIterator implements Iterator<Key> {
348
355 protected VerseIterator(Versification v11n, Iterator<VerseRange> it) {
356 Set<Key> temp = new TreeSet<Key>();
357
358 while (it.hasNext()) {
359 VerseRange range = it.next();
360 int start = range.getStart().getOrdinal();
361 int end = range.getCardinality();
362
363 for (int i = 0; i < end; i++) {
364 temp.add(v11n.decodeOrdinal(start + i));
365 }
366 }
367
368 real = temp.iterator();
369 }
370
371
374 public boolean hasNext() {
375 return real.hasNext();
376 }
377
378
381 public Key next() throws NoSuchElementException {
382 return real.next();
383 }
384
385
388 public void remove() throws UnsupportedOperationException {
389 throw new UnsupportedOperationException();
390 }
391
392
395 private Iterator<Key> real;
396 }
397
398
401 private static final class VerseRangeIterator implements Iterator<VerseRange> {
402
407 protected VerseRangeIterator(Iterator<VerseRange> it, RestrictionType restrict) {
408 this.restrict = restrict;
409 this.real = it;
410 }
411
412
415 public void remove() {
416 throw new UnsupportedOperationException();
417 }
418
419
422 public boolean hasNext() {
423 return next != null || real.hasNext();
424 }
425
426
429 public VerseRange next() {
430 if (next == null) {
431 next = real.next();
432 }
433
434 if (next == null) {
435 throw new NoSuchElementException();
436 }
437
438 if (restrict.isSameScope(next.getVersification(), next.getStart(), next.getEnd())) {
441 return replyNext();
442 }
443 return splitNext();
444 }
445
446
449 private VerseRange replyNext() {
450 VerseRange reply = next;
451 next = null;
452 return reply;
453 }
454
455
458 private VerseRange splitNext() {
459 Iterator<VerseRange> chop = next.rangeIterator(restrict);
460 VerseRange first = chop.next();
461 VerseRange[] ranges = VerseRange.remainder(next, first);
462
463 assert ranges.length == 1;
464 next = ranges[0];
465
466 return first;
467 }
468
469
472 private VerseRange next;
473
474
477 private RestrictionType restrict;
478
479
482 private Iterator<VerseRange> real;
483 }
484
485
495 private void writeObject(ObjectOutputStream out) throws IOException {
496 out.defaultWriteObject();
497
498 writeObjectSupport(out);
499 }
500
501
513 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
514 optimizeWrites();
515
516 store = new TreeSet<VerseRange>();
517
518 in.defaultReadObject();
519
520 readObjectSupport(in);
521 }
522
523
526 private static final long serialVersionUID = 955115811339960826L;
527
528
531 private transient Set<VerseRange> store;
532 }
533