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.type;
012
013import mondrian.olap.*;
014
015/**
016 * The type of an expression which represents a member.
017 *
018 * @author jhyde
019 * @since Feb 17, 2005
020 */
021public class MemberType implements Type {
022    private final Hierarchy hierarchy;
023    private final Dimension dimension;
024    private final Level level;
025    private final Member member;
026    private final String digest;
027
028    public static final MemberType Unknown =
029        new MemberType(null, null, null, null);
030
031    /**
032     * Creates a type representing a member.
033     *
034     * @param dimension Dimension the member belongs to, or null if not known
035     * @param hierarchy Hierarchy the member belongs to, or null if not known
036     * @param level Level the member belongs to, or null if not known
037     * @param member The precise member, or null if not known
038     */
039    public MemberType(
040        Dimension dimension,
041        Hierarchy hierarchy,
042        Level level,
043        Member member)
044    {
045        this.dimension = dimension;
046        this.hierarchy = hierarchy;
047        this.level = level;
048        this.member = member;
049        if (member != null) {
050            Util.assertPrecondition(level != null);
051            Util.assertPrecondition(member.getLevel() == level);
052        }
053        if (level != null) {
054            Util.assertPrecondition(hierarchy != null);
055            Util.assertPrecondition(level.getHierarchy() == hierarchy);
056        }
057        if (hierarchy != null) {
058            Util.assertPrecondition(dimension != null);
059            Util.assertPrecondition(hierarchy.getDimension() == dimension);
060        }
061        StringBuilder buf = new StringBuilder("MemberType<");
062        if (member != null) {
063            buf.append("member=").append(member.getUniqueName());
064        } else if (level != null) {
065            buf.append("level=").append(level.getUniqueName());
066        } else if (hierarchy != null) {
067            buf.append("hierarchy=").append(hierarchy.getUniqueName());
068        } else if (dimension != null) {
069            buf.append("dimension=").append(dimension.getUniqueName());
070        }
071        buf.append(">");
072        this.digest = buf.toString();
073    }
074
075    public static MemberType forDimension(Dimension dimension) {
076        return new MemberType(dimension, null, null, null);
077    }
078
079    public static MemberType forHierarchy(Hierarchy hierarchy) {
080        final Dimension dimension;
081        if (hierarchy == null) {
082            dimension = null;
083        } else {
084            dimension = hierarchy.getDimension();
085        }
086        return new MemberType(dimension, hierarchy, null, null);
087    }
088
089    public static MemberType forLevel(Level level) {
090        final Dimension dimension;
091        final Hierarchy hierarchy;
092        if (level == null) {
093            dimension = null;
094            hierarchy = null;
095        } else {
096            dimension = level.getDimension();
097            hierarchy = level.getHierarchy();
098        }
099        return new MemberType(dimension, hierarchy, level, null);
100    }
101
102    public static MemberType forMember(Member member) {
103        final Dimension dimension;
104        final Hierarchy hierarchy;
105        final Level level;
106        if (member == null) {
107            dimension = null;
108            hierarchy = null;
109            level = null;
110        } else {
111            dimension = member.getDimension();
112            hierarchy = member.getHierarchy();
113            level = member.getLevel();
114        }
115        return new MemberType(dimension, hierarchy, level, member);
116    }
117
118    public String toString() {
119        return digest;
120    }
121
122    public Hierarchy getHierarchy() {
123        return hierarchy;
124    }
125
126    public Level getLevel() {
127        return level;
128    }
129
130    public Member getMember() {
131        return member;
132    }
133
134    public boolean usesDimension(Dimension dimension, boolean definitely) {
135        return this.dimension == dimension
136            || (!definitely && this.dimension == null);
137    }
138
139    public boolean usesHierarchy(Hierarchy hierarchy, boolean definitely) {
140        return this.hierarchy == hierarchy
141            || (!definitely
142                && this.hierarchy == null
143                && (this.dimension == null
144                    || this.dimension == hierarchy.getDimension()));
145    }
146
147    public Type getValueType() {
148        // todo: when members have more type information (double vs. integer
149        // vs. string), return better type if member != null.
150        return new ScalarType();
151    }
152
153    public Dimension getDimension() {
154        return dimension;
155    }
156
157    public static MemberType forType(Type type) {
158        if (type instanceof MemberType) {
159            return (MemberType) type;
160        } else {
161            return new MemberType(
162                type.getDimension(),
163                type.getHierarchy(),
164                type.getLevel(),
165                null);
166        }
167    }
168
169    public Type computeCommonType(Type type, int[] conversionCount) {
170        if (type instanceof ScalarType) {
171            return getValueType().computeCommonType(type, conversionCount);
172        }
173        if (type instanceof TupleType) {
174            return type.computeCommonType(this, conversionCount);
175        }
176        if (!(type instanceof MemberType)) {
177            return null;
178        }
179        MemberType that = (MemberType) type;
180        if (this.getMember() != null
181            && this.getMember().equals(that.getMember()))
182        {
183            return this;
184        }
185        if (this.getLevel() != null
186            && this.getLevel().equals(that.getLevel()))
187        {
188            return new MemberType(
189                this.getDimension(),
190                this.getHierarchy(),
191                this.getLevel(),
192                null);
193        }
194        if (this.getHierarchy() != null
195            && this.getHierarchy().equals(that.getHierarchy()))
196        {
197            return new MemberType(
198                this.getDimension(),
199                this.getHierarchy(),
200                null,
201                null);
202        }
203        if (this.getDimension() != null
204            && this.getDimension().equals(that.getDimension()))
205        {
206            return new MemberType(
207                this.getDimension(),
208                null,
209                null,
210                null);
211        }
212        return MemberType.Unknown;
213    }
214
215    public boolean isInstance(Object value) {
216        return value instanceof Member
217            && (level == null
218            || ((Member) value).getLevel().equals(level))
219            && (hierarchy == null
220            || ((Member) value).getHierarchy().equals(hierarchy))
221            && (dimension == null
222            || ((Member) value).getDimension().equals(dimension));
223    }
224
225    public int getArity() {
226        return 1;
227    }
228}
229
230// End MemberType.java