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.ConstantCalc;
014import mondrian.calc.impl.GenericCalc;
015import mondrian.mdx.ResolvedFunCall;
016import mondrian.olap.*;
017
018import java.util.ArrayList;
019import java.util.List;
020
021/**
022 * Definition of the tested <code>CASE</code> MDX operator.
023 *
024 * Syntax is:
025 * <blockquote><pre><code>Case
026 * When &lt;Logical Expression&gt; Then &lt;Expression&gt;
027 * [...]
028 * [Else &lt;Expression&gt;]
029 * End</code></blockquote>.
030 *
031 * @see CaseMatchFunDef
032 *
033 * @author jhyde
034 * @since Mar 23, 2006
035 */
036class CaseTestFunDef extends FunDefBase {
037    static final ResolverImpl Resolver = new ResolverImpl();
038
039    public CaseTestFunDef(FunDef dummyFunDef) {
040        super(dummyFunDef);
041    }
042
043    public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
044        final Exp[] args = call.getArgs();
045        final BooleanCalc[] conditionCalcs =
046                new BooleanCalc[args.length / 2];
047        final Calc[] exprCalcs =
048                new Calc[args.length / 2];
049        final List<Calc> calcList = new ArrayList<Calc>();
050        for (int i = 0, j = 0; i < exprCalcs.length; i++) {
051            conditionCalcs[i] =
052                    compiler.compileBoolean(args[j++]);
053            calcList.add(conditionCalcs[i]);
054            exprCalcs[i] = compiler.compile(args[j++]);
055            calcList.add(exprCalcs[i]);
056        }
057        final Calc defaultCalc =
058            args.length % 2 == 1
059            ? compiler.compileScalar(args[args.length - 1], true)
060            : ConstantCalc.constantNull(call.getType());
061        calcList.add(defaultCalc);
062        final Calc[] calcs = calcList.toArray(new Calc[calcList.size()]);
063
064        return new GenericCalc(call) {
065            public Object evaluate(Evaluator evaluator) {
066                for (int i = 0; i < conditionCalcs.length; i++) {
067                    if (conditionCalcs[i].evaluateBoolean(evaluator)) {
068                        return exprCalcs[i].evaluate(evaluator);
069                    }
070                }
071                return defaultCalc.evaluate(evaluator);
072            }
073
074            public Calc[] getCalcs() {
075                return calcs;
076            }
077        };
078    }
079
080    private static class ResolverImpl extends ResolverBase {
081        public ResolverImpl() {
082            super(
083                "_CaseTest",
084                "Case When <Logical Expression> Then <Expression> [...] [Else <Expression>] End",
085                "Evaluates various conditions, and returns the corresponding expression for the first which evaluates to true.",
086                Syntax.Case);
087        }
088
089        public FunDef resolve(
090            Exp[] args,
091            Validator validator,
092            List<Conversion> conversions)
093        {
094            if (args.length < 1) {
095                return null;
096            }
097            int j = 0;
098            int clauseCount = args.length / 2;
099            int mismatchingArgs = 0;
100            int returnType = args[1].getCategory();
101            for (int i = 0; i < clauseCount; i++) {
102                if (!validator.canConvert(
103                        j, args[j++], Category.Logical, conversions))
104                {
105                    mismatchingArgs++;
106                }
107                if (!validator.canConvert(
108                        j, args[j++], returnType, conversions))
109                {
110                    mismatchingArgs++;
111                }
112            }
113            if (j < args.length) {
114                if (!validator.canConvert(
115                        j, args[j++], returnType, conversions))
116                {
117                    mismatchingArgs++;
118                }
119            }
120            Util.assertTrue(j == args.length);
121            if (mismatchingArgs != 0) {
122                return null;
123            }
124            FunDef dummy = createDummyFunDef(this, returnType, args);
125            return new CaseTestFunDef(dummy);
126        }
127
128        public boolean requiresExpression(int k) {
129            return true;
130        }
131    }
132}
133
134// End CaseTestFunDef.java