1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package java.text;
19
20/**
21 * An implementation of {@link CharacterIterator} for strings.
22 */
23public final class StringCharacterIterator implements CharacterIterator {
24
25    String string;
26
27    int start, end, offset;
28
29    /**
30     * Constructs a new {@code StringCharacterIterator} on the specified string.
31     * The begin and current indices are set to the beginning of the string, the
32     * end index is set to the length of the string.
33     *
34     * @param value
35     *            the source string to iterate over.
36     */
37    public StringCharacterIterator(String value) {
38        string = value;
39        start = offset = 0;
40        end = string.length();
41    }
42
43    /**
44     * Constructs a new {@code StringCharacterIterator} on the specified string
45     * with the current index set to the specified value. The begin index is set
46     * to the beginning of the string, the end index is set to the length of the
47     * string.
48     *
49     * @param value
50     *            the source string to iterate over.
51     * @param location
52     *            the current index.
53     * @throws IllegalArgumentException
54     *            if {@code location} is negative or greater than the length
55     *            of the source string.
56     */
57    public StringCharacterIterator(String value, int location) {
58        string = value;
59        start = 0;
60        end = string.length();
61        if (location < 0 || location > end) {
62            throw new IllegalArgumentException();
63        }
64        offset = location;
65    }
66
67    /**
68     * Constructs a new {@code StringCharacterIterator} on the specified string
69     * with the begin, end and current index set to the specified values.
70     *
71     * @param value
72     *            the source string to iterate over.
73     * @param start
74     *            the index of the first character to iterate.
75     * @param end
76     *            the index one past the last character to iterate.
77     * @param location
78     *            the current index.
79     * @throws IllegalArgumentException
80     *            if {@code start < 0}, {@code start > end}, {@code location <
81     *            start}, {@code location > end} or if {@code end} is greater
82     *            than the length of {@code value}.
83     */
84    public StringCharacterIterator(String value, int start, int end, int location) {
85        string = value;
86        if (start < 0 || end > string.length() || start > end
87                || location < start || location > end) {
88            throw new IllegalArgumentException();
89        }
90        this.start = start;
91        this.end = end;
92        offset = location;
93    }
94
95    /**
96     * Returns a new {@code StringCharacterIterator} with the same source
97     * string, begin, end, and current index as this iterator.
98     *
99     * @return a shallow copy of this iterator.
100     * @see java.lang.Cloneable
101     */
102    @Override
103    public Object clone() {
104        try {
105            return super.clone();
106        } catch (CloneNotSupportedException e) {
107            throw new AssertionError(e);
108        }
109    }
110
111    /**
112     * Returns the character at the current index in the source string.
113     *
114     * @return the current character, or {@code DONE} if the current index is
115     *         past the end.
116     */
117    public char current() {
118        if (offset == end) {
119            return DONE;
120        }
121        return string.charAt(offset);
122    }
123
124    /**
125     * Compares the specified object with this {@code StringCharacterIterator}
126     * and indicates if they are equal. In order to be equal, {@code object}
127     * must be an instance of {@code StringCharacterIterator} that iterates over
128     * the same sequence of characters with the same index.
129     *
130     * @param object
131     *            the object to compare with this object.
132     * @return {@code true} if the specified object is equal to this
133     *         {@code StringCharacterIterator}; {@code false} otherwise.
134     * @see #hashCode
135     */
136    @Override
137    public boolean equals(Object object) {
138        if (!(object instanceof StringCharacterIterator)) {
139            return false;
140        }
141        StringCharacterIterator it = (StringCharacterIterator) object;
142        return string.equals(it.string) && start == it.start && end == it.end
143                && offset == it.offset;
144    }
145
146    /**
147     * Sets the current position to the begin index and returns the character at
148     * the new position in the source string.
149     *
150     * @return the character at the begin index or {@code DONE} if the begin
151     *         index is equal to the end index.
152     */
153    public char first() {
154        if (start == end) {
155            return DONE;
156        }
157        offset = start;
158        return string.charAt(offset);
159    }
160
161    /**
162     * Returns the begin index in the source string.
163     *
164     * @return the index of the first character of the iteration.
165     */
166    public int getBeginIndex() {
167        return start;
168    }
169
170    /**
171     * Returns the end index in the source string.
172     *
173     * @return the index one past the last character of the iteration.
174     */
175    public int getEndIndex() {
176        return end;
177    }
178
179    /**
180     * Returns the current index in the source string.
181     *
182     * @return the current index.
183     */
184    public int getIndex() {
185        return offset;
186    }
187
188    @Override
189    public int hashCode() {
190        return string.hashCode() + start + end + offset;
191    }
192
193    /**
194     * Sets the current position to the end index - 1 and returns the character
195     * at the new position.
196     *
197     * @return the character before the end index or {@code DONE} if the begin
198     *         index is equal to the end index.
199     */
200    public char last() {
201        if (start == end) {
202            return DONE;
203        }
204        offset = end - 1;
205        return string.charAt(offset);
206    }
207
208    /**
209     * Increments the current index and returns the character at the new index.
210     *
211     * @return the character at the next index, or {@code DONE} if the next
212     *         index would be past the end.
213     */
214    public char next() {
215        if (offset >= (end - 1)) {
216            offset = end;
217            return DONE;
218        }
219        return string.charAt(++offset);
220    }
221
222    /**
223     * Decrements the current index and returns the character at the new index.
224     *
225     * @return the character at the previous index, or {@code DONE} if the
226     *         previous index would be past the beginning.
227     */
228    public char previous() {
229        if (offset == start) {
230            return DONE;
231        }
232        return string.charAt(--offset);
233    }
234
235    /**
236     * Sets the current index in the source string.
237     *
238     * @param location
239     *            the index the current position is set to.
240     * @return the character at the new index, or {@code DONE} if
241     *         {@code location} is set to the end index.
242     * @throws IllegalArgumentException
243     *            if {@code location} is smaller than the begin index or greater
244     *            than the end index.
245     */
246    public char setIndex(int location) {
247        if (location < start || location > end) {
248            throw new IllegalArgumentException();
249        }
250        offset = location;
251        if (offset == end) {
252            return DONE;
253        }
254        return string.charAt(offset);
255    }
256
257    /**
258     * Sets the source string to iterate over. The begin and end positions are
259     * set to the start and end of this string.
260     *
261     * @param value
262     *            the new source string.
263     */
264    public void setText(String value) {
265        string = value;
266        start = offset = 0;
267        end = value.length();
268    }
269}
270