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.AbstractMemberCalc;
014import mondrian.mdx.ResolvedFunCall;
015import mondrian.olap.*;
016import mondrian.olap.type.LevelType;
017import mondrian.olap.type.Type;
018
019/**
020 * Definition of the <code>Ancestor</code> MDX function.
021 *
022 * @author jhyde
023 * @since Mar 23, 2006
024 */
025class AncestorFunDef extends FunDefBase {
026    static final ReflectiveMultiResolver Resolver =
027        new ReflectiveMultiResolver(
028            "Ancestor",
029            "Ancestor(<Member>, {<Level>|<Numeric Expression>})",
030            "Returns the ancestor of a member at a specified level.",
031            new String[] {"fmml", "fmmn"},
032            AncestorFunDef.class);
033
034    public AncestorFunDef(FunDef dummyFunDef) {
035        super(dummyFunDef);
036    }
037
038    public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
039        final MemberCalc memberCalc =
040            compiler.compileMember(call.getArg(0));
041        final Type type1 = call.getArg(1).getType();
042        if (type1 instanceof LevelType) {
043            final LevelCalc levelCalc =
044                compiler.compileLevel(call.getArg(1));
045            return new AbstractMemberCalc(
046                call, new Calc[] {memberCalc, levelCalc})
047            {
048                public Member evaluateMember(Evaluator evaluator) {
049                    Level level = levelCalc.evaluateLevel(evaluator);
050                    Member member = memberCalc.evaluateMember(evaluator);
051                    int distance =
052                        member.getLevel().getDepth() - level.getDepth();
053                    return ancestor(evaluator, member, distance, level);
054                }
055            };
056        } else {
057            final IntegerCalc distanceCalc =
058                compiler.compileInteger(call.getArg(1));
059            return new AbstractMemberCalc(
060                call, new Calc[] {memberCalc, distanceCalc})
061            {
062                public Member evaluateMember(Evaluator evaluator) {
063                    int distance = distanceCalc.evaluateInteger(evaluator);
064                    Member member = memberCalc.evaluateMember(evaluator);
065                    return ancestor(evaluator, member, distance, null);
066                }
067            };
068        }
069    }
070}
071
072// End AncestorFunDef.java