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

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

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

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

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

    public static final IntInterval EMPTY_INTERVAL = new AbstractIntInterval() {
        public boolean isEmpty() { return true; }
        public int getFirst() { return 0; }
        public int getLast() { return -1; }
        public int min() { return 0; }
        public int max() { return -1; }
    };

    public static final IntList EMPTY_LIST = new IntArrAsList(new int[0]);

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

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

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

    public static IntList asList(int[] arr) {
        return new IntArrAsList(arr);
    }

    private static class IntArrAsList extends AbstractIntCollection
                                       implements IntList {
        final int[] arr;
        IntArrAsList(int[] arr) {
            this.arr = arr;
        }

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

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

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

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

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

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

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

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

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

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

        public boolean equals(Object o) {
            if (o == this) return true;
            if (!(o instanceof IntList)) return false;
            IntList that = (IntList)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 int getAt(int index) { return arr[index]; }

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

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

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

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

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

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

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

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

        public int size64() {  
            return arr.length;  
        }                       
                                
        private class ArrAsListItr implements IntListIterator {
            int cursor;
            ArrAsListItr(int cursor) {
                this.cursor = cursor;
            }
            public boolean hasNext() { return cursor < arr.length; }

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

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

            public int 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(int e) { arr[cursor] = e; }

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

}
