/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.collection;

import java.util.Collection;
import java.util.Iterator;
import java.util.stream.IntStream;

import net.ranides.assira.collection.arrays.ArrayAllocator;
import net.ranides.assira.collection.arrays.ArrayUtils;
import net.ranides.assira.collection.iterators.IntIterator;
import net.ranides.assira.collection.iterators.IntIteratorUtils;

/**
 * An abstract base class for collections of primitive int values. 
 * Designed to avoid autoboxing.
 */
public abstract class AIntCollection extends ACollection<Integer> implements IntCollection {

    private static final int[] EMPTY = new int[0];
    
    protected AIntCollection() {
        // protected constructor
    }

    
    @Override
    public boolean contains(int k) {
        IntIterator iterator = iterator();
        while (iterator.hasNext()) {
            if (k == iterator.nextInt()) {
                return true;
            }
        }
        return false;
    }
    
    @Override
    public boolean contains(Object value) {
        if(!(value instanceof Integer)) {
            return false;
        }
        return contains( ((Integer)value).intValue() );
    }
    
    @Override
    public boolean containsAll(IntCollection values) {
        IntIterator iterator = values.iterator();
        while (iterator.hasNext()) {
            if (!contains(iterator.nextInt())) {
                return false;
            }
        }
        return true;
    }
    
    @Override
    @SuppressWarnings("element-type-mismatch")
    public boolean containsAll(Collection<?> values) {
        int n = values.size();
        Iterator<?> iterator = values.iterator();
        while (n-- != 0) {
            if (!contains(iterator.next())) {
                return false;
            }
        }
        return true;
    }

    @Override
    public boolean add(int k) {
        throw new UnsupportedOperationException();
    }

    @Override
    public final boolean add(Integer value) {
        return add(value.intValue());
    }
    
    @Override
    public boolean addAll(IntCollection values) {
        boolean modified = false;
        IntIterator iterator = values.iterator();
        while (iterator.hasNext()) {
            if (add(iterator.nextInt())) {
                modified = true;
            }
        }
        return modified;
    }
    
    @Override
    public boolean addAll(Collection<? extends Integer> values) {
        boolean modified = false;
        Iterator<? extends Integer> iterator = values.iterator();
        while (iterator.hasNext()) {
            if (add(iterator.next())) {
                modified = true;
            }
        }
        return modified;
    }
    
    @Override
    public boolean rem(int k) {
        IntIterator iterator = iterator();
        while (iterator.hasNext()) {
            if (k == iterator.nextInt()) {
                iterator.remove();
                return true;
            }
        }
        return false;
    }
    
    @Override
    public boolean rem(Object value) {
        if(!(value instanceof Integer)) {
            return false;
        }
        return rem( ((Integer)value).intValue() );
    }
    
    @Override
    public boolean remove(Object value) {
        if(!(value instanceof Integer)) {
            return false;
        }
        return rem( ((Integer) value).intValue() );
    }

    @Override
    public boolean removeAll(IntCollection values) {
        boolean modified = false;
        IntIterator iterator = values.iterator();
        while (iterator.hasNext()) {
            if (rem(iterator.nextInt())) {
                modified = true;
            }
        }
        return modified;
    }

    @Override
    @SuppressWarnings("element-type-mismatch")
    public boolean removeAll(Collection<?> values) {
        boolean modified = false;
        Iterator<?> iterator = values.iterator();
        while (iterator.hasNext()) {
            if (remove(iterator.next())) {
                modified = true;
            }
        }
        return modified;
    }
    
    @Override
    public boolean retainAll(IntCollection values) {
        boolean modified = false;
        IntIterator iterator = iterator();
        while (iterator.hasNext()) {
            if (!values.contains(iterator.nextInt())) {
                iterator.remove();
                modified = true;
            }
        }
        return modified;
    }

    @Override
    public boolean retainAll(Collection<?> values) {
        boolean modified = false;
        Iterator<?> iterator = iterator();
        while (iterator.hasNext()) {
            if (!values.contains(iterator.next())) {
                iterator.remove();
                modified = true;
            }
        }
        return modified;
    }

    @Override
    public IntStream intstream() {
        return IntIteratorUtils.stream(iterator());
    }
    
    @Override
    public int[] toIntArray() {
        return toIntArray(EMPTY);
    }
    
    @Override
    public int[] toIntArray(int target[]) {
        int[] result = target;
        if (result == null || result.length < size()) {
            result = new int[size()];
        }
        ArrayUtils.collect(iterator(), result);
        return result;
    }
    
    @Override
    public int[] toArray(int a[]) {
        return toIntArray(a);
    }

    @Override
    public Object[] toArray() {
        Object[] target = new Object[size()];
        ArrayUtils.collect(iterator(), target);
        return target;
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> T[] toArray(T[] target) {
        T[] result = target;
        int n = size();
        if (result.length < n) {
            result = ArrayAllocator.forPrototype(result, n);
        }
        ArrayUtils.collect(iterator(), result);
        return result;
    }

    @Override
    public String toString() {
        IntIterator itr = iterator();
        if ( !itr.hasNext() ) {
            return "[]";
        }
        StringBuilder builder = new StringBuilder();
        builder.append('[');
        for (;;) {
            builder.append(itr.nextInt());
            if ( !itr.hasNext() ) {
                return builder.append(']').toString();
            }
            builder.append(", ");
        }
    }
    

}
