001 /* 002 // $Id: //open/mondrian/src/main/mondrian/olap/fun/ToggleDrillStateFunDef.java#3 $ 003 // This software is subject to the terms of the Common Public License 004 // Agreement, available at the following URL: 005 // http://www.opensource.org/licenses/cpl.html. 006 // Copyright (C) 2006-2008 Julian Hyde 007 // All Rights Reserved. 008 // You must accept the terms of that agreement to use this software. 009 */ 010 package mondrian.olap.fun; 011 012 import mondrian.olap.*; 013 import mondrian.olap.type.TupleType; 014 import mondrian.olap.type.SetType; 015 import mondrian.calc.Calc; 016 import mondrian.calc.ExpCompiler; 017 import mondrian.calc.ListCalc; 018 import mondrian.calc.impl.AbstractListCalc; 019 import mondrian.mdx.ResolvedFunCall; 020 import mondrian.resource.MondrianResource; 021 022 import java.util.List; 023 import java.util.HashSet; 024 import java.util.ArrayList; 025 import java.util.Set; 026 027 /** 028 * Definition of the <code>ToggleDrillState</code> MDX function. 029 * 030 * @author jhyde 031 * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/ToggleDrillStateFunDef.java#3 $ 032 * @since Mar 23, 2006 033 */ 034 class ToggleDrillStateFunDef extends FunDefBase { 035 static final String[] ReservedWords = new String[] {"RECURSIVE"}; 036 static final ReflectiveMultiResolver Resolver = new ReflectiveMultiResolver( 037 "ToggleDrillState", 038 "ToggleDrillState(<Set1>, <Set2>[, RECURSIVE])", 039 "Toggles the drill state of members. This function is a combination of DrillupMember and DrilldownMember.", 040 new String[]{"fxxx", "fxxxy"}, 041 ToggleDrillStateFunDef.class, 042 ReservedWords); 043 044 public ToggleDrillStateFunDef(FunDef dummyFunDef) { 045 super(dummyFunDef); 046 } 047 048 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 049 if (call.getArgCount() > 2) { 050 throw MondrianResource.instance().ToggleDrillStateRecursiveNotSupported.ex(); 051 } 052 final ListCalc listCalc0 = 053 compiler.compileList(call.getArg(0)); 054 final ListCalc listCalc1 = 055 compiler.compileList(call.getArg(1)); 056 if (((SetType) call.getType()).getArity() == 1) { 057 return new AbstractListCalc(call, new Calc[] {listCalc0, listCalc1}) { 058 public List evaluateList(Evaluator evaluator) { 059 final List<Member> list0 = listCalc0.evaluateList(evaluator); 060 final List<Member> list1 = listCalc1.evaluateList(evaluator); 061 return toggleDrillStateMembers(evaluator, list0, list1); 062 } 063 }; 064 } else { 065 return new AbstractListCalc(call, new Calc[] {listCalc0, listCalc1}) { 066 public List evaluateList(Evaluator evaluator) { 067 final List<Member[]> list0 = listCalc0.evaluateList(evaluator); 068 final List<Member> list1 = listCalc1.evaluateList(evaluator); 069 return toggleDrillStateTuples(evaluator, list0, list1); 070 } 071 }; 072 } 073 } 074 075 List<Member> toggleDrillStateMembers( 076 Evaluator evaluator, List<Member> v0, List<Member> list1) 077 { 078 if (list1.isEmpty()) { 079 return v0; 080 } 081 if (v0.isEmpty()) { 082 return v0; 083 } 084 Set<Member> set = new HashSet<Member>(); 085 set.addAll(list1); 086 List<Member> result = new ArrayList<Member>(); 087 int i = 0, n = v0.size(); 088 while (i < n) { 089 Member m = v0.get(i++); 090 result.add(m); 091 if (!set.contains(m)) { 092 continue; 093 } 094 boolean isDrilledDown = false; 095 if (i < n) { 096 Member nextMember = v0.get(i); 097 boolean strict = true; 098 if (FunUtil.isAncestorOf(m, nextMember, strict)) { 099 isDrilledDown = true; 100 } 101 } 102 if (isDrilledDown) { 103 // skip descendants of this member 104 do { 105 Member nextMember = v0.get(i); 106 boolean strict = true; 107 if (FunUtil.isAncestorOf(m, nextMember, strict)) { 108 i++; 109 } else { 110 break; 111 } 112 } while (i < n); 113 } else { 114 List<Member> children = 115 evaluator.getSchemaReader().getMemberChildren(m); 116 for (Member child : children) { 117 result.add(child); 118 } 119 } 120 } 121 return result; 122 } 123 124 List<Member[]> toggleDrillStateTuples( 125 Evaluator evaluator, List<Member[]> v0, List<Member> list1) 126 { 127 if (list1.isEmpty()) { 128 return v0; 129 } 130 if (v0.isEmpty()) { 131 return v0; 132 } 133 Set<Member> set = new HashSet<Member>(); 134 set.addAll(list1); 135 List<Member[]> result = new ArrayList<Member[]>(); 136 int i = 0, n = v0.size(); 137 while (i < n) { 138 Member[] o = v0.get(i++); 139 result.add(o); 140 Member m = null; 141 int k = -1; 142 for (int j = 0; j < o.length; j++) { 143 Member member = o[j]; 144 if (set.contains(member)) { 145 k = j; 146 m = member; 147 break; 148 } 149 } 150 if (k == -1) { 151 continue; 152 } 153 boolean isDrilledDown = false; 154 if (i < n) { 155 Member[] next = v0.get(i); 156 Member nextMember = next[k]; 157 boolean strict = true; 158 if (FunUtil.isAncestorOf(m, nextMember, strict)) { 159 isDrilledDown = true; 160 } 161 } 162 if (isDrilledDown) { 163 // skip descendants of this member 164 do { 165 Member[] next = v0.get(i); 166 Member nextMember = next[k]; 167 boolean strict = true; 168 if (FunUtil.isAncestorOf(m, nextMember, strict)) { 169 i++; 170 } else { 171 break; 172 } 173 } while (i < n); 174 } else { 175 List<Member> children = evaluator.getSchemaReader().getMemberChildren(m); 176 for (Member child : children) { 177 Member[] members = o.clone(); 178 members[k] = child; 179 result.add(members); 180 } 181 } 182 } 183 return result; 184 } 185 } 186 187 // End ToggleDrillStateFunDef.java