/*
 * Written by Dawid Kurzyniec and released to the public domain, as explained
 * at http://creativecommons.org/licenses/publicdomain
 */

package edu.emory.mathcs.util.collections.longs;

import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 * @author Dawid Kurzyniec
 * @version 1.0
 */
public class LongCollections {
    private LongCollections() {}

    public static LongInterval interval(long first, long last) {
        return (first > last) ? EMPTY_INTERVAL : new SimpleInterval(first, last);
    }

    public static final LongInterval EMPTY_INTERVAL = new AbstractLongInterval() {
        public boolean isEmpty() { return true; }
        public long getFirst() { return 0; }
        public long getLast() { return -1; }
        public long min() { return 0; }
        public long max() { return -1; }
    };

    public static final LongList EMPTY_LIST = new LongArrAsList(new long[0]);

    public static class SimpleInterval extends AbstractLongInterval {
        final long first, last;
        public SimpleInterval(long first, long last) {
            if (first > last) throw new IllegalArgumentException();
            this.first = first;
            this.last = last;
        }
        public long getFirst() { return first; }
        public long getLast() { return last; }

        public long first() { return first; }
        public long last() { return last; }

        public long min() { return first; }
        public long max() { return last; }
    }

    public static LongList asList(long[] arr) {
        return new LongArrAsList(arr);
    }

    private static class LongArrAsList extends AbstractLongCollection
                                       implements LongList {
        final long[] arr;
        LongArrAsList(long[] arr) {
            this.arr = arr;
        }

        public int size() { return arr.length; }

        public boolean isEmpty() { return arr.length == 0; }

        public boolean contains(long e) {
            for (int i=0; i<arr.length; i++) {
                if (arr[i] == e) return true;
            }
            return false;
        }

        public LongIterator iterator() {
            return listIterator();
        }

        public long[] toArray() {
            long[] a = new long[arr.length];
            System.arraycopy(arr, 0, a, 0, arr.length);
            return a;
        }

        public long[] toArray(long[] a) {
            if (a.length < arr.length) {
                a = new long[arr.length];
            }
            System.arraycopy(arr, 0, a, 0, arr.length);
            return a;
        }

        public boolean add(long e) {
            throw new UnsupportedOperationException();
        }

        public boolean addAll(int idx, LongCollection c) {
            throw new UnsupportedOperationException();
        }

        public boolean remove(long e) {
            throw new UnsupportedOperationException();
        }

        public void clear() {
            throw new UnsupportedOperationException();
        }

        public boolean equals(Object o) {
            if (o == this) return true;
            if (!(o instanceof LongList)) return false;
            LongList that = (LongList)o;
            if (this.size() != that.size()) return false;
            for (int i=0; i<arr.length; i++) {
                if (arr[i] != that.getAt(i)) return false;
            }
            return true;
        }

        public int hashCode() {
            int hashCode = 1;
            for (int i=0; i<arr.length; i++) {
                hashCode = 31*hashCode + (int)arr[i];
            }
            return hashCode;
        }

        public long getAt(int index) { return arr[index]; }

        public long setAt(int index, long e) {
            long old = arr[index];
            arr[index] = e;
            return old;
        }

        public void addAt(int index, long e) {
            throw new UnsupportedOperationException();
        }

        public long removeAt(int index) {
            throw new UnsupportedOperationException();
        }

        public int indexOf(long e) {
            for (int i=0; i<arr.length; i++) {
                if (arr[i] == e) return i;
            }
            return -1;
        }

        public int lastIndexOf(long e) {
            for (int i=arr.length-1; i>=0; --i) {
                if (arr[i] == e) return i;
            }
            return -1;
        }

        public LongListIterator listIterator() {
            return new ArrAsListItr(0);
        }

        public LongListIterator listIterator(int index) {
            return new ArrAsListItr(index);
        }

        public LongList subList(int fromIndex, int toIndex) {
            throw new UnsupportedOperationException();
        }

        public long size64() {  // PREPROC: Long,Int only
            return arr.length;  // PREPROC: Long,Int only
        }                       // PREPROC: Long,Int only
                                // PREPROC: Long,Int only
        private class ArrAsListItr implements LongListIterator {
            int cursor;
            ArrAsListItr(int cursor) {
                this.cursor = cursor;
            }
            public boolean hasNext() { return cursor < arr.length; }

            public long next() {
                if (cursor == arr.length) {
                    throw new NoSuchElementException();
                }
                return arr[cursor++];
            }

            public boolean hasPrevious() { return cursor > 0; }

            public long previous() {
                if (cursor == 0) {
                    throw new NoSuchElementException();
                }
                return arr[--cursor];
            }

            public int nextIndex() { return cursor; }

            public int previousIndex() { return cursor-1; }

            public void remove() { throw new UnsupportedOperationException(); }

            public void set(long e) { arr[cursor] = e; }

            public void add(long e) { throw new UnsupportedOperationException(); }
        }
    }

}
