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.util;
011
012import mondrian.olap.Util;
013
014import java.lang.reflect.Array;
015import java.util.*;
016
017/**
018 * Implementation of {@link java.util.List} for transposing an array of
019 * lists.
020 *
021 * @author Luis F. Canals
022 * @since Dec, 2007
023 */
024public class TraversalList<T> extends UnsupportedList<List<T>> {
025    private boolean asInternalArray = false;
026    private List<T>[] internalArray = null;
027    private final List<T>[] lists;
028    private final Class<T> clazz;
029    private final T[] tmpArray; // work space; not threadsafe even for reads
030
031    public TraversalList(
032        final List<T>[] lists,
033        Class<T> clazz)
034    {
035        this.lists = lists;
036        this.clazz = clazz;
037        //noinspection unchecked
038        this.tmpArray = (T[]) Array.newInstance(clazz, lists.length);
039    }
040
041    public List<T> get(int index) {
042        if (this.asInternalArray) {
043            return internalArray[index];
044        } else {
045            for (int i = 0; i < lists.length; i++) {
046                tmpArray[i] = lists[i].get(index);
047            }
048            return Util.flatList(tmpArray.clone());
049        }
050    }
051
052    public Iterator<List<T>> iterator() {
053        return new Iterator<List<T>>() {
054            private int currentIndex = 0;
055            private List<T> precalculated;
056
057            public List<T> next() {
058                if (precalculated != null) {
059                    final List<T> t = precalculated;
060                    precalculated = null;
061                    currentIndex++;
062                    return t;
063                } else {
064                    return get(currentIndex++);
065                }
066            }
067
068            public boolean hasNext() {
069                try {
070                    precalculated = get(currentIndex);
071                    return true;
072                } catch (IndexOutOfBoundsException e) {
073                    return false;
074                }
075            }
076
077            public void remove() {
078                throw new UnsupportedOperationException();
079            }
080        };
081    }
082
083    // Used by Collections.sort
084    public ListIterator<List<T>> listIterator(final int index) {
085        return new ListItr(index) {
086            public void set(final List<T> l) {
087                TraversalList.this.set(cursor - 1, l);
088            }
089        };
090    }
091
092    // Used by Collections.sort
093    public ListIterator<List<T>> listIterator() {
094        return new ListItr(0) {
095            public void set(final List<T> l) {
096                TraversalList.this.set(cursor - 1, l);
097            }
098        };
099    }
100
101    public int size() {
102        return lists[0].size();
103    }
104
105    public List<List<T>> subList(final int first, final int last) {
106        return new AbstractList<List<T>>() {
107            public List<T> get(int index) {
108                return TraversalList.this.get(index + first);
109            }
110            public int size() {
111                return last - first;
112            }
113        };
114    }
115
116    private List<T>[] materialize(List<T>[] a) {
117        final List<T>[] array;
118        if (a != null
119            && a.length == size()
120            && a.getClass().getComponentType() == clazz)
121        {
122            array = a;
123        } else {
124            //noinspection unchecked
125            array = (List<T>[]) new List[this.size()];
126        }
127        int k = 0;
128        for (List<T> x : this) {
129            array[k++] = x;
130        }
131        this.asInternalArray = true;
132        this.internalArray = array;
133        return array;
134    }
135
136    @Override
137    public <S> S[] toArray(S[] a) {
138        // Our requirements are stronger than the general toArray(T[] a)
139        // contract. We will use the user's array 'a' only if it is PRECISELY
140        // the right type and size; otherwise we will allocate our own array.
141        //noinspection unchecked
142        return (S[]) materialize((List<T>[]) a);
143    }
144
145    public Object[] toArray() {
146        return materialize(null);
147    }
148
149    // Used by Collections.sort
150    public List<T> set(final int index, List<T> l) {
151        if (this.asInternalArray) {
152            final List<T> previous = this.internalArray[index];
153            this.internalArray[index] = l;
154            return previous;
155        } else {
156            throw new UnsupportedOperationException();
157        }
158    }
159}
160
161// End TraversalList.java