1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package de.jaret.util.ui.timebars.strategy;
21
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collection;
25 import java.util.Collections;
26 import java.util.Comparator;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.SortedMap;
31 import java.util.TreeMap;
32
33 import de.jaret.util.date.Interval;
34 import de.jaret.util.date.IntervalImpl;
35 import de.jaret.util.ui.timebars.TimeBarViewerDelegate;
36 import de.jaret.util.ui.timebars.model.TimeBarRow;
37
38
39
40
41
42
43
44
45
46
47 public class DefaultOverlapStrategy implements IOverlapStrategy {
48
49 protected TimeBarViewerDelegate _delegate;
50
51 protected Map<TimeBarRow, Map<Interval, OverlapInfo>> _oiRowCache = new HashMap<TimeBarRow, Map<Interval, OverlapInfo>>();
52
53
54 protected boolean _assumeSortedIntervals = true;
55
56
57
58
59
60
61 public DefaultOverlapStrategy(TimeBarViewerDelegate delegate) {
62 _delegate = delegate;
63 }
64
65
66
67
68 public OverlapInfo getOverlapInfo(TimeBarRow row, Interval interval) {
69 Map<Interval, OverlapInfo> oiIntervalMap = _oiRowCache.get(row);
70 if (oiIntervalMap == null) {
71 oiIntervalMap = updateOICache(row);
72 }
73 OverlapInfo oi = oiIntervalMap.get(interval);
74 return oi;
75 }
76
77
78
79
80 public int getMaxOverlapCount(TimeBarRow row) {
81
82 Map<Interval, OverlapInfo> oiIntervalMap = _oiRowCache.get(row);
83 if (oiIntervalMap == null) {
84 oiIntervalMap = updateOICache(row);
85 }
86 int max = 0;
87 Collection<OverlapInfo> infos = oiIntervalMap.values();
88 for (OverlapInfo overlapInfo : infos) {
89 if (overlapInfo.maxOverlapping > max) {
90 max = overlapInfo.maxOverlapping;
91 }
92 }
93 return max + 1;
94 }
95
96
97
98
99 public Map<Interval, OverlapInfo> updateOICache(TimeBarRow row) {
100
101 List<Interval> intervals = _delegate.filterIntervals(row.getIntervals());
102
103 Map<Interval, OverlapInfo> result = new HashMap<Interval, OverlapInfo>();
104
105
106 if (!_assumeSortedIntervals) {
107 List<Interval> temp = new ArrayList<Interval>(intervals.size());
108 temp.addAll(intervals);
109 Collections.sort(temp, new Comparator<Interval>() {
110 public int compare(Interval o1, Interval o2) {
111 return (int) (o1.getBegin().getDate().getTime() - o2.getBegin().getDate().getTime());
112 }
113 });
114 intervals = temp;
115 }
116
117
118 Integer[] sortedStartTime = new Integer[intervals.size()];
119 for (int i = 0; i < intervals.size(); i++) {
120 sortedStartTime[i] = i;
121 }
122 final List<Interval> finalIntervals = intervals;
123 Arrays.sort(sortedStartTime, new Comparator<Integer>() {
124 public int compare(Integer o1, Integer o2) {
125 return finalIntervals.get(o1).getBegin().compareTo(finalIntervals.get(o2).getBegin());
126 }
127 });
128
129
130 TreeMap<Long, Integer> mapEndTime = new TreeMap<Long, Integer>();
131 long maxEndTime = Long.MIN_VALUE;
132 for (int i = 0; i < sortedStartTime.length; i++) {
133 Interval interval1 = intervals.get(sortedStartTime[i]);
134 maxEndTime = Math.max(maxEndTime, interval1.getEnd().getDate().getTime());
135 mapEndTime.put(maxEndTime, i);
136 }
137
138
139 List<OverlapInfo> oList = new ArrayList<OverlapInfo>();
140
141 for (int i = 0; i < intervals.size(); i++) {
142 Interval interval = intervals.get(i);
143 OverlapInfo oi = new OverlapInfo();
144 oi.interval = interval;
145 result.put(interval, oi);
146 oList.add(oi);
147
148
149
150
151
152 SortedMap<Long, Integer> first = mapEndTime.subMap(0L, interval.getBegin().getDate().getTime());
153 int startIdx = (first.size() == 0 ? 0 : first.get(first.lastKey()));
154
155
156
157 for (int y = startIdx; y < sortedStartTime.length; y++) {
158 int x = sortedStartTime[y];
159 if (i == x) {
160 continue;
161 }
162 Interval cmp = intervals.get(x);
163 if (0 < cmp.getBegin().compareTo(interval.getEnd())) {
164 break;
165 }
166 if (IntervalImpl.intersectNonIncluding(interval, cmp)) {
167 oi.overlapping.add(cmp);
168 }
169 }
170
171
172 oi.overlappingCount = oi.overlapping.size();
173 oi.maxOverlapping = oi.overlappingCount;
174
175 }
176
177
178
179 for (OverlapInfo oi : oList) {
180 Interval interval = oi.interval;
181
182
183 int max = 0;
184 int cur = 0;
185 for (Interval check : oi.overlapping) {
186 if (check.contains(interval.getBegin())) {
187 cur++;
188 }
189 }
190 if (cur > max) {
191 max = cur;
192 }
193 cur = 0;
194 for (Interval check : oi.overlapping) {
195 if (check.contains(interval.getEnd())) {
196 cur++;
197 }
198 }
199 if (cur > max) {
200 max = cur;
201 }
202
203 for (Interval check : oi.overlapping) {
204 if (interval.contains(check.getBegin())) {
205 cur = 1;
206 for (Interval check2 : oi.overlapping) {
207 if (!check.equals(check2)) {
208 if (IntervalImpl.containsNonIncluding(check2, check.getBegin())) {
209 cur++;
210 }
211 }
212 }
213 if (cur > max) {
214 max = cur;
215 }
216 }
217 }
218 for (Interval check : oi.overlapping) {
219 if (interval.contains(check.getEnd())) {
220 cur = 1;
221 for (Interval check2 : oi.overlapping) {
222 if (!check.equals(check2)) {
223 if (IntervalImpl.containsNonIncluding(check2, check.getEnd())) {
224 cur++;
225 }
226 }
227 }
228 if (cur > max) {
229 max = cur;
230 }
231 }
232 }
233
234 oi.maxOverlapping = max;
235 oi.overlappingCount = max;
236 }
237
238
239
240
241 Collections.sort(oList, new Comparator<OverlapInfo>() {
242 public int compare(OverlapInfo arg0, OverlapInfo arg1) {
243 return -arg1.overlappingCount - arg0.overlappingCount;
244 }
245 });
246
247
248
249 calcTransitiveOverlaps(result, oList);
250
251
252
253 for (int i = 0; i < oList.size(); i++) {
254 OverlapInfo oi = oList.get(i);
255 assignPosition(oi, result);
256
257
258 if (oi.pos == -1) {
259
260 oi.maxOverlapping = oi.maxOverlapping + 1;
261
262 calcTransitiveOverlaps(result, oList);
263 assignPosition(oi, result);
264 }
265 }
266
267
268 _oiRowCache.put(row, result);
269 return result;
270 }
271
272
273
274
275
276
277
278
279 private void calcTransitiveOverlaps(Map<Interval, OverlapInfo> result, List<OverlapInfo> oList) {
280 boolean change = true;
281 while (change) {
282 change = false;
283 for (int i = 0; i < oList.size(); i++) {
284 OverlapInfo oi = oList.get(i);
285 int max = getMaxOverlapping(oi, result);
286 if (max != oi.maxOverlapping) {
287 oi.maxOverlapping = max;
288 change = true;
289 }
290 }
291 }
292 }
293
294
295
296
297
298
299
300 private void assignPosition(OverlapInfo oi, Map<Interval, OverlapInfo> result) {
301
302 int[] positions = new int[oi.maxOverlapping + 1];
303 for (int p = 0; p < oi.maxOverlapping + 1; p++) {
304 positions[p] = -1;
305 }
306
307 for (Interval interval : oi.overlapping) {
308 OverlapInfo o = result.get(interval);
309 if (o.pos != -1) {
310 positions[o.pos] = o.pos;
311 }
312 }
313
314
315 if (oi.pos == -1) {
316 for (int p = 0; p < oi.maxOverlapping + 1; p++) {
317 if (positions[p] == -1) {
318 oi.pos = p;
319 positions[p] = p;
320 break;
321 }
322 }
323 }
324 }
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345 private int getMaxOverlapping(OverlapInfo oi, Map<Interval, OverlapInfo> map) {
346 int max = oi.overlappingCount;
347 for (Interval interval : oi.overlapping) {
348 OverlapInfo o = map.get(interval);
349 if (o.maxOverlapping > max) {
350 max = o.maxOverlapping;
351 }
352 }
353 return max;
354 }
355
356
357
358
359 public void clearCachedData() {
360 _oiRowCache.clear();
361 }
362
363
364
365
366 public void dispose() {
367 _delegate = null;
368 _oiRowCache = null;
369 }
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402 public boolean getAssumeSortedIntervals() {
403 return _assumeSortedIntervals;
404 }
405
406
407
408
409
410
411 public void setAssumeSortedIntervals(boolean assumeSortedIntervals) {
412 _assumeSortedIntervals = assumeSortedIntervals;
413 }
414
415 }