// 
// Decompiled by Procyon v0.6.0
// 

package it.unimi.dsi.fastutil.doubles;

import java.util.Spliterator;
import java.io.Serializable;
import java.util.Arrays;
import java.util.NoSuchElementException;
import java.util.ListIterator;
import java.util.Objects;
import java.util.List;
import it.unimi.dsi.fastutil.HashCommon;
import java.util.function.DoubleConsumer;
import java.util.RandomAccess;
import java.util.Iterator;
import java.util.Collection;

public abstract class AbstractDoubleList extends AbstractDoubleCollection implements DoubleList, DoubleStack
{
    protected AbstractDoubleList() {
    }
    
    protected void ensureIndex(final int index) {
        if (index < 0) {
            throw new IndexOutOfBoundsException("Index (" + index + ") is negative");
        }
        if (index > this.size()) {
            throw new IndexOutOfBoundsException("Index (" + index + ") is greater than list size (" + this.size() + ")");
        }
    }
    
    protected void ensureRestrictedIndex(final int index) {
        if (index < 0) {
            throw new IndexOutOfBoundsException("Index (" + index + ") is negative");
        }
        if (index >= this.size()) {
            throw new IndexOutOfBoundsException("Index (" + index + ") is greater than or equal to list size (" + this.size() + ")");
        }
    }
    
    @Override
    public void add(final int index, final double k) {
        throw new UnsupportedOperationException();
    }
    
    @Override
    public boolean add(final double k) {
        this.add(this.size(), k);
        return true;
    }
    
    @Override
    public double removeDouble(final int i) {
        throw new UnsupportedOperationException();
    }
    
    @Override
    public double set(final int index, final double k) {
        throw new UnsupportedOperationException();
    }
    
    @Override
    public boolean addAll(int index, final Collection<? extends Double> c) {
        if (c instanceof DoubleCollection) {
            return this.addAll(index, (DoubleCollection)c);
        }
        this.ensureIndex(index);
        final Iterator<? extends Double> i = c.iterator();
        final boolean retVal = i.hasNext();
        while (i.hasNext()) {
            this.add(index++, (double)i.next());
        }
        return retVal;
    }
    
    @Override
    public boolean addAll(final Collection<? extends Double> c) {
        return this.addAll(this.size(), c);
    }
    
    @Override
    public DoubleListIterator iterator() {
        return this.listIterator();
    }
    
    @Override
    public DoubleListIterator listIterator() {
        return this.listIterator(0);
    }
    
    @Override
    public DoubleListIterator listIterator(final int index) {
        this.ensureIndex(index);
        return new DoubleIterators.AbstractIndexBasedListIterator(0, index) {
            @Override
            protected final double get(final int i) {
                return AbstractDoubleList.this.getDouble(i);
            }
            
            @Override
            protected final void add(final int i, final double k) {
                AbstractDoubleList.this.add(i, k);
            }
            
            @Override
            protected final void set(final int i, final double k) {
                AbstractDoubleList.this.set(i, k);
            }
            
            @Override
            protected final void remove(final int i) {
                AbstractDoubleList.this.removeDouble(i);
            }
            
            @Override
            protected final int getMaxPos() {
                return AbstractDoubleList.this.size();
            }
        };
    }
    
    @Override
    public boolean contains(final double k) {
        return this.indexOf(k) >= 0;
    }
    
    @Override
    public int indexOf(final double k) {
        final DoubleListIterator i = this.listIterator();
        while (i.hasNext()) {
            final double e = i.nextDouble();
            if (Double.doubleToLongBits(k) == Double.doubleToLongBits(e)) {
                return i.previousIndex();
            }
        }
        return -1;
    }
    
    @Override
    public int lastIndexOf(final double k) {
        final DoubleListIterator i = this.listIterator(this.size());
        while (i.hasPrevious()) {
            final double e = i.previousDouble();
            if (Double.doubleToLongBits(k) == Double.doubleToLongBits(e)) {
                return i.nextIndex();
            }
        }
        return -1;
    }
    
    @Override
    public void size(final int size) {
        int i = this.size();
        if (size > i) {
            while (i++ < size) {
                this.add(0.0);
            }
        }
        else {
            while (i-- != size) {
                this.removeDouble(i);
            }
        }
    }
    
    @Override
    public DoubleList subList(final int from, final int to) {
        this.ensureIndex(from);
        this.ensureIndex(to);
        if (from > to) {
            throw new IndexOutOfBoundsException("Start index (" + from + ") is greater than end index (" + to + ")");
        }
        return (this instanceof RandomAccess) ? new DoubleRandomAccessSubList(this, from, to) : new DoubleSubList(this, from, to);
    }
    
    @Override
    public void forEach(final DoubleConsumer action) {
        if (this instanceof RandomAccess) {
            for (int i = 0, max = this.size(); i < max; ++i) {
                action.accept(this.getDouble(i));
            }
        }
        else {
            super.forEach(action);
        }
    }
    
    @Override
    public void removeElements(final int from, final int to) {
        this.ensureIndex(to);
        final DoubleListIterator i = this.listIterator(from);
        int n = to - from;
        if (n < 0) {
            throw new IllegalArgumentException("Start index (" + from + ") is greater than end index (" + to + ")");
        }
        while (n-- != 0) {
            i.nextDouble();
            i.remove();
        }
    }
    
    @Override
    public void addElements(int index, final double[] a, int offset, int length) {
        this.ensureIndex(index);
        DoubleArrays.ensureOffsetLength(a, offset, length);
        if (this instanceof RandomAccess) {
            while (length-- != 0) {
                this.add(index++, a[offset++]);
            }
        }
        else {
            final DoubleListIterator iter = this.listIterator(index);
            while (length-- != 0) {
                iter.add(a[offset++]);
            }
        }
    }
    
    @Override
    public void addElements(final int index, final double[] a) {
        this.addElements(index, a, 0, a.length);
    }
    
    @Override
    public void getElements(final int from, final double[] a, int offset, int length) {
        this.ensureIndex(from);
        DoubleArrays.ensureOffsetLength(a, offset, length);
        if (from + length > this.size()) {
            throw new IndexOutOfBoundsException("End index (" + (from + length) + ") is greater than list size (" + this.size() + ")");
        }
        if (this instanceof RandomAccess) {
            int current = from;
            while (length-- != 0) {
                a[offset++] = this.getDouble(current++);
            }
        }
        else {
            final DoubleListIterator i = this.listIterator(from);
            while (length-- != 0) {
                a[offset++] = i.nextDouble();
            }
        }
    }
    
    @Override
    public void setElements(final int index, final double[] a, final int offset, final int length) {
        this.ensureIndex(index);
        DoubleArrays.ensureOffsetLength(a, offset, length);
        if (index + length > this.size()) {
            throw new IndexOutOfBoundsException("End index (" + (index + length) + ") is greater than list size (" + this.size() + ")");
        }
        if (this instanceof RandomAccess) {
            for (int i = 0; i < length; ++i) {
                this.set(i + index, a[i + offset]);
            }
        }
        else {
            final DoubleListIterator iter = this.listIterator(index);
            int j = 0;
            while (j < length) {
                iter.nextDouble();
                iter.set(a[offset + j++]);
            }
        }
    }
    
    @Override
    public void clear() {
        this.removeElements(0, this.size());
    }
    
    @Override
    public int hashCode() {
        final DoubleIterator i = this.iterator();
        int h = 1;
        int s = this.size();
        while (s-- != 0) {
            final double k = i.nextDouble();
            h = 31 * h + HashCommon.double2int(k);
        }
        return h;
    }
    
    @Override
    public boolean equals(final Object o) {
        if (o == this) {
            return true;
        }
        if (!(o instanceof List)) {
            return false;
        }
        final List<?> l = (List<?>)o;
        int s = this.size();
        if (s != l.size()) {
            return false;
        }
        if (l instanceof DoubleList) {
            final DoubleListIterator i1 = this.listIterator();
            final DoubleListIterator i2 = ((DoubleList)l).listIterator();
            while (s-- != 0) {
                if (i1.nextDouble() != i2.nextDouble()) {
                    return false;
                }
            }
            return true;
        }
        final ListIterator<?> i3 = this.listIterator();
        final ListIterator<?> i4 = l.listIterator();
        while (s-- != 0) {
            if (!Objects.equals(i3.next(), i4.next())) {
                return false;
            }
        }
        return true;
    }
    
    @Override
    public int compareTo(final List<? extends Double> l) {
        if (l == this) {
            return 0;
        }
        if (l instanceof DoubleList) {
            final DoubleListIterator i1 = this.listIterator();
            final DoubleListIterator i2 = ((DoubleList)l).listIterator();
            while (i1.hasNext() && i2.hasNext()) {
                final double e1 = i1.nextDouble();
                final double e2 = i2.nextDouble();
                final int r;
                if ((r = Double.compare(e1, e2)) != 0) {
                    return r;
                }
            }
            return i2.hasNext() ? -1 : (i1.hasNext() ? 1 : 0);
        }
        final ListIterator<? extends Double> i3 = this.listIterator();
        final ListIterator<? extends Double> i4 = l.listIterator();
        while (i3.hasNext() && i4.hasNext()) {
            final int r;
            if ((r = ((Comparable)i3.next()).compareTo(i4.next())) != 0) {
                return r;
            }
        }
        return i4.hasNext() ? -1 : (i3.hasNext() ? 1 : 0);
    }
    
    @Override
    public void push(final double o) {
        this.add(o);
    }
    
    @Override
    public double popDouble() {
        if (this.isEmpty()) {
            throw new NoSuchElementException();
        }
        return this.removeDouble(this.size() - 1);
    }
    
    @Override
    public double topDouble() {
        if (this.isEmpty()) {
            throw new NoSuchElementException();
        }
        return this.getDouble(this.size() - 1);
    }
    
    @Override
    public double peekDouble(final int i) {
        return this.getDouble(this.size() - 1 - i);
    }
    
    @Override
    public boolean rem(final double k) {
        final int index = this.indexOf(k);
        if (index == -1) {
            return false;
        }
        this.removeDouble(index);
        return true;
    }
    
    @Override
    public double[] toDoubleArray() {
        final int size = this.size();
        if (size == 0) {
            return DoubleArrays.EMPTY_ARRAY;
        }
        final double[] ret = new double[size];
        this.getElements(0, ret, 0, size);
        return ret;
    }
    
    @Override
    public double[] toArray(double[] a) {
        final int size = this.size();
        if (a.length < size) {
            a = Arrays.copyOf(a, size);
        }
        this.getElements(0, a, 0, size);
        return a;
    }
    
    @Override
    public boolean addAll(int index, final DoubleCollection c) {
        this.ensureIndex(index);
        final DoubleIterator i = c.iterator();
        final boolean retVal = i.hasNext();
        while (i.hasNext()) {
            this.add(index++, i.nextDouble());
        }
        return retVal;
    }
    
    @Override
    public boolean addAll(final DoubleCollection c) {
        return this.addAll(this.size(), c);
    }
    
    @Override
    public final void replaceAll(final DoubleUnaryOperator operator) {
        this.replaceAll((java.util.function.DoubleUnaryOperator)operator);
    }
    
    @Override
    public String toString() {
        final StringBuilder s = new StringBuilder();
        final DoubleIterator i = this.iterator();
        int n = this.size();
        boolean first = true;
        s.append("[");
        while (n-- != 0) {
            if (first) {
                first = false;
            }
            else {
                s.append(", ");
            }
            final double k = i.nextDouble();
            s.append(String.valueOf(k));
        }
        s.append("]");
        return s.toString();
    }
    
    static final class IndexBasedSpliterator extends DoubleSpliterators.LateBindingSizeIndexBasedSpliterator
    {
        final DoubleList l;
        
        IndexBasedSpliterator(final DoubleList l, final int pos) {
            super(pos);
            this.l = l;
        }
        
        IndexBasedSpliterator(final DoubleList l, final int pos, final int maxPos) {
            super(pos, maxPos);
            this.l = l;
        }
        
        @Override
        protected final int getMaxPosFromBackingStore() {
            return this.l.size();
        }
        
        @Override
        protected final double get(final int i) {
            return this.l.getDouble(i);
        }
        
        @Override
        protected final IndexBasedSpliterator makeForSplit(final int pos, final int maxPos) {
            return new IndexBasedSpliterator(this.l, pos, maxPos);
        }
    }
    
    public static class DoubleSubList extends AbstractDoubleList implements Serializable
    {
        private static final long serialVersionUID = -7046029254386353129L;
        protected final DoubleList l;
        protected final int from;
        protected int to;
        
        public DoubleSubList(final DoubleList l, final int from, final int to) {
            this.l = l;
            this.from = from;
            this.to = to;
        }
        
        private boolean assertRange() {
            assert this.from <= this.l.size();
            assert this.to <= this.l.size();
            assert this.to >= this.from;
            return true;
        }
        
        @Override
        public boolean add(final double k) {
            this.l.add(this.to, k);
            ++this.to;
            assert this.assertRange();
            return true;
        }
        
        @Override
        public void add(final int index, final double k) {
            this.ensureIndex(index);
            this.l.add(this.from + index, k);
            ++this.to;
            assert this.assertRange();
        }
        
        @Override
        public boolean addAll(final int index, final Collection<? extends Double> c) {
            this.ensureIndex(index);
            this.to += c.size();
            return this.l.addAll(this.from + index, c);
        }
        
        @Override
        public double getDouble(final int index) {
            this.ensureRestrictedIndex(index);
            return this.l.getDouble(this.from + index);
        }
        
        @Override
        public double removeDouble(final int index) {
            this.ensureRestrictedIndex(index);
            --this.to;
            return this.l.removeDouble(this.from + index);
        }
        
        @Override
        public double set(final int index, final double k) {
            this.ensureRestrictedIndex(index);
            return this.l.set(this.from + index, k);
        }
        
        @Override
        public int size() {
            return this.to - this.from;
        }
        
        @Override
        public void getElements(final int from, final double[] a, final int offset, final int length) {
            this.ensureIndex(from);
            if (from + length > this.size()) {
                throw new IndexOutOfBoundsException("End index (" + from + length + ") is greater than list size (" + this.size() + ")");
            }
            this.l.getElements(this.from + from, a, offset, length);
        }
        
        @Override
        public void removeElements(final int from, final int to) {
            this.ensureIndex(from);
            this.ensureIndex(to);
            this.l.removeElements(this.from + from, this.from + to);
            this.to -= to - from;
            assert this.assertRange();
        }
        
        @Override
        public void addElements(final int index, final double[] a, final int offset, final int length) {
            this.ensureIndex(index);
            this.l.addElements(this.from + index, a, offset, length);
            this.to += length;
            assert this.assertRange();
        }
        
        @Override
        public void setElements(final int index, final double[] a, final int offset, final int length) {
            this.ensureIndex(index);
            this.l.setElements(this.from + index, a, offset, length);
            assert this.assertRange();
        }
        
        @Override
        public DoubleListIterator listIterator(final int index) {
            this.ensureIndex(index);
            return (this.l instanceof RandomAccess) ? new RandomAccessIter(index) : new ParentWrappingIter(this.l.listIterator(index + this.from));
        }
        
        @Override
        public DoubleSpliterator spliterator() {
            return (this.l instanceof RandomAccess) ? new IndexBasedSpliterator(this.l, this.from, this.to) : super.spliterator();
        }
        
        @Override
        public DoubleList subList(final int from, final int to) {
            this.ensureIndex(from);
            this.ensureIndex(to);
            if (from > to) {
                throw new IllegalArgumentException("Start index (" + from + ") is greater than end index (" + to + ")");
            }
            return new DoubleSubList(this, from, to);
        }
        
        @Override
        public boolean rem(final double k) {
            final int index = this.indexOf(k);
            if (index == -1) {
                return false;
            }
            --this.to;
            this.l.removeDouble(this.from + index);
            assert this.assertRange();
            return true;
        }
        
        @Override
        public boolean addAll(final int index, final DoubleCollection c) {
            this.ensureIndex(index);
            return super.addAll(index, c);
        }
        
        @Override
        public boolean addAll(final int index, final DoubleList l) {
            this.ensureIndex(index);
            return super.addAll(index, l);
        }
        
        private final class RandomAccessIter extends DoubleIterators.AbstractIndexBasedListIterator
        {
            RandomAccessIter(final int pos) {
                super(0, pos);
            }
            
            @Override
            protected final double get(final int i) {
                return DoubleSubList.this.l.getDouble(DoubleSubList.this.from + i);
            }
            
            @Override
            protected final void add(final int i, final double k) {
                DoubleSubList.this.add(i, k);
            }
            
            @Override
            protected final void set(final int i, final double k) {
                DoubleSubList.this.set(i, k);
            }
            
            @Override
            protected final void remove(final int i) {
                DoubleSubList.this.removeDouble(i);
            }
            
            @Override
            protected final int getMaxPos() {
                return DoubleSubList.this.to - DoubleSubList.this.from;
            }
            
            @Override
            public void add(final double k) {
                super.add(k);
                assert DoubleSubList.this.assertRange();
            }
            
            @Override
            public void remove() {
                super.remove();
                assert DoubleSubList.this.assertRange();
            }
        }
        
        private class ParentWrappingIter implements DoubleListIterator
        {
            private DoubleListIterator parent;
            
            ParentWrappingIter(final DoubleListIterator parent) {
                this.parent = parent;
            }
            
            @Override
            public int nextIndex() {
                return this.parent.nextIndex() - DoubleSubList.this.from;
            }
            
            @Override
            public int previousIndex() {
                return this.parent.previousIndex() - DoubleSubList.this.from;
            }
            
            @Override
            public boolean hasNext() {
                return this.parent.nextIndex() < DoubleSubList.this.to;
            }
            
            @Override
            public boolean hasPrevious() {
                return this.parent.previousIndex() >= DoubleSubList.this.from;
            }
            
            @Override
            public double nextDouble() {
                if (!this.hasNext()) {
                    throw new NoSuchElementException();
                }
                return this.parent.nextDouble();
            }
            
            @Override
            public double previousDouble() {
                if (!this.hasPrevious()) {
                    throw new NoSuchElementException();
                }
                return this.parent.previousDouble();
            }
            
            @Override
            public void add(final double k) {
                this.parent.add(k);
            }
            
            @Override
            public void set(final double k) {
                this.parent.set(k);
            }
            
            @Override
            public void remove() {
                this.parent.remove();
            }
            
            @Override
            public int back(final int n) {
                if (n < 0) {
                    throw new IllegalArgumentException("Argument must be nonnegative: " + n);
                }
                final int currentPos = this.parent.previousIndex();
                int parentNewPos = currentPos - n;
                if (parentNewPos < DoubleSubList.this.from - 1) {
                    parentNewPos = DoubleSubList.this.from - 1;
                }
                final int toSkip = parentNewPos - currentPos;
                return this.parent.back(toSkip);
            }
            
            @Override
            public int skip(final int n) {
                if (n < 0) {
                    throw new IllegalArgumentException("Argument must be nonnegative: " + n);
                }
                final int currentPos = this.parent.nextIndex();
                int parentNewPos = currentPos + n;
                if (parentNewPos > DoubleSubList.this.to) {
                    parentNewPos = DoubleSubList.this.to;
                }
                final int toSkip = parentNewPos - currentPos;
                return this.parent.skip(toSkip);
            }
        }
    }
    
    public static class DoubleRandomAccessSubList extends DoubleSubList implements RandomAccess
    {
        private static final long serialVersionUID = -107070782945191929L;
        
        public DoubleRandomAccessSubList(final DoubleList l, final int from, final int to) {
            super(l, from, to);
        }
        
        @Override
        public DoubleList subList(final int from, final int to) {
            this.ensureIndex(from);
            this.ensureIndex(to);
            if (from > to) {
                throw new IllegalArgumentException("Start index (" + from + ") is greater than end index (" + to + ")");
            }
            return new DoubleRandomAccessSubList(this, from, to);
        }
    }
}
