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) 2011-2012 Pentaho
008// All Rights Reserved.
009*/
010package mondrian.calc.impl;
011
012import mondrian.calc.TupleIterator;
013import mondrian.calc.TupleList;
014import mondrian.olap.Member;
015import mondrian.olap.Util;
016
017import java.util.*;
018
019/**
020 * Implementation of {@link mondrian.calc.TupleList} based on a list of
021 * {@code List<Member>} tuples.
022 *
023 * @author jhyde
024*/
025public class DelegatingTupleList extends AbstractTupleList
026{
027    private final List<List<Member>> list;
028
029    /**
030     * Creates a DelegatingTupleList.
031     *
032     * @param arity Arity
033     * @param list Backing list
034     */
035    public DelegatingTupleList(int arity, List<List<Member>> list) {
036        super(arity);
037        this.list = list;
038        assert list.isEmpty()
039               || (list.get(0) instanceof List
040                   && (list.get(0).isEmpty()
041                   || list.get(0).get(0) == null
042                   || list.get(0).get(0) instanceof Member))
043            : "sanity check failed: " + list;
044    }
045
046    @Override
047    protected TupleIterator tupleIteratorInternal() {
048        return new AbstractTupleListIterator();
049    }
050
051    @Override
052    public TupleList subList(int fromIndex, int toIndex) {
053        return new DelegatingTupleList(arity, list.subList(fromIndex, toIndex));
054    }
055
056    @Override
057    public List<Member> get(int index) {
058        return list.get(index);
059    }
060
061    @Override
062    public int size() {
063        return list.size();
064    }
065
066    public List<Member> slice(final int column) {
067        return new AbstractList<Member>() {
068            @Override
069            public Member get(int index) {
070                return list.get(index).get(column);
071            }
072            @Override
073            public int size() {
074                return list.size();
075            }
076            public Member set(int index, Member element) {
077                List<Member> subList = list.get(index);
078                if (subList.size() == 1) {
079                    // The sub list is probably a singleton list.
080                    // calling set() on it will fail. We have to
081                    // create a new singleton list.
082                    return list.set(index, Collections.singletonList(element))
083                        .get(0);
084                }
085                return subList.set(column, element);
086            };
087        };
088    }
089
090    public TupleList cloneList(int capacity) {
091        return new DelegatingTupleList(
092            arity,
093            capacity < 0
094                ? new ArrayList<List<Member>>(list)
095                : new ArrayList<List<Member>>(capacity));
096    }
097
098    @Override
099    public List<Member> set(int index, List<Member> element) {
100        return list.set(index, element);
101    }
102
103    @Override
104    public void add(int index, List<Member> element) {
105        list.add(index, element);
106    }
107
108    public void addTuple(Member... members) {
109        list.add(Util.flatList(members));
110    }
111
112    public TupleList project(final int[] destIndices) {
113        return new DelegatingTupleList(
114            destIndices.length,
115            new AbstractList<List<Member>>() {
116                public List<Member> get(final int index) {
117                    return new AbstractList<Member>() {
118                        public Member get(int column) {
119                            return list.get(index).get(destIndices[column]);
120                        }
121
122                        public int size() {
123                            return destIndices.length;
124                        }
125
126                        public Member set(int column, Member element) {
127                            return list.get(index).set(index, element);
128                        };
129                    };
130                }
131
132                public List<Member> set(int index, List<Member> element) {
133                    return list.set(index, element);
134                };
135
136                public int size() {
137                    return list.size();
138                }
139            }
140        );
141    }
142
143    public TupleList withPositionCallback(
144        final PositionCallback positionCallback)
145    {
146        return new DelegatingTupleList(
147            arity,
148            new AbstractList<List<Member>>() {
149                @Override
150                public List<Member> get(int index) {
151                    positionCallback.onPosition(index);
152                    return list.get(index);
153                }
154
155                @Override
156                public int size() {
157                    return list.size();
158                }
159
160                @Override
161                public List<Member> set(int index, List<Member> element) {
162                    positionCallback.onPosition(index);
163                    return list.set(index, element);
164                }
165
166                @Override
167                public void add(int index, List<Member> element) {
168                    positionCallback.onPosition(index);
169                    list.add(index, element);
170                }
171
172                @Override
173                public List<Member> remove(int index) {
174                    positionCallback.onPosition(index);
175                    return list.remove(index);
176                }
177            }
178        );
179    }
180}
181
182// End DelegatingTupleList.java