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) 2005-2005 Julian Hyde
008// Copyright (C) 2005-2011 Pentaho
009// All Rights Reserved.
010*/
011package mondrian.olap.fun;
012
013import mondrian.calc.*;
014import mondrian.calc.impl.AbstractListCalc;
015import mondrian.calc.impl.UnaryTupleList;
016import mondrian.mdx.ResolvedFunCall;
017import mondrian.olap.DimensionType;
018import mondrian.olap.*;
019import mondrian.olap.LevelType;
020import mondrian.olap.type.*;
021import mondrian.resource.MondrianResource;
022import mondrian.rolap.RolapCube;
023import mondrian.rolap.RolapHierarchy;
024
025/**
026 * Definition of <code>Ytd</code>, <code>Qtd</code>, <code>Mtd</code>,
027 * and <code>Wtd</code> MDX builtin functions.
028 *
029 * @author jhyde
030 * @since Mar 23, 2006
031 */
032class XtdFunDef extends FunDefBase {
033    private final LevelType levelType;
034
035    static final ResolverImpl MtdResolver =
036        new ResolverImpl(
037            "Mtd",
038            "Mtd([<Member>])",
039            "A shortcut function for the PeriodsToDate function that specifies the level to be Month.",
040            new String[]{"fx", "fxm"},
041            LevelType.TimeMonths);
042
043    static final ResolverImpl QtdResolver =
044        new ResolverImpl(
045            "Qtd",
046            "Qtd([<Member>])",
047            "A shortcut function for the PeriodsToDate function that specifies the level to be Quarter.",
048            new String[]{"fx", "fxm"},
049            LevelType.TimeQuarters);
050
051    static final ResolverImpl WtdResolver =
052        new ResolverImpl(
053            "Wtd",
054            "Wtd([<Member>])",
055            "A shortcut function for the PeriodsToDate function that specifies the level to be Week.",
056            new String[]{"fx", "fxm"},
057            LevelType.TimeWeeks);
058
059    static final ResolverImpl YtdResolver =
060        new ResolverImpl(
061            "Ytd",
062            "Ytd([<Member>])",
063            "A shortcut function for the PeriodsToDate function that specifies the level to be Year.",
064            new String[]{"fx", "fxm"},
065            LevelType.TimeYears);
066
067    public XtdFunDef(FunDef dummyFunDef, LevelType levelType) {
068        super(dummyFunDef);
069        this.levelType = levelType;
070    }
071
072    public Type getResultType(Validator validator, Exp[] args) {
073        if (args.length == 0) {
074            // With no args, the default implementation cannot
075            // guess the hierarchy.
076            RolapHierarchy defaultTimeHierarchy =
077                ((RolapCube) validator.getQuery().getCube()).getTimeHierarchy(
078                    getName());
079            return new SetType(MemberType.forHierarchy(defaultTimeHierarchy));
080        }
081        final Type type = args[0].getType();
082        if (type.getDimension().getDimensionType()
083            != DimensionType.TimeDimension)
084        {
085            throw MondrianResource.instance().TimeArgNeeded.ex(getName());
086        }
087        return super.getResultType(validator, args);
088    }
089
090    private Level getLevel(Evaluator evaluator) {
091        switch (levelType) {
092        case TimeYears:
093            return evaluator.getCube().getYearLevel();
094        case TimeQuarters:
095            return evaluator.getCube().getQuarterLevel();
096        case TimeMonths:
097            return evaluator.getCube().getMonthLevel();
098        case TimeWeeks:
099            return evaluator.getCube().getWeekLevel();
100        case TimeDays:
101            return evaluator.getCube().getWeekLevel();
102        default:
103            throw Util.badValue(levelType);
104        }
105    }
106
107    public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
108        final Level level = getLevel(compiler.getEvaluator());
109        switch (call.getArgCount()) {
110        case 0:
111            return new AbstractListCalc(call, new Calc[0]) {
112                public TupleList evaluateList(Evaluator evaluator) {
113                    return new UnaryTupleList(
114                        periodsToDate(evaluator, level, null));
115                }
116
117                public boolean dependsOn(Hierarchy hierarchy) {
118                    return hierarchy.getDimension().getDimensionType()
119                        == mondrian.olap.DimensionType.TimeDimension;
120                }
121            };
122        default:
123            final MemberCalc memberCalc =
124                compiler.compileMember(call.getArg(0));
125            return new AbstractListCalc(call, new Calc[] {memberCalc}) {
126                public TupleList evaluateList(Evaluator evaluator) {
127                    return new UnaryTupleList(
128                        periodsToDate(
129                            evaluator,
130                            level,
131                            memberCalc.evaluateMember(evaluator)));
132                }
133            };
134        }
135    }
136
137    private static class ResolverImpl extends MultiResolver {
138        private final LevelType levelType;
139
140        public ResolverImpl(
141            String name,
142            String signature,
143            String description,
144            String[] signatures,
145            LevelType levelType)
146        {
147            super(name, signature, description, signatures);
148            this.levelType = levelType;
149        }
150
151        protected FunDef createFunDef(Exp[] args, FunDef dummyFunDef) {
152            return new XtdFunDef(dummyFunDef, levelType);
153        }
154    }
155}
156
157// End XtdFunDef.java