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

import java.io.Serializable;
import java.util.AbstractList;
import java.util.List;
import net.ranides.assira.collection.arrays.NativeArrayAllocator;
import net.ranides.assira.collection.arrays.NativeArray;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
public final class NativeArrayList {
    
    private static final int[] EMPTY = new int[0];
	
	private NativeArrayList() { }

	public static IntList wrap(int[] array) {
        if(null == array) {
            array = EMPTY;
        }
        return new IntegerList(array, 0, array.length);
	}

	public static IntList wrap(int[] array, int offset, int length) {
		return new IntegerList(array, offset, offset+length);
		
    }
	
	public static List<Object> wrap(Object array) {
        NativeArray na = NativeArray.wrap(array);
        return new NativeList(na, 0, na.size());
	}
	
	public static List<Object> wrap(Object array, int offset, int length) {
        return new NativeList(NativeArray.wrap(array), offset, offset+length);
    }
	
    @SuppressWarnings("unchecked")
	public static <Auto> List<Auto> $wrap(Object array) {
		return (List)wrap(array);
	}
	
    @SuppressWarnings("unchecked")
	public static <Auto> List<Auto> $wrap(Object array, int offset, int length) {
		return (List)wrap(array, offset, length);
	}


    public static final class NativeList extends AbstractList<Object> implements Serializable {
        
        private static final long serialVersionUID = 1L;
		
		private final int begin;
		private final int end;
		private final NativeArray array;

        public NativeList(NativeArray array, int begin, int end) {
			this.begin = begin;
			this.end = end;
            this.array = array;
			NativeArrayAllocator.ensureFromTo(array, begin, end);
        }

        @Override
        public Object set(int index, Object element) {
            Object prev = array.get(begin+index);
            array.set(begin+index, element);
            return prev;
        }

        @Override
        public Object get(int index) {
            return array.get(begin+index);
        }

		@Override
		public int size() {
			return end - begin;
		}

		@Override
		public boolean equals(Object object) {
			if(object instanceof NativeList) {
				NativeList list = (NativeList)object;
                int asize = end-begin;
                int bsize = list.end - list.begin;
                if(asize != bsize) {
                    return false;
                }
                return array.equals(list.array, begin, list.begin, asize);
			}
			return super.equals(object);
		}
		
		@Override
		public int hashCode() {
            return array.hashCode(begin, end);
		}
		
    }

    public static final class IntegerList extends AIntList {
        
        private static final long serialVersionUID = 1L;
		
		private final int begin;
		private final int end;
		private final int[] array;

        @SuppressWarnings("PMD.ArrayIsStoredDirectly")
        public IntegerList(int[] array, int begin, int end) {
			this.begin = begin;
			this.end = end;
            this.array = array;
			NativeArrayAllocator.ensureFromTo(NativeArray.wrap(array), begin, end);
        }

        @Override
        public int set(int index, int element) {
            int prev = array[begin+index];
            array[begin+index] = element;
            return prev;
        }

        @Override
        public int getInt(int index) {
            return array[begin+index];
        }

		@Override
		public int size() {
			return end - begin;
		}

		@Override
		public boolean equals(Object object) {
			if(object instanceof IntegerList) {
				IntegerList list = (IntegerList)object;
                int asize = end-begin;
                int bsize = list.end - list.begin;
                if(asize != bsize) {
                    return false;
                }
                return NativeArray.wrap(array).equals(NativeArray.wrap(list.array), begin, list.begin, asize);
			}
			return super.equals(object);
		}
		
		@Override
		public int hashCode() {
            return NativeArray.wrap(array).hashCode(begin, end);
		}

        @Override
        public void add(int index, int k) {
            throw new UnsupportedOperationException();
        }

        @Override
        public int removeInt(int index) {
            throw new UnsupportedOperationException();
        }
        
        
        
    }
	
}
