1 /**
2 *
3 * Copyright 2003-2005 The Apache Software Foundation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * 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
18 package org.apache.geronimo.javamail.store.nntp.newsrc;
19
20 import java.io.IOException;
21 import java.io.Writer;
22
23 /**
24 * Represent a single Range in a newsrc file. A Range can be either a single
25 * number (start == end) or a span of article numbers.
26 */
27 public class Range {
28
29 int start;
30
31
32 int end;
33
34 /**
35 * Construct a Range item for a single digit range.
36 *
37 * @param spot
38 * The location of the singleton.
39 */
40 public Range(int spot) {
41 this(spot, spot);
42 }
43
44 /**
45 * Construct a Range item.
46 *
47 * @param start
48 * The starting point of the Range.
49 * @param end
50 * The Range end point (which may be equal to the starting
51 * point).
52 */
53 public Range(int start, int end) {
54 this.start = start;
55 this.end = end;
56 }
57
58 /**
59 * Parse a section of a .newsrc range string into a single Range item. The
60 * range is either a single number, or a pair of numbers separated by a
61 * hyphen.
62 *
63 * @param range
64 * The range string.
65 *
66 * @return A constructed Range item, or null if there is a parsing error.
67 */
68 static public Range parse(String range) {
69
70
71
72 int marker = range.indexOf('-');
73
74 try {
75 if (marker != -1) {
76 String rangeStart = range.substring(0, marker).trim();
77 String rangeEnd = range.substring(marker + 1).trim();
78
79 int start = Integer.parseInt(rangeStart);
80 int end = Integer.parseInt(rangeEnd);
81
82 if (start >= 0 && end >= 0) {
83 return new Range(start, end);
84 }
85 } else {
86
87 int start = Integer.parseInt(range);
88
89 return new Range(start, start);
90
91 }
92 } catch (NumberFormatException e) {
93 }
94
95 return null;
96 }
97
98 /**
99 * Get the starting point for the Range.
100 *
101 * @return The beginning of the mark range.
102 */
103 public int getStart() {
104 return start;
105 }
106
107 /**
108 * Set the starting point for a Range.
109 *
110 * @param start
111 * The new start value.
112 */
113 public void setStart(int start) {
114 this.start = start;
115 }
116
117 /**
118 * Get the ending point for the Range.
119 *
120 * @return The end of the mark range.
121 */
122 public int getEnd() {
123 return end;
124 }
125
126 /**
127 * Set the ending point for a Range.
128 *
129 * @param end
130 * The new end value.
131 */
132 public void setEnd(int end) {
133 this.end = end;
134 }
135
136 /**
137 * Test if a range contains a point value.
138 *
139 * @param target
140 * The article location to test.
141 *
142 * @return True if the target is between the start and end values,
143 * inclusive.
144 */
145 public boolean contains(int target) {
146 return target >= start && target <= end;
147 }
148
149 /**
150 * Test if one range is completely contained within another Range.
151 *
152 * @param other
153 * The other test range.
154 *
155 * @return true if the other start and end points are contained within this
156 * range.
157 */
158 public boolean contains(Range other) {
159 return contains(other.getStart()) && contains(other.getEnd());
160 }
161
162 /**
163 * Tests if two ranges overlap
164 *
165 * @param other
166 * The other test range.
167 *
168 * @return true if the start or end points of either range are contained
169 * within the range of the other.
170 */
171 public boolean overlaps(Range other) {
172 return other.contains(start) || other.contains(end) || contains(other.getStart()) || contains(other.getEnd());
173 }
174
175 /**
176 * Test if two ranges exactly abutt each other.
177 *
178 * @param other
179 * The other Range to test.
180 *
181 * @return true if the end of one range abutts the start of the other range.
182 */
183 public boolean abutts(Range other) {
184 return other.getStart() == end + 1 || other.getEnd() == start - 1;
185 }
186
187 /**
188 * Tests if a single point abutts either the start or end of this Range.
189 *
190 * @param article
191 * The point to test.
192 *
193 * @return true if test point is equal to start - 1 or end + 1.
194 */
195 public boolean abutts(int article) {
196 return article == start - 1 || article == end + 1;
197 }
198
199 /**
200 * Test if a point is below the test Range.
201 *
202 * @param article
203 * The point to test.
204 *
205 * @return true if the entire range is less than the test point.
206 */
207 public boolean lessThan(int article) {
208 return end < article;
209 }
210
211 /**
212 * Test if another Range is less than this Range.
213 *
214 * @param other
215 * The other Range to test.
216 *
217 * @return true if the other Range lies completely below this Range.
218 */
219 public boolean lessThan(Range other) {
220 return end < other.start;
221 }
222
223 /**
224 * Test if a point is above the test Range.
225 *
226 * @param article
227 * The point to test.
228 *
229 * @return true if the entire range is greater than the test point.
230 */
231 public boolean greaterThan(int article) {
232 return start > article;
233 }
234
235 /**
236 * Test if another Range is greater than this Range.
237 *
238 * @param other
239 * The other Range to test.
240 *
241 * @return true if the other Range lies completely below this Range.
242 */
243 public boolean greaterThan(Range other) {
244 return start > other.end;
245 }
246
247 /**
248 * Merge another Range into this one. Merging will increase the bounds of
249 * this Range to encompass the entire span of the two. If the Ranges do not
250 * overlap, the newly created range will include the gap between the two.
251 *
252 * @param other
253 * The Range to merge.
254 */
255 public void merge(Range other) {
256 if (other.start < start) {
257 start = other.start;
258 }
259
260 if (other.end > end) {
261 end = other.end;
262 }
263 }
264
265 /**
266 * Split a range at a given split point. Splitting will truncate at the
267 * split location - 1 and return a new range beginning at location + 1; This
268 * code assumes that the split location is at neither end poing.
269 *
270 * @param location
271 * The split location. Location must be in the range start <
272 * location < end.
273 *
274 * @return A new Range object for the split portion of the range.
275 */
276 public Range split(int location) {
277 int newEnd = end;
278
279 end = location - 1;
280
281 return new Range(location + 1, newEnd);
282 }
283
284 /**
285 * Save an individual range element to a newsrc file. The range is expressed
286 * either as a single number, or a hypenated pair of numbers.
287 *
288 * @param out
289 * The output writer used to save the data.
290 *
291 * @exception IOException
292 */
293 public void save(Writer out) throws IOException {
294
295 if (start == end) {
296 out.write(Integer.toString(start));
297 } else {
298 out.write(Integer.toString(start));
299 out.write("-");
300 out.write(Integer.toString(end));
301 }
302 }
303
304 /**
305 * Convert a Range into String form. Used mostly for debugging.
306 *
307 * @return The String representation of the Range.
308 */
309 public String toString() {
310 if (start == end) {
311 return Integer.toString(start);
312 } else {
313 return Integer.toString(start) + "-" + Integer.toString(end);
314 }
315 }
316 }