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 import java.util.ArrayList;
23 import java.util.StringTokenizer;
24
25 /**
26 * Manage a list of ranges values from a newsrc file.
27 */
28 public class RangeList {
29 boolean dirty = false;
30
31 ArrayList ranges = new ArrayList();
32
33 /**
34 * Create a RangeList instance from a newsrc range line. Values are saved as
35 * a comma separated set of range values. A range value is either a single
36 * number or a hypenated pair of numbers.
37 *
38 * @param line
39 * The newsrc range line.
40 */
41 public RangeList(String line) {
42
43
44 if (line != null) {
45
46 StringTokenizer tokenizer = new StringTokenizer(line, ",");
47
48 while (tokenizer.hasMoreTokens()) {
49 String rangeString = (String) tokenizer.nextToken();
50 rangeString = rangeString.trim();
51 if (rangeString.length() != 0) {
52 Range range = Range.parse(rangeString);
53 if (range != null) {
54 insert(range);
55 }
56 }
57 }
58 }
59
60
61 dirty = false;
62 }
63
64 /**
65 * Insert a range item into our list. If possible, the inserted range will
66 * be merged with existing ranges.
67 *
68 * @param newRange
69 * The new range item.
70 */
71 public void insert(Range newRange) {
72
73 for (int i = 0; i < ranges.size(); i++) {
74 Range range = (Range) ranges.get(i);
75
76
77 if (range.contains(newRange)) {
78 return;
79 }
80
81
82 if (range.abutts(newRange) || range.overlaps(newRange)) {
83
84
85
86
87
88
89
90 dirty = true;
91 newRange.merge(range);
92 ranges.remove(i);
93 insert(newRange);
94 return;
95 }
96
97
98
99
100 if (newRange.lessThan(range)) {
101 dirty = true;
102 ranges.add(i, newRange);
103 return;
104 }
105 }
106 dirty = true;
107
108 ranges.add(newRange);
109 }
110
111 /**
112 * Test if a given article point falls within one of the contained Ranges.
113 *
114 * @param article
115 * The test point.
116 *
117 * @return true if this falls within one of our current mark Ranges, false
118 * otherwise.
119 */
120 public boolean isMarked(int article) {
121 for (int i = 0; i < ranges.size(); i++) {
122 Range range = (Range) ranges.get(i);
123 if (range.contains(article)) {
124 return true;
125 }
126
127 if (range.greaterThan(article)) {
128 return false;
129 }
130 }
131 return false;
132 }
133
134 /**
135 * Mark a target article as having been seen.
136 *
137 * @param article
138 * The target article number.
139 */
140 public void setMarked(int article) {
141
142 insert(new Range(article, article));
143 }
144
145 /**
146 * Clear the seen mark for a target article.
147 *
148 * @param article
149 * The target article number.
150 */
151 public void setUnmarked(int article) {
152 for (int i = 0; i < ranges.size(); i++) {
153 Range range = (Range) ranges.get(i);
154
155
156 if (range.contains(article)) {
157
158
159
160
161
162
163 if (range.getStart() == article) {
164 if (range.getEnd() == article) {
165
166 ranges.remove(i);
167 } else {
168
169 range.setStart(article + 1);
170 }
171 } else if (range.getEnd() == article) {
172
173 range.setEnd(article - 1);
174 } else {
175
176
177 Range section = range.split(article);
178 ranges.add(i + 1, section);
179 }
180 dirty = true;
181 return;
182 }
183
184 if (range.greaterThan(article)) {
185
186 return;
187 }
188 }
189
190 }
191
192 /**
193 * Save this List of Ranges out to a .newsrc file. This creates a
194 * comma-separated list of range values from each of the Ranges.
195 *
196 * @param out
197 * The target output stream.
198 *
199 * @exception IOException
200 */
201 public void save(Writer out) throws IOException {
202
203 if (ranges.size() == 0) {
204 return;
205 }
206
207 Range range = (Range) ranges.get(0);
208 range.save(out);
209
210 for (int i = 1; i < ranges.size(); i++) {
211 out.write(",");
212 range = (Range) ranges.get(i);
213 range.save(out);
214 }
215 }
216
217 /**
218 * Return the state of the dirty flag.
219 *
220 * @return True if the range list information has changed, false otherwise.
221 */
222 public boolean isDirty() {
223 return dirty;
224 }
225 }