/*=============================================================================#
 # Copyright (c) 2009, 2022 Stephan Wahlbrink and others.
 # 
 # This program and the accompanying materials are made available under the
 # terms of the Eclipse Public License 2.0 which is available at
 # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
 # which is available at https://www.apache.org/licenses/LICENSE-2.0.
 # 
 # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
 # 
 # Contributors:
 #     Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
 #=============================================================================*/

package org.eclipse.statet.internal.jcommons.collections;

import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.RandomAccess;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.Function;

import org.eclipse.statet.jcommons.collections.ImCollection.MappingResult;
import org.eclipse.statet.jcommons.collections.ImIdentityList;
import org.eclipse.statet.jcommons.collections.ImList;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;


/**
 * Constant list implementation based on an array.
 * <p>
 * Comparable to <code>Collections.unmodifiableList(Array.asList(...))</code>.</p>
 * 
 * @since de.walware.ecommons.coremisc 1.2
 */
@NonNullByDefault
public final class ImArrayList<E> extends AbstractImList<E> implements ImList<E>,
		RandomAccess, MappingResult<E> {
	
	
	private class Iter extends AbstractImListIter<E> {
		
		
		private int cursor;
		
		
		Iter(final int index) {
			this.cursor= index;
		}
		
		
		@Override
		public boolean hasNext() {
			return (this.cursor < ImArrayList.this.array.length);
		}
		
		@Override
		public int nextIndex() {
			return this.cursor;
		}
		
		@Override
		public E next() {
			if (this.cursor >= ImArrayList.this.array.length) {
				throw new NoSuchElementException();
			}
			return ImArrayList.this.array[this.cursor++];
		}
		
		@Override
		public boolean hasPrevious() {
			return (this.cursor > 0);
		}
		
		@Override
		public int previousIndex() {
			return this.cursor - 1;
		}
		
		@Override
		public E previous() {
			if (this.cursor <= 0 || ImArrayList.this.array.length <= 0) {
				throw new NoSuchElementException();
			}
			return ImArrayList.this.array[--this.cursor];
		}
		
	}
	
	
	private final E[] array;
	
	
	/**
	 * Create a new constant list backed by the given array (directly used!).
	 * 
	 * If the list is published through an API and should be constant, the
	 * the elements of the given array must not any longer be changed.
	 * 
	 * @param a the array by which the list will be backed.
	 */
	public ImArrayList(final E[] a) {
		this.array= a;
	}
	
	
	@Override
	public int size() {
		return this.array.length;
	}
	
	@Override
	public boolean isEmpty() {
		return false;
	}
	
	@Override
	public boolean contains(final @Nullable Object o) {
		return (indexOf(o) >= 0);
	}
	
	@Override
	public boolean containsAll(final Collection<?> c) {
		final Iterator<?> e= c.iterator();
		while (e.hasNext()) {
			if (indexOf(e.next()) < 0) {
				return false;
			}
		}
		return true;
	}
	
	@Override
	public E get(final int index) {
		return this.array[index];
	}
	
	@Override
	public int indexOf(final @Nullable Object o) {
		if (o == null) {
			for (int i= 0; i < this.array.length; i++) {
				if (null == this.array[i]) {
					return i;
				}
			}
			return -1;
		}
		else {
			for (int i= 0; i < this.array.length; i++) {
				if (o.equals(this.array[i])) {
					return i;
				}
			}
			return -1;
		}
	}
	
	@Override
	public int lastIndexOf(final @Nullable Object o) {
		if (o == null) {
			for (int i= this.array.length - 1; i >= 0; i--) {
				if (null == this.array[i]) {
					return i;
				}
			}
			return -1;
		}
		else {
			for (int i= this.array.length - 1; i >= 0; i--) {
				if (o.equals(this.array[i])) {
					return i;
				}
			}
			return -1;
		}
	}
	
	
	@Override
	public Iterator<E> iterator() {
		return new Iter(0);
	}
	
	@Override
	public ListIterator<E> listIterator() {
		return new Iter(0);
	}
	
	@Override
	public ListIterator<E> listIterator(final int index) {
		if (index < 0 || index > this.array.length) {
			throw new IndexOutOfBoundsException("index= " + index); //$NON-NLS-1$
		}
		return new Iter(index);
	}
	
	@Override
	public Spliterator<E> spliterator() {
		return Spliterators.spliterator(this.array, 0, this.array.length,
				Spliterator.IMMUTABLE | Spliterator.ORDERED );
	}
	
	
	@Override
	@SuppressWarnings("unchecked")
	public ImList<E> subList(final int fromIndex, final int toIndex) {
		if (fromIndex < 0 || toIndex > this.array.length) {
			throw new IndexOutOfBoundsException("fromIndex= " + fromIndex + ", toIndex= " + toIndex + ", size= " + this.array.length); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
		}
		if (fromIndex > toIndex) {
			throw new IllegalArgumentException("fromIndex > toIndex: fromIndex= " + fromIndex + ", toIndex= " + toIndex); //$NON-NLS-1$ //$NON-NLS-2$
		}
		final int l= toIndex - fromIndex;
		if (l == this.array.length) {
			return this;
		}
		else if (l == 0){
			return ImEmptyList.INSTANCE;
		}
		else if (l == 1) {
			return new ImSingletonList<>(this.array[fromIndex]);
		}
		else if (fromIndex == 0) {
			return new ImArraySub0List<>(this.array, toIndex);
		}
		else {
			return new ImArraySubList<>(this.array, fromIndex, toIndex);
		}
	}
	
	@Override
	public Object[] toArray() {
		final Object[] dest= new Object[this.array.length];
		System.arraycopy(this.array, 0, dest, 0, this.array.length);
		return dest;
	}
	
	@Override
	@SuppressWarnings({ "unchecked", "null" })
	public <T> T[] toArray(final T[] dest) {
		final int n= this.array.length;
		if (dest.length < n) {
			return Arrays.copyOf(this.array, n, (Class<? extends T[]>)dest.getClass());
		}
		System.arraycopy(this.array, 0, dest, 0, n);
		if (dest.length > n) {
			dest[n]= null;
		}
		return dest;
	}
	
	@Override
	public void copyTo(final Object[] dest, final int destPos) {
		System.arraycopy(this.array, 0, dest, destPos, this.array.length);
	}
	
	@Override
	public void copyTo(final int srcPos, final Object[] dest, final int destPos, final int length) {
		System.arraycopy(this.array, srcPos, dest, destPos, length);
	}
	
	@Override
	public ImList<E> toList() {
		return this;
	}
	
	@Override
	public ImIdentityList<E> toIdentityList() {
		return new ImArrayIdentityList<>(this.array);
	}
	
	@Override
	@SuppressWarnings("unchecked")
	public <R> MappingResult<R> map(final Function<E, R> mapper) {
		final R[] result= (R[])new Object[this.array.length];
		for (int i= 0; i < this.array.length; i++) {
			result[i]= mapper.apply(this.array[i]);
		}
		return new ImArrayList<>(result);
	}
	
	
	@Override
	public int hashCode() {
		int hashCode= 1;
		for (int i= 0; i < this.array.length; i++) {
			hashCode= 31 * hashCode + ((this.array[i] != null) ? this.array[i].hashCode() : 0);
		}
		return hashCode;
	}
	
	@Override
	public boolean equals(final @Nullable Object obj) {
		if (obj == this) {
			return true;
		}
		if (obj instanceof List) {
			final var other= (List<?>)obj;
			if (this.array.length != other.size()) {
				return false;
			}
			final Iterator<?> otherIter= other.iterator();
			for (int i= 0; i < this.array.length; i++) {
				if (!Objects.equals(this.array[i], otherIter.next())) {
					return false;
				}
			}
			return true;
		}
		return false;
	}
	
	@Override
	public String toString() {
		return Arrays.toString(this.array);
	}
	
}
