1 13 package com.tonbeller.jpivot.table.span; 14 15 import java.util.Iterator ; 16 17 import org.apache.log4j.Logger; 18 19 import com.tonbeller.jpivot.olap.model.Axis; 20 import com.tonbeller.jpivot.olap.model.Member; 21 import com.tonbeller.jpivot.olap.model.Position; 22 23 32 public class SpanCalc { 33 private static final Logger logger = Logger.getLogger(SpanCalc.class); 34 35 int positionCount, hierarchyCount; 36 Span[][] spans; 38 39 boolean initialized = false; 41 42 SpanConfig config = new NoSpanConfig(); 43 44 47 public SpanCalc(Span[][] spans) { 48 this.spans = spans; 49 } 50 51 54 public SpanCalc(Axis axis) { 55 positionCount = axis.getPositions().size(); 56 if (positionCount > 0) 57 hierarchyCount = ((Position) axis.getPositions().get(0)).getMembers().length; 58 else 59 hierarchyCount = 0; 60 if (logger.isInfoEnabled()) 61 logger.info("creating SpanCalc, positionCount = " + positionCount + ", hierarchyCount = " + hierarchyCount); 62 spans = new Span[positionCount][]; 63 for (int i = 0; i < positionCount; i++) 64 spans[i] = new Span[hierarchyCount]; 65 66 Iterator it = axis.getPositions().iterator(); 67 for (int posIndex = 0; posIndex < positionCount; posIndex++) { 68 Position p = (Position) it.next(); 69 createSpansFromAxis(axis, p, posIndex, spans[posIndex]); 70 } 71 } 72 73 void createSpansFromAxis(Axis axis, Position position, int posIndex, Span[] spans) { 74 if (logger.isDebugEnabled()) 75 logger.debug("creating Span for position " + posIndex); 76 Member[] members = position.getMembers(); 77 for (int hierIndex = 0; hierIndex < hierarchyCount; hierIndex++) { 78 Member member = members[hierIndex]; 79 spans[hierIndex] = new Span(axis, position, member); 80 } 81 } 82 83 void initialize() { 84 if (!initialized) { 85 positionCount = spans.length; 86 if (positionCount > 0) 87 hierarchyCount = spans[0].length; 88 else 89 hierarchyCount = 0; 90 initSpans(); 91 calcSpans(); 92 calcIndent(); 93 initialized = true; 94 } 95 } 96 97 100 void initSpans() { 101 for (int posIndex = 0; posIndex < positionCount; posIndex++) { 102 for (int hierIndex = 0; hierIndex < hierarchyCount; hierIndex++) { 103 spans[posIndex][hierIndex].initialize(posIndex, hierIndex); 104 } 105 } 106 } 107 108 117 boolean[][] forcePositionBreak; 118 119 void calcSpans() { 120 logger.info("calcSpans"); 121 forcePositionBreak = new boolean[positionCount][hierarchyCount]; 122 123 for (int hierIndex = 0; hierIndex < hierarchyCount; hierIndex++) { 124 for (int posIndex = 0; posIndex < positionCount; posIndex++) { 125 Span span = spans[posIndex][hierIndex]; 126 127 if (!span.isSignificant()) 129 continue; 130 131 int dir = config.chooseSpanDirection(span); 132 133 if (dir == SpanConfig.HIERARCHY_SPAN) { 134 makeHierSpan(span, 1); 135 addForcePositionBreak(span); 136 } else if (dir == SpanConfig.POSITION_SPAN) { 137 makePosSpan(span, 1); 138 addForcePositionBreak(span); 139 } else if (dir == SpanConfig.HIERARCHY_THEN_POSITION_SPAN) { 140 int count = makeHierSpan(span, 1); 141 makePosSpan(span, count); 142 addForcePositionBreak(span); 143 } else if (dir == SpanConfig.POSITION_THEN_HIERARCHY_SPAN) { 144 int count = makePosSpan(span, 1); 145 makeHierSpan(span, count); 146 addForcePositionBreak(span); 147 } 148 149 } 151 } 152 } 153 154 155 int makeHierSpan(Span span, int posSpans) { 156 logger.debug("makeHierSpan"); 157 int pi = span.positionIndex; 158 int spanCount = 1; 159 loop : for (int hi = span.hierarchyIndex + 1; hi < hierarchyCount; hi++) { 160 boolean equal = true; 162 for (int i = 0; i < posSpans; i++) { 163 Span s = spans[pi + i][hi]; 164 equal = equal && config.equals(span, s); 165 } 166 167 if (equal) { 169 span.hierarchySpan += 1; 170 spanCount += 1; 171 for (int i = 0; i < posSpans; i++) { 172 Span s = spans[pi + i][hi]; 173 s.significant = false; 174 s.hierarchySpan = s.positionSpan = 0; 175 } 176 } else 177 break loop; 178 } 179 return spanCount; 180 } 181 182 183 int makePosSpan(Span span, int hierSpans) { 184 logger.debug("makePosSpan"); 185 int hi = span.hierarchyIndex; 186 int spanCount = 1; 187 loop : for (int pi = span.positionIndex + 1; pi < positionCount; pi++) { 188 if (forcePositionBreak[pi][hi]) 190 break loop; 191 192 boolean equal = true; 194 for (int i = 0; i < hierSpans; i++) { 195 Span s = spans[pi][hi + i]; 196 equal = equal && config.equals(span, s); 197 } 198 199 if (equal) { 201 span.positionSpan += 1; 202 spanCount += 1; 203 for (int i = 0; i < hierSpans; i++) { 204 Span s = spans[pi][hi + i]; 205 s.significant = false; 206 s.hierarchySpan = s.positionSpan = 0; 207 } 208 } else 209 break loop; 210 } 211 return spanCount; 212 } 213 214 void addForcePositionBreak(Span span) { 215 int pi = span.positionIndex + span.positionSpan; 217 int hi = span.hierarchyIndex + span.hierarchySpan; 218 for (; pi < positionCount && hi < hierarchyCount; hi++) 219 forcePositionBreak[pi][hi] = true; 220 } 221 222 223 224 242 public SpanCalc createPositionHeader(SpanHeaderFactory shf) { 243 logger.info("createPositionHeader"); 244 if (!initialized) 245 initialize(); 246 247 if (hierarchyCount == 0 || positionCount == 0) 248 return null; 249 250 Span[][] header = new Span[1][hierarchyCount]; 251 252 header[0][0] = shf.create(spans[0][0]); 253 254 for (int hi = 1; hi < hierarchyCount; hi++) { 255 int pi; 256 inner : for (pi = 0; pi < positionCount; pi++) { 257 Span curSpan = spans[pi][hi]; 258 Span prevSpan = spans[pi][hi - 1]; 259 if (!config.equals(prevSpan, curSpan)) { 260 prevSpan = curSpan; 261 header[0][hi] = shf.create(curSpan); 262 break inner; 263 } 264 } 265 if (pi == positionCount) { 266 header[0][hi] = shf.create(spans[0][hi]); 269 } 270 } 271 272 return new SpanCalc(header); 273 } 274 275 276 277 public void addHierarchyHeader(SpanHeaderFactory shf, boolean removeDuplicates) { 278 logger.info("addHierarchyHeader"); 279 boolean[] keep = new boolean[hierarchyCount * 2]; 280 createHeaderSpans(shf, keep); 281 int newHierarchyCount = 0; 282 for (int i = 0; i < keep.length; i++) 283 if (keep[i]) 284 newHierarchyCount += 1; 285 removeDuplicateHeaders(keep, newHierarchyCount); 286 initialized = false; 287 } 288 289 void removeDuplicateHeaders(boolean[] keep, int newHierarchyCount) { 290 logger.info("removeDuplicateHeaders"); 291 for (int posIndex = 0; posIndex < positionCount; posIndex++) { 292 Span[] oldSpans = spans[posIndex]; 293 Span[] newSpans = new Span[newHierarchyCount]; 294 int newHierIndex = 0; 295 for (int oldHierIndex = 0; oldHierIndex < oldSpans.length; oldHierIndex++) { 296 if (keep[oldHierIndex]) { 297 Span span = oldSpans[oldHierIndex]; 298 newSpans[newHierIndex++] = span; 299 } 300 } 301 spans[posIndex] = newSpans; 302 } 303 } 304 305 310 void createHeaderSpans(SpanHeaderFactory shf, boolean[] keep) { 311 logger.info("createHeaderSpans"); 312 for (int posIndex = 0; posIndex < positionCount; posIndex++) { 313 Span[] newSpans = new Span[hierarchyCount * 2]; 314 int newIndex = 0; 315 Span prevHeaderSpan = null; 316 for (int hierIndex = 0; hierIndex < hierarchyCount; hierIndex++) { 317 Span span = spans[posIndex][hierIndex]; 318 Span curHeaderSpan = shf.create(span); 320 if (prevHeaderSpan == null || !config.equals(prevHeaderSpan, curHeaderSpan)) { 321 keep[newIndex] = true; 322 newSpans[newIndex++] = curHeaderSpan; 323 prevHeaderSpan = curHeaderSpan; 324 } else { 325 newSpans[newIndex++] = (Span) span.clone(); 327 } 328 keep[newIndex] = true; 330 newSpans[newIndex++] = span; 331 } 332 spans[posIndex] = newSpans; 333 } 334 } 335 336 337 338 347 public Span getSpan(int positionIndex, int hierarchyIndex) { 348 if (!initialized) 349 initialize(); 350 return spans[positionIndex][hierarchyIndex]; 351 } 352 353 357 public int getHierarchyCount() { 358 if (!initialized) 359 initialize(); 360 return hierarchyCount; 361 } 362 363 367 public int getPositionCount() { 368 if (!initialized) 369 initialize(); 370 return positionCount; 371 } 372 373 377 public SpanConfig getConfig() { 378 return config; 379 } 380 381 385 public void setConfig(SpanConfig config) { 386 initialized = false; 387 this.config = config; 388 } 389 390 393 public Span[][] getSpans() { 394 return spans; 395 } 396 397 400 public void setSpans(Span[][] spans) { 401 this.spans = spans; 402 initialized = false; 403 } 404 405 408 void calcIndent() { 409 logger.info("calcIndent"); 410 for (int hi = 0; hi < hierarchyCount; hi++) { 411 412 int minRootDistance = Integer.MAX_VALUE; 414 for (int pi = 0; pi < positionCount; pi++) { 415 Span s = spans[pi][hi]; 416 if (s.isMember()) { 417 Member m = s.getMember(); 418 if (m.getRootDistance() < minRootDistance) 419 minRootDistance = m.getRootDistance(); 420 } 421 } 422 423 for (int pi = 0; pi < positionCount; pi++) { 425 Span s = spans[pi][hi]; 426 if (s.isMember()) { 427 Member m = s.getMember(); 428 s.setIndent(m.getRootDistance() - minRootDistance); 429 } else 430 s.setIndent(0); 431 } 432 } 433 } 434 435 436 437 public static SpanCalc appendBelow(SpanCalc above, SpanCalc below) { 438 logger.info("appendBelow"); 439 if (above == null) 440 return below; 441 if (below == null) 442 return above; 443 if (above.getHierarchyCount() != below.getHierarchyCount()) 444 throw new IllegalArgumentException ("sizes dont match"); 445 final int HI = above.getHierarchyCount(); 446 Span[][] a = above.spans; 447 Span[][] b = below.spans; 448 Span[][] s = new Span[a.length + b.length][]; 449 for (int pi = 0; pi < a.length; pi++) { 450 s[pi] = new Span[HI]; 451 for (int hi = 0; hi < HI; hi++) 452 s[pi][hi] = a[pi][hi]; 453 } 454 for (int pi = 0; pi < b.length; pi++) { 455 s[pi + a.length] = new Span[HI]; 456 for (int hi = 0; hi < HI; hi++) 457 s[pi + a.length][hi] = b[pi][hi]; 458 } 459 return new SpanCalc(s); 460 } 461 462 } 463 | Popular Tags |