1 /* 2 * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import java.text.BreakIterator; 25 import java.text.CharacterIterator; 26 import java.util.ArrayList; 27 import java.util.Collections; 28 import java.util.Iterator; 29 import java.util.List; 30 import java.util.NoSuchElementException; 31 32 public class MirroredBreakIterator extends BreakIterator { 33 private final List<Integer> boundaries; 34 private int charIndex; 35 private int boundaryIndex; 36 MirroredBreakIterator(BreakIterator bi)37 MirroredBreakIterator(BreakIterator bi) { 38 List<Integer> b = new ArrayList<Integer>(); 39 int i = bi.first(); 40 charIndex = i; 41 for (; i != DONE; i = bi.next()) { 42 b.add(i); 43 } 44 boundaries = Collections.unmodifiableList(b); 45 } 46 47 @Override clone()48 public Object clone() { 49 try { 50 return super.clone(); 51 } catch (Exception e) { 52 throw new RuntimeException("clone failed", e); 53 } 54 } 55 56 @Override first()57 public int first() { 58 return changeIndices(0); 59 } 60 61 @Override last()62 public int last() { 63 return changeIndices(boundaries.size() - 1); 64 } 65 66 @Override next(int n)67 public int next(int n) { 68 if (n == 0) { 69 return current(); 70 } 71 int newBoundary = boundaryIndex + n; 72 if (newBoundary < 0) { 73 first(); 74 return DONE; 75 } 76 if (newBoundary > lastBoundary()) { 77 last(); 78 return DONE; 79 } 80 return changeIndices(newBoundary); 81 } 82 83 @Override next()84 public int next() { 85 if (boundaryIndex == lastBoundary()) { 86 return DONE; 87 } 88 return changeIndices(boundaryIndex + 1); 89 } 90 91 @Override previous()92 public int previous() { 93 if (boundaryIndex == 0) { 94 return DONE; 95 } 96 return changeIndices(boundaryIndex - 1); 97 } 98 99 @Override following(int offset)100 public int following(int offset) { 101 validateOffset(offset); 102 for (int b = 0; b <= lastBoundary(); b++) { 103 int i = boundaries.get(b); 104 if (i > offset) { 105 return changeIndices(i, b); 106 } 107 } 108 return DONE; 109 } 110 111 @Override preceding(int offset)112 public int preceding(int offset) { 113 validateOffset(offset); 114 for (int b = lastBoundary(); b >= 0; b--) { 115 int i = boundaries.get(b); 116 if (i < offset) { 117 return changeIndices(i, b); 118 } 119 } 120 return DONE; 121 } 122 123 @Override isBoundary(int offset)124 public boolean isBoundary(int offset) { 125 // Call the default impelementation in BreakIterator 126 return super.isBoundary(offset); 127 } 128 129 @Override current()130 public int current() { 131 return charIndex; 132 } 133 134 @Override getText()135 public CharacterIterator getText() { 136 throw new UnsupportedOperationException(); 137 } 138 139 @Override setText(CharacterIterator newText)140 public void setText(CharacterIterator newText) { 141 throw new UnsupportedOperationException(); 142 } 143 lastBoundary()144 private int lastBoundary() { 145 return boundaries.size() - 1; 146 } 147 changeIndices(int newCharIndex, int newBoundary)148 private int changeIndices(int newCharIndex, int newBoundary) { 149 boundaryIndex = newBoundary; 150 return charIndex = newCharIndex; 151 } 152 changeIndices(int newBoundary)153 private int changeIndices(int newBoundary) { 154 try { 155 return changeIndices(boundaries.get(newBoundary), newBoundary); 156 } catch (IndexOutOfBoundsException e) { 157 throw new IllegalArgumentException(e); 158 } 159 } 160 validateOffset(int offset)161 private void validateOffset(int offset) { 162 if (offset < boundaries.get(0) || offset > boundaries.get(lastBoundary())) { 163 throw new IllegalArgumentException(); 164 } 165 } 166 } 167