001/* 002// This software is subject to the terms of the Eclipse Public License v1.0 003// Agreement, available at the following URL: 004// http://www.eclipse.org/legal/epl-v10.html. 005// You must accept the terms of that agreement to use this software. 006// 007// Copyright (C) 2006-2011 Pentaho 008// All Rights Reserved. 009*/ 010package mondrian.olap.fun; 011 012import mondrian.calc.*; 013import mondrian.calc.impl.AbstractListCalc; 014import mondrian.mdx.ResolvedFunCall; 015import mondrian.olap.*; 016import mondrian.resource.MondrianResource; 017 018import java.util.*; 019 020/** 021 * Definition of the <code>ToggleDrillState</code> MDX function. 022 * 023 * @author jhyde 024 * @since Mar 23, 2006 025 */ 026class ToggleDrillStateFunDef extends FunDefBase { 027 static final String[] ReservedWords = new String[] {"RECURSIVE"}; 028 static final ReflectiveMultiResolver Resolver = 029 new ReflectiveMultiResolver( 030 "ToggleDrillState", 031 "ToggleDrillState(<Set1>, <Set2>[, RECURSIVE])", 032 "Toggles the drill state of members. This function is a combination of DrillupMember and DrilldownMember.", 033 new String[]{"fxxx", "fxxxy"}, 034 ToggleDrillStateFunDef.class, 035 ReservedWords); 036 037 public ToggleDrillStateFunDef(FunDef dummyFunDef) { 038 super(dummyFunDef); 039 } 040 041 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 042 if (call.getArgCount() > 2) { 043 throw MondrianResource.instance() 044 .ToggleDrillStateRecursiveNotSupported.ex(); 045 } 046 final ListCalc listCalc0 = 047 compiler.compileList(call.getArg(0)); 048 final ListCalc listCalc1 = 049 compiler.compileList(call.getArg(1)); 050 return new AbstractListCalc(call, new Calc[]{listCalc0, listCalc1}) { 051 public TupleList evaluateList(Evaluator evaluator) { 052 final TupleList list0 = listCalc0.evaluateList(evaluator); 053 final TupleList list1 = listCalc1.evaluateList(evaluator); 054 return toggleDrillStateTuples(evaluator, list0, list1); 055 } 056 }; 057 } 058 059 TupleList toggleDrillStateTuples( 060 Evaluator evaluator, TupleList v0, TupleList list1) 061 { 062 assert list1.getArity() == 1; 063 if (list1.isEmpty()) { 064 return v0; 065 } 066 if (v0.isEmpty()) { 067 return v0; 068 } 069 final Member[] members = new Member[v0.getArity()]; // tuple workspace 070 final Set<Member> set = new HashSet<Member>(list1.slice(0)); 071 TupleList result = v0.cloneList((v0.size() * 3) / 2 + 1); // allow 50% 072 int i = 0, n = v0.size(); 073 while (i < n) { 074 List<Member> o = v0.get(i++); 075 result.add(o); 076 Member m = null; 077 int k = -1; 078 for (int j = 0; j < o.size(); j++) { 079 Member member = o.get(j); 080 if (set.contains(member)) { 081 k = j; 082 m = member; 083 break; 084 } 085 } 086 if (k == -1) { 087 continue; 088 } 089 boolean isDrilledDown = false; 090 if (i < n) { 091 List<Member> next = v0.get(i); 092 Member nextMember = next.get(k); 093 boolean strict = true; 094 if (FunUtil.isAncestorOf(m, nextMember, strict)) { 095 isDrilledDown = true; 096 } 097 } 098 if (isDrilledDown) { 099 // skip descendants of this member 100 do { 101 List<Member> next = v0.get(i); 102 Member nextMember = next.get(k); 103 boolean strict = true; 104 if (FunUtil.isAncestorOf(m, nextMember, strict)) { 105 i++; 106 } else { 107 break; 108 } 109 } while (i < n); 110 } else { 111 List<Member> children = 112 evaluator.getSchemaReader().getMemberChildren(m); 113 for (Member child : children) { 114 o.toArray(members); 115 members[k] = child; 116 result.addTuple(members); 117 } 118 } 119 } 120 return result; 121 } 122} 123 124// End ToggleDrillStateFunDef.java