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-2010 Pentaho and others
008// All Rights Reserved.
009*/
010package mondrian.udf;
011
012import mondrian.olap.*;
013import mondrian.olap.type.*;
014import mondrian.spi.UserDefinedFunction;
015import mondrian.util.Format;
016
017import java.util.*;
018
019/**
020 * User-defined function <code>CurrentDateMember</code>.  Arguments to the
021 * function are as follows:
022 *
023 * <blockquote>
024 * <code>
025 * CurrentDateMember(&lt;Hierarchy&gt;, &lt;FormatString&gt;[, &lt;Find&gt;)
026 * returns &lt;Member&gt;
027 * </code>
028 * </blockquote>
029 *
030 * The function returns the member from the specified hierarchy that matches
031 * the current date, to the granularity specified by the &lt;FormatString&gt;.
032 *
033 * The format string conforms to the format string implemented by
034 * {@link Format}.
035 *
036 * @author Zelaine Fong
037 */
038public class CurrentDateMemberUdf implements UserDefinedFunction {
039    private Object resultDateMember = null;
040
041    public Object execute(Evaluator evaluator, Argument[] arguments) {
042        if (resultDateMember != null) {
043            return resultDateMember;
044        }
045
046        // determine the current date
047        Object formatArg = arguments[1].evaluateScalar(evaluator);
048
049        final Locale locale = Locale.getDefault();
050        final Format format = new Format((String) formatArg, locale);
051        String currDateStr = format.format(getDate(evaluator, arguments));
052
053        // determine the match type
054        MatchType matchType;
055        if (arguments.length == 3) {
056            String matchStr = arguments[2].evaluateScalar(evaluator).toString();
057            matchType = Enum.valueOf(MatchType.class, matchStr);
058        } else {
059            matchType = MatchType.EXACT;
060        }
061
062        List<Id.Segment> uniqueNames = Util.parseIdentifier(currDateStr);
063        resultDateMember =
064            evaluator.getSchemaReader().getMemberByUniqueName(
065                uniqueNames, false, matchType);
066        if (resultDateMember != null) {
067            return resultDateMember;
068        }
069
070        // if there is no matching member, return the null member for
071        // the specified dimension/hierarchy
072        Object arg0 = arguments[0].evaluate(evaluator);
073        if (arg0 instanceof Hierarchy) {
074            resultDateMember = ((Hierarchy) arg0).getNullMember();
075        } else {
076            resultDateMember =
077                ((Dimension) arg0).getHierarchy().getNullMember();
078        }
079        return resultDateMember;
080    }
081
082    /*
083     * Package private function created for proper testing.
084     */
085    Date getDate(Evaluator evaluator, Argument[] arguments) {
086        return evaluator.getQueryStartTime();
087    }
088
089    public String getDescription() {
090        return "Returns the closest or exact member within the specified "
091            + "dimension corresponding to the current date, in the format "
092            + "specified by the format parameter. "
093            + "Format strings are the same as used by the MDX Format function, "
094            + "namely the Visual Basic format strings. "
095            + "See http://www.apostate.com/programming/vb-format.html.";
096    }
097
098    public String getName() {
099        return "CurrentDateMember";
100    }
101
102    public Type[] getParameterTypes() {
103        return new Type[] {
104            new HierarchyType(null, null),
105            new StringType(),
106            new SymbolType()
107        };
108    }
109
110    public String[] getReservedWords() {
111        return new String[] {
112            "EXACT",
113            "BEFORE",
114            "AFTER"
115        };
116    }
117
118    public Type getReturnType(Type[] parameterTypes) {
119        return MemberType.Unknown;
120    }
121
122    public Syntax getSyntax() {
123        return Syntax.Function;
124    }
125}
126
127// End CurrentDateMemberUdf.java