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