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) 2012-2013 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.olap.type.LevelType;
017import mondrian.olap.type.Type;
018
019import java.util.ArrayList;
020import java.util.List;
021
022
023/**
024 * Definition of the <code>Ancestors</code> MDX function.
025 *
026 * @author lboudreau
027 * @since Nov 27 2012
028 */
029class AncestorsFunDef extends FunDefBase {
030    static final ReflectiveMultiResolver Resolver =
031        new ReflectiveMultiResolver(
032            "Ancestors",
033            "Ancestors(<Member>, {<Level>|<Numeric Expression>})",
034            "Returns the set of all ancestors of a specified member at a specified level or at a specified distance from the member",
035            new String[] {"fxml", "fxmn"},
036            AncestorsFunDef.class);
037
038    public AncestorsFunDef(FunDef dummyFunDef) {
039        super(dummyFunDef);
040    }
041
042    public int getReturnCategory() {
043        return Category.Set;
044    }
045
046    public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
047        final MemberCalc memberCalc =
048            compiler.compileMember(call.getArg(0));
049        final Type type1 = call.getArg(1).getType();
050        if (type1 instanceof LevelType) {
051            final LevelCalc levelCalc =
052                compiler.compileLevel(call.getArg(1));
053            return new AbstractListCalc(
054                call, new Calc[] {memberCalc, levelCalc})
055            {
056                public TupleList evaluateList(Evaluator evaluator) {
057                    Level level = levelCalc.evaluateLevel(evaluator);
058                    Member member = memberCalc.evaluateMember(evaluator);
059                    int distance =
060                        member.getDepth() - level.getDepth();
061                    List<Member> ancestors = new ArrayList<Member>();
062                    for (int curDist = 1; curDist <= distance; curDist++) {
063                        ancestors.add(
064                            ancestor(evaluator, member, curDist, null));
065                    }
066                    return TupleCollections.asTupleList(ancestors);
067                }
068            };
069        } else {
070            final IntegerCalc distanceCalc =
071                compiler.compileInteger(call.getArg(1));
072            return new AbstractListCalc(
073                call, new Calc[] {memberCalc, distanceCalc})
074            {
075                public TupleList evaluateList(Evaluator evaluator) {
076                    Member member = memberCalc.evaluateMember(evaluator);
077                    int distance = distanceCalc.evaluateInteger(evaluator);
078                    List<Member> ancestors = new ArrayList<Member>();
079                    for (int curDist = 1; curDist <= distance; curDist++) {
080                        ancestors.add(
081                            ancestor(evaluator, member, curDist, null));
082                    }
083                    return TupleCollections.asTupleList(ancestors);
084                }
085            };
086        }
087    }
088}
089
090// End AncestorsFunDef.java