001    /*
002    // $Id: //open/mondrian/src/main/mondrian/olap/fun/DrilldownMemberFunDef.java#12 $
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) 2004-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.calc.*;
014    import mondrian.calc.impl.AbstractListCalc;
015    import mondrian.mdx.ResolvedFunCall;
016    
017    import java.util.HashSet;
018    import java.util.Set;
019    import java.util.List;
020    import java.util.ArrayList;
021    
022    /**
023     * Definition of the <code>DrilldownMember</code> MDX function.
024     *
025     * @author Grzegorz Lojek
026     * @since 6 December, 2004
027     * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/DrilldownMemberFunDef.java#12 $
028     */
029    class DrilldownMemberFunDef extends FunDefBase {
030        static final String[] reservedWords = new String[] {"RECURSIVE"};
031        static final ReflectiveMultiResolver Resolver = new ReflectiveMultiResolver(
032                "DrilldownMember",
033                "DrilldownMember(<Set1>, <Set2>[, RECURSIVE])",
034                "Drills down the members in a set that are present in a second specified set.",
035                new String[]{"fxxx", "fxxxy"},
036                DrilldownMemberFunDef.class,
037                reservedWords);
038    
039        public DrilldownMemberFunDef(FunDef funDef) {
040            super(funDef);
041        }
042    
043        public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
044            final ListCalc listCalc1 = compiler.compileList(call.getArg(0));
045            final ListCalc listCalc2 = compiler.compileList(call.getArg(1));
046            final String literalArg = getLiteralArg(call, 2, "", reservedWords);
047            final boolean recursive = literalArg.equals("RECURSIVE");
048    
049            return new AbstractListCalc(call, new Calc[] {listCalc1, listCalc2}) {
050                public List evaluateList(Evaluator evaluator) {
051                    final List<?> list1 = listCalc1.evaluateList(evaluator);
052                    final List<Member> list2 = listCalc2.evaluateList(evaluator);
053                    return drilldownMember(list1, list2, evaluator);
054                }
055    
056                /**
057                 * Drills down an element.
058                 *
059                 * Algorithm: If object is present in a_hsSet1 then adds to result children
060                 * of the object. If flag a_bRecursive is set then this method is called
061                 * recursively for the children.
062                 *
063                 * @param element Element of a set, can be either {@link Member} or
064                 *   {@link Member}[]
065                 *
066                 *
067                 */
068                protected void drillDownObj(
069                        Evaluator evaluator,
070                        Object element,
071                        Set memberSet,
072                        List<Object> resultList) {
073                    if (null == element) {
074                        return;
075                    }
076    
077                    Member m = null;
078                    Member[] tuple;
079                    int k = -1;
080                    if (element instanceof Member) {
081                        m = (Member) element;
082                        if (!memberSet.contains(m)) {
083                            return;
084                        }
085                        tuple = null;
086                    } else {
087                        Util.assertTrue(element instanceof Member[]);
088                        tuple = (Member[]) element;
089                        m = null;
090                        for (Member member : tuple) {
091                            ++k;
092                            if (memberSet.contains(member)) {
093                                m = member;
094                                break;
095                            }
096                        }
097                        if (m == null) {
098                            //not found
099                            return;
100                        }
101                    }
102    
103                    List<Member> children = evaluator.getSchemaReader().getMemberChildren(m);
104                    for (Member member : children) {
105                        Object objNew;
106                        if (tuple == null) {
107                            objNew = member;
108                        } else {
109                            Member[] members = tuple.clone();
110                            members[k] = member;
111                            objNew = members;
112                        }
113    
114                        resultList.add(objNew);
115                        if (recursive) {
116                            drillDownObj(evaluator, objNew, memberSet, resultList);
117                        }
118                    }
119                }
120    
121                private List drilldownMember(List<?> v0, List<Member> v1, Evaluator evaluator) {
122                    if (null == v0 ||
123                        v0.isEmpty() ||
124                        null == v1 ||
125                        v1.isEmpty()) {
126                        return v0;
127                    }
128    
129                    Set<Member> set1 = new HashSet<Member>();
130                    set1.addAll(v1);
131    
132                    List<Object> result = new ArrayList<Object>();
133                    int i = 0, n = v0.size();
134                    while (i < n) {
135                        Object o = v0.get(i++);
136                        result.add(o);
137                        drillDownObj(evaluator, o, set1, result);
138                    }
139                    return result;
140                }
141            };
142        }
143    }
144    
145    // End DrilldownMemberFunDef.java