001    /*
002    // $Id: //open/mondrian/src/main/mondrian/olap/type/TupleType.java#12 $
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.type;
011    
012    import mondrian.olap.*;
013    
014    import java.util.Arrays;
015    import java.util.ArrayList;
016    import java.util.List;
017    
018    /**
019     * Tuple type.
020     *
021     * @author jhyde
022     * @since Feb 17, 2005
023     * @version $Id: //open/mondrian/src/main/mondrian/olap/type/TupleType.java#12 $
024     */
025    public class TupleType implements Type {
026        public final Type[] elementTypes;
027        private final String digest;
028    
029        /**
030         * Creates a type representing a tuple whose fields are the given types.
031         *
032         * @param elementTypes Array of types of the members in this tuple
033         */
034        public TupleType(Type[] elementTypes) {
035            assert elementTypes != null;
036            this.elementTypes = elementTypes.clone();
037    
038            final StringBuilder buf = new StringBuilder();
039            buf.append("TupleType<");
040            int k = 0;
041            for (Type elementType : elementTypes) {
042                if (k++ > 0) {
043                    buf.append(", ");
044                }
045                buf.append(elementType);
046            }
047            buf.append(">");
048            digest = buf.toString();
049        }
050    
051        public String toString() {
052            return digest;
053        }
054    
055        public boolean equals(Object obj) {
056            if (obj instanceof TupleType) {
057                TupleType that = (TupleType) obj;
058                return Arrays.equals(this.elementTypes, that.elementTypes);
059            } else {
060                return false;
061            }
062        }
063    
064        public int hashCode() {
065            return digest.hashCode();
066        }
067    
068        public boolean usesDimension(Dimension dimension, boolean definitely) {
069            for (Type elementType : elementTypes) {
070                if (elementType.usesDimension(dimension, definitely)) {
071                    return true;
072                }
073            }
074            return false;
075        }
076    
077        public Dimension getDimension() {
078            throw new UnsupportedOperationException();
079        }
080    
081        public Hierarchy getHierarchy() {
082            throw new UnsupportedOperationException();
083        }
084    
085        public Level getLevel() {
086            throw new UnsupportedOperationException();
087        }
088    
089        public Type getValueType() {
090            for (Type elementType : elementTypes) {
091                if (elementType instanceof MemberType) {
092                    MemberType memberType = (MemberType) elementType;
093                    Dimension dimension = memberType.getDimension();
094                    if (dimension != null && dimension.isMeasures()) {
095                        return memberType.getValueType();
096                    }
097                }
098            }
099            return new ScalarType();
100        }
101    
102        public Type computeCommonType(Type type, int[] conversionCount) {
103            if (type instanceof ScalarType) {
104                return getValueType().computeCommonType(type, conversionCount);
105            }
106            if (type instanceof MemberType) {
107                return commonTupleType(
108                    new TupleType(new Type[]{type}),
109                    conversionCount);
110            }
111            if (!(type instanceof TupleType)) {
112                return null;
113            }
114            return commonTupleType(type, conversionCount);
115        }
116    
117        private Type commonTupleType(Type type, int[] conversionCount) {
118            TupleType that = (TupleType) type;
119    
120            if (this.elementTypes.length < that.elementTypes.length) {
121                return createCommonTupleType(that, conversionCount);
122            }
123            return that.createCommonTupleType(this, conversionCount);
124        }
125    
126        private Type createCommonTupleType(TupleType that, int[] conversionCount) {
127            final List<Type> elementTypes = new ArrayList<Type>();
128            for (int i = 0; i < this.elementTypes.length; i++) {
129                Type commonType = this.elementTypes[i].computeCommonType(
130                        that.elementTypes[i], conversionCount);
131                elementTypes.add(commonType);
132                if (commonType == null) {
133                    return null;
134                }
135            }
136            if (elementTypes.size() < that.elementTypes.length) {
137                for (int i = elementTypes.size(); i < that.elementTypes.length; i++) {
138                    elementTypes.add(new ScalarType());
139                }
140            }
141            return new TupleType(
142                elementTypes.toArray(new Type[elementTypes.size()]));
143        }
144    }
145    
146    // End TupleType.java