/*
 * Java
 *
 * Copyright 2011-2020 MicroEJ Corp. All rights reserved.
 * This library is provided in source code for use, modification and test, subject to license terms.
 * Any modification of the source code will break MicroEJ Corp. warranties on the whole library.
 */
package ej.basictool;

import ej.bon.Util;

/**
 * Defines a set of functions to manipulate arrays.
 */
public final class ArrayTools {

	private ArrayTools() {
	}

	/**
	 * Checks the given range is included in the given byte array.
	 *
	 * @param bytes
	 *            the byte array.
	 * @param offset
	 *            the offset of the range.
	 * @param length
	 *            the length of the range.
	 * @throws IndexOutOfBoundsException
	 *             if the range is not included in the array.
	 */
	public static void checkBounds(byte[] bytes, int offset, int length) {
		if (!checkBoundsInternal(bytes.length, offset, length)) {
			throw new IndexOutOfBoundsException();
		}
	}

	/**
	 * Checks the given range is included in the array (defined by its length).
	 *
	 * @param arrayLength
	 *            the array length.
	 * @param offset
	 *            the offset of the range.
	 * @param length
	 *            the length of the range.
	 * @throws IndexOutOfBoundsException
	 *             if the range is not included in the array.
	 */
	public static void checkBounds(int arrayLength, int offset, int length) {
		if (!checkBoundsInternal(arrayLength, offset, length)) {
			throw new IndexOutOfBoundsException();
		}
	}

	/**
	 * Checks the given range is included in the array (defined by its length).
	 *
	 * @param arrayLength
	 *            the array length.
	 * @param offset
	 *            the offset of the range.
	 * @param length
	 *            the length of the range.
	 * @throws ArrayIndexOutOfBoundsException
	 *             if the range is not included in the array.
	 */
	public static void checkArrayBounds(int arrayLength, int offset, int length) {
		if (!checkBoundsInternal(arrayLength, offset, length)) {
			throw new ArrayIndexOutOfBoundsException();
		}
	}

	/**
	 * Checks the given range is included in the array (defined by its length).
	 *
	 * @param stringLength
	 *            the string length.
	 * @param offset
	 *            the offset of the range.
	 * @param length
	 *            the length of the range.
	 * @throws StringIndexOutOfBoundsException
	 *             if the range is not included in the array.
	 */
	public static void checkStringBounds(int stringLength, int offset, int length) {
		if (!checkBoundsInternal(stringLength, offset, length)) {
			throw new StringIndexOutOfBoundsException();
		}
	}

	private static boolean checkBoundsInternal(int arrayLength, int offset, int length) {
		int offsetPlusLength = offset + length;
		return offset >= 0 && length >= 0 && offsetPlusLength <= arrayLength && offsetPlusLength >= 0;
	}

	/**
	 * Grows an array by inserting a number of cells at an index. The new cells are initialized to <code>null</code>.
	 *
	 * @param array
	 *            the input array.
	 * @param index
	 *            the index to insert the cells at in the array.
	 * @param count
	 *            the number of cells to insert.
	 * @return the output array.
	 * @throws IllegalArgumentException
	 *             if the given count is negative.
	 * @throws IndexOutOfBoundsException
	 *             if the given index is not included in the resulting array.
	 */
	public static int[] grow(int[] array, int index, int count) {
		checkCount(count);
		int arrayLength = array.length;
		int[] result = new int[arrayLength + count];
		System.arraycopy(array, 0, result, 0, index);
		System.arraycopy(array, index, result, index + count, arrayLength - index);
		return result;
	}

	/**
	 * Grows an array by inserting a number of cells at an index. The new cells are initialized to <code>null</code>.
	 *
	 * @param array
	 *            the input array.
	 * @param index
	 *            the index to insert the cells at in the array.
	 * @param count
	 *            the number of cells to insert.
	 * @param <T>
	 *            the type of array elements.
	 * @return the output array.
	 * @throws IllegalArgumentException
	 *             if the given count is negative.
	 * @throws IndexOutOfBoundsException
	 *             if the given index is not included in the resulting array.
	 */
	public static <T> T[] grow(T[] array, int index, int count) {
		checkCount(count);
		int arrayLength = array.length;
		T[] result = createNewArray(array, arrayLength + count);
		System.arraycopy(array, 0, result, 0, index);
		System.arraycopy(array, index, result, index + count, arrayLength - index);
		return result;
	}

	/**
	 * Shrinks an array by removing a number of cells at an index.
	 *
	 * @param array
	 *            the input array.
	 * @param index
	 *            the index of the cells to remove in the array.
	 * @param count
	 *            the number of cells to remove.
	 * @return the output array.
	 * @throws IllegalArgumentException
	 *             if the given count is negative or greater than array length.
	 * @throws IndexOutOfBoundsException
	 *             if the given index is not included in the resulting array.
	 */
	public static int[] shrink(int[] array, int index, int count) {
		checkCount(count);
		int arrayLength = array.length;
		int[] result = new int[arrayLength - count];
		System.arraycopy(array, 0, result, 0, index);
		System.arraycopy(array, index + count, result, index, arrayLength - index - count);
		return result;
	}

	/**
	 * Shrinks an array by removing a number of cells at an index.
	 *
	 * @param array
	 *            the input array.
	 * @param index
	 *            the index of the cells to remove in the array.
	 * @param count
	 *            the number of cells to remove.
	 * @param <T>
	 *            the type of array elements.
	 * @return the output array.
	 * @throws IllegalArgumentException
	 *             if the given count is negative or greater than array length.
	 * @throws IndexOutOfBoundsException
	 *             if the given index is not included in the resulting array.
	 */
	public static <T> T[] shrink(T[] array, int index, int count) {
		checkCount(count);
		int arrayLength = array.length;
		T[] result = createNewArray(array, arrayLength - count);
		System.arraycopy(array, 0, result, 0, index);
		System.arraycopy(array, index + count, result, index, arrayLength - index - count);
		return result;
	}

	private static void checkCount(int count) {
		if (count < 0) {
			throw new IllegalArgumentException();
		}
	}

	/**
	 * Adds an element in an array. The array returned is always different from the given one, and its size fit the
	 * number of elements (in opposition with {@link #add(Object[], Object, int)}).
	 *
	 * @param array
	 *            the input array.
	 * @param element
	 *            the element to add.
	 * @param <T>
	 *            the type of array elements.
	 * @return the output array.
	 */
	public static <T> T[] add(T[] array, T element) {
		int arrayLength = array.length;
		T[] result = grow(array, arrayLength, 1);
		result[arrayLength] = element;
		return result;
	}

	/**
	 * Appends an array to another. The array returned is always different from the given one, and its size fit the
	 * number of elements (in opposition with {@link #add(Object[], Object, int)}).
	 *
	 * @param array
	 *            the input array.
	 * @param other
	 *            the array to append.
	 * @param <T>
	 *            the type of array elements.
	 * @return the output array.
	 */
	public static <T> T[] add(T[] array, T[] other) {
		int arrayLength = array.length;
		int otherLength = other.length;
		T[] result = grow(array, arrayLength, otherLength);
		System.arraycopy(other, 0, result, arrayLength, otherLength);
		return result;
	}

	/**
	 * Inserts an element at an index in an array. The array returned is always different from the given one, and its
	 * size fit the number of elements (in opposition with {@link #insert(Object[], int, Object, int)}).
	 *
	 * @param array
	 *            the input array.
	 * @param index
	 *            the index in the array.
	 * @param element
	 *            the element to add.
	 * @param <T>
	 *            the type of array elements.
	 * @return the output array.
	 * @throws IndexOutOfBoundsException
	 *             if the given index is not included in the resulting array.
	 */
	public static <T> T[] insert(T[] array, int index, T element) {
		T[] result = grow(array, index, 1);
		result[index] = element;
		return result;
	}

	/**
	 * Removes an element in an array.
	 * <p>
	 * The comparison between the elements is done using <code>==</code> operator.
	 * <p>
	 * If the array does not contain the given element, the returned array is the given one, otherwise, it is always a
	 * different one. If the array contains several times the given element, only the last added is removed.
	 * <p>
	 * The returned array size fit the number of elements (in opposition with {@link #remove(Object[], Object, int)}).
	 *
	 * @param array
	 *            the input array.
	 * @param element
	 *            the element to remove.
	 * @param <T>
	 *            the type of array elements.
	 * @return the output array.
	 */
	public static <T> T[] remove(T[] array, T element) {
		int index = getIndex(array, element);
		if (index != -1) {
			array = shrink(array, index, 1);
		}
		return array;
	}

	/**
	 * Removes an element in an array.
	 * <p>
	 * The comparison between the elements is done using {@link Object#equals(Object)}.
	 * <p>
	 * If the array does not contain the given element, the returned array is the given one, otherwise, it is always a
	 * different one. If the array contains several times the given element, only the last added is removed.
	 * <p>
	 * The returned array size fit the number of elements (in opposition with {@link #remove(Object[], Object, int)}).
	 *
	 * @param array
	 *            the input array.
	 * @param element
	 *            the element to remove.
	 * @param <T>
	 *            the type of array elements.
	 * @return the output array.
	 */
	public static <T> T[] removeEquals(T[] array, T element) {
		int index = getIndexEquals(array, element);
		if (index != -1) {
			array = shrink(array, index, 1);
		}
		return array;
	}

	/**
	 * Removes an element at an index in an array.
	 * <p>
	 * The returned array size fit the number of elements.
	 *
	 * @param array
	 *            the input array.
	 * @param index
	 *            the index of the element to remove.
	 * @param <T>
	 *            the type of array elements.
	 * @return the output array.
	 * @throws IndexOutOfBoundsException
	 *             if the given index is not included in the resulting array.
	 */
	public static <T> T[] remove(T[] array, int index) {
		return shrink(array, index, 1);
	}

	/**
	 * Gets whether an array contains an element or not.
	 * <p>
	 * The comparison between the elements is done using <code>==</code> operator.
	 *
	 * @param array
	 *            the array.
	 * @param element
	 *            the element to search.
	 * @param <T>
	 *            the type of array elements.
	 * @return <code>true</code> if the element exists in the array, <code>false</code> otherwise.
	 */
	public static <T> boolean contains(T[] array, T element) {
		return getIndex(array, element) != -1;
	}

	/**
	 * Gets whether an array contains an element or not.
	 * <p>
	 * The comparison between the elements is done using {@link Object#equals(Object)}.
	 *
	 * @param array
	 *            the array.
	 * @param element
	 *            the element to search.
	 * @param <T>
	 *            the type of array elements.
	 * @return <code>true</code> if the element exists in the array, <code>false</code> otherwise.
	 */
	public static <T> boolean containsEquals(T[] array, T element) {
		return getIndexEquals(array, element) != -1;
	}

	/**
	 * Gets the index of an element in an array. If the array contains several times the given element, the index of the
	 * last added is returned.
	 *
	 * @param array
	 *            the array.
	 * @param element
	 *            the element to search.
	 * @return the index of the element in the array or <code>-1</code> if not found.
	 */
	public static int getIndex(int[] array, int element) {
		int arrayLength = array.length;
		for (int i = arrayLength; --i >= 0;) {
			if (element == array[i]) {
				return i;
			}
		}
		return -1;
	}

	/**
	 * Gets the index of an element in an array. If the array contains several times the given element, the index of the
	 * last added is returned.
	 * <p>
	 * The comparison between the elements is done using <code>==</code> operator.
	 *
	 * @param array
	 *            the array.
	 * @param element
	 *            the element to search.
	 * @param <T>
	 *            the type of array elements.
	 * @return the index of the element in the array or <code>-1</code> if not found.
	 */
	public static <T> int getIndex(T[] array, T element) {
		int arrayLength = array.length;
		for (int i = arrayLength; --i >= 0;) {
			if (element == array[i]) {
				return i;
			}
		}
		return -1;
	}

	/**
	 * Gets the index of an element in an array. If the array contains several times the given element, the index of the
	 * last added is returned.
	 * <p>
	 * The comparison between the elements is done using {@link Object#equals(Object)}.
	 *
	 * @param array
	 *            the array.
	 * @param element
	 *            the element to search.
	 * @param <T>
	 *            the type of array elements.
	 * @return the index of the element in the array or <code>-1</code> if not found.
	 */
	public static <T> int getIndexEquals(T[] array, T element) {
		int arrayLength = array.length;
		for (int i = 0; i < arrayLength; i++) {
			if (element.equals(array[i])) {
				return i;
			}
		}
		return -1;
	}

	/**
	 * Copies an array.
	 *
	 * @param array
	 *            the input array.
	 * @param <T>
	 *            the type of array elements.
	 * @return the output array.
	 * @deprecated Use {@link Object#clone()} instead.
	 */
	@Deprecated
	public static <T> T[] copy(T[] array) {
		return array.clone();
	}

	/**
	 * Copies an array into an array of a different type.
	 *
	 * @param array
	 *            the input array.
	 * @param type
	 *            the output array type.
	 * @param <T>
	 *            the type of array elements.
	 * @return the output array.
	 * @throws ArrayStoreException
	 *             if the given type is not an array type.
	 * @throws ArrayStoreException
	 *             if the given type mismatch the array elements type.
	 * @deprecated Use <code>Arrays.copyOf(Object[], int, Class)</code> instead.
	 */
	@Deprecated
	public static <T> T[] copy(Object[] array, Class<T[]> type) {
		return copyInternal(array, array.length, type);
	}

	/**
	 * Adds an element in an array. The array returned is always different from the given one, and its size fit the
	 * number of elements (in opposition with {@link #add(int[], int, int)}).
	 *
	 * @param array
	 *            the input array.
	 * @param element
	 *            the element to add.
	 * @return the output array.
	 */
	public static int[] add(int[] array, int element) {
		int arrayLength = array.length;
		int[] result = grow(array, arrayLength, 1);
		result[arrayLength] = element;
		return result;
	}

	/**
	 * Removes an element in an array.
	 * <p>
	 * If the array does not contain the given element, the returned array is the given array, otherwise, it is always a
	 * different one. If the array contains several times the given element, only the last added is removed.
	 * <p>
	 * The returned array size fit the number of elements (in opposition with {@link #remove(int[], int, int)}).
	 *
	 * @param array
	 *            the input array.
	 * @param element
	 *            the element to remove.
	 * @return the output array.
	 */
	public static int[] remove(int[] array, int element) {
		int index = getIndex(array, element);
		if (index != -1) {
			array = shrink(array, index, 1);
		}
		return array;
	}

	/**
	 * Removes several elements in an array.
	 * <p>
	 * The returned array size fit the number of elements.
	 *
	 * @param array
	 *            the input array.
	 * @param offset
	 *            the start index of the range to remove.
	 * @param length
	 *            the number of elements to remove.
	 * @return the output array.
	 * @throws IllegalArgumentException
	 *             if the given count is negative or greater than array length.
	 * @throws IndexOutOfBoundsException
	 *             if the given index is not included in the resulting array.
	 * @deprecated Use {@link #shrink(int[], int, int)} instead.
	 */
	@Deprecated
	public static int[] removeRange(int[] array, int offset, int length) {
		return shrink(array, offset, length);
	}

	/**
	 * Gets whether an array contains an element or not.
	 *
	 * @param array
	 *            the array.
	 * @param element
	 *            the element to search.
	 * @return <code>true</code> if the element exists in the array, <code>false</code> otherwise.
	 */
	public static boolean contains(int[] array, int element) {
		return getIndex(array, element) != -1;
	}

	/**
	 * Copies an array.
	 *
	 * @param array
	 *            the input array.
	 * @return the output array.
	 * @deprecated Use {@link Object#clone()} instead.
	 */
	@Deprecated
	public static int[] copy(int[] array) {
		return array.clone();
	}

	/**
	 * Adds an element in an array.
	 * <p>
	 * The array returned could be different from the given one, it grows to <code>pointer*2</code> only if the given
	 * array is not large enough to add the given element (<code>pointer == array.length</code>).
	 *
	 * @param array
	 *            the input array.
	 * @param element
	 *            the element to add.
	 * @param pointer
	 *            the index of the element to add.
	 * @param <T>
	 *            the type of array elements.
	 * @return the output array.
	 * @throws ArrayIndexOutOfBoundsException
	 *             if the given pointer is greater than the array length.
	 */
	public static <T> T[] add(T[] array, T element, int pointer) {
		try {
			array[pointer] = element;
		} catch (ArrayIndexOutOfBoundsException e) {
			// grow array
			T[] result = createNewArray(array, (pointer << 1) + 1);
			System.arraycopy(array, 0, result, 0, array.length);
			array = result;
			array[pointer] = element;
		}
		return array;
	}

	/**
	 * Inserts an element at an index in an array.
	 * <p>
	 * The array returned could be different from the given one, it grows to <code>pointer*2</code> only if the given
	 * array is not large enough to add the given element (<code>pointer == array.length</code>).
	 *
	 * @param array
	 *            the input array.
	 * @param index
	 *            the index in the array.
	 * @param element
	 *            the element to add.
	 * @param pointer
	 *            the index of the element to add.
	 * @param <T>
	 *            the type of array elements.
	 * @return the output array.
	 * @throws ArrayIndexOutOfBoundsException
	 *             if the given pointer is greater than the array length.
	 * @throws IndexOutOfBoundsException
	 *             if the given index is not included in the resulting array.
	 */
	public static <T> T[] insert(T[] array, int index, T element, int pointer) {
		int arrayLength = array.length;
		T[] result;
		if (pointer == arrayLength) {
			// grow array
			result = createNewArray(array, (pointer << 1) + 1);
			System.arraycopy(array, 0, result, 0, index);
		} else {
			result = array;
		}
		System.arraycopy(array, index, result, index + 1, pointer - index);
		result[index] = element;
		return result;
	}

	/**
	 * Removes an element in an array.
	 * <p>
	 * The comparison between the elements is done using <code>==</code> operator.
	 * <p>
	 * If the array does not contain the given element, the given array is not modified and the method returns
	 * <code>false</code>, otherwise it returns <code>true</code>.
	 * <p>
	 * If the array contains several times the given element, only the last added is removed.
	 *
	 * @param array
	 *            the input array.
	 * @param element
	 *            the element to remove.
	 * @param pointer
	 *            the index of the last element of the array.
	 * @param <T>
	 *            the type of array elements.
	 * @return <code>true</code> if the element has been removed, <code>false</code> otherwise.
	 * @throws ArrayIndexOutOfBoundsException
	 *             if the given pointer is greater than the array length.
	 */
	public static <T> boolean remove(T[] array, T element, int pointer) {
		for (int i = pointer; --i >= 0;) {
			if (array[i] == element) {
				System.arraycopy(array, 0, array, 0, i);
				System.arraycopy(array, i + 1, array, i, pointer - i);
				array[pointer] = null;
				return true;
			}
		}
		// nothing removed
		return false;
	}

	/**
	 * Removes an element in an array.
	 * <p>
	 * The comparison between the elements is done using {@link Object#equals(Object)}.
	 * <p>
	 * If the array does not contain the given element, the given array is not modified and the method returns
	 * <code>false</code>, otherwise it returns <code>true</code>.
	 * <p>
	 * If the array contains several times the given element, only the last added is removed.
	 *
	 * @param array
	 *            the input array.
	 * @param element
	 *            the element to remove.
	 * @param pointer
	 *            the index of the last element of the array.
	 * @param <T>
	 *            the type of array elements.
	 * @return <code>true</code> if the element has been removed, <code>false</code> otherwise.
	 * @throws ArrayIndexOutOfBoundsException
	 *             if the given pointer is greater than the array length.
	 */
	public static <T> boolean removeEquals(T[] array, T element, int pointer) {
		for (int i = pointer; --i >= 0;) {
			if (element.equals(array[i])) {
				System.arraycopy(array, 0, array, 0, i);
				System.arraycopy(array, i + 1, array, i, pointer - i);
				array[pointer] = null;
				return true;
			}
		}
		// nothing removed
		return false;
	}

	/**
	 * Gets whether an array contains an element or not.
	 * <p>
	 * The comparison between the elements is done using <code>==</code> operator.
	 *
	 * @param array
	 *            the array.
	 * @param element
	 *            the element to search.
	 * @param pointer
	 *            the index of the last element of the array.
	 * @param <T>
	 *            the type of array elements.
	 * @return <code>true</code> if the element exists in the array, <code>false</code> otherwise.
	 * @throws ArrayIndexOutOfBoundsException
	 *             if the given pointer is greater than the array length.
	 */
	public static <T> boolean contains(T[] array, T element, int pointer) {
		for (int i = pointer; --i >= 0;) {
			if (element == array[i]) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Gets whether an array contains an element or not.
	 * <p>
	 * The comparison between the elements is done using {@link Object#equals(Object)}.
	 *
	 * @param array
	 *            the array.
	 * @param element
	 *            the element to search.
	 * @param pointer
	 *            the index of the last element of the array.
	 * @param <T>
	 *            the type of array elements.
	 * @return <code>true</code> if the element exists in the array, <code>false</code> otherwise.
	 * @throws ArrayIndexOutOfBoundsException
	 *             if the given pointer is greater than the array length.
	 */
	public static <T> boolean containsEquals(T[] array, T element, int pointer) {
		for (int i = pointer; --i >= 0;) {
			if (element.equals(array[i])) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Gets the index of an element in an array. If the array contains several times the given element, the index of the
	 * last added is returned.
	 * <p>
	 * The comparison between the elements is done using <code>==</code> operator.
	 *
	 * @param array
	 *            the array.
	 * @param element
	 *            the element to search.
	 * @param pointer
	 *            the index of the last element of the array.
	 * @param <T>
	 *            the type of array elements.
	 * @return the index of the element in the array or <code>-1</code> if not found.
	 * @throws ArrayIndexOutOfBoundsException
	 *             if the given pointer is greater than the array length.
	 */
	public static <T> int getIndex(T[] array, T element, int pointer) {
		for (int i = pointer; --i >= 0;) {
			if (element == array[i]) {
				return i;
			}
		}
		return -1;
	}

	/**
	 * Gets the index of an element in an array. If the array contains several times the given element, the index of the
	 * last added is returned.
	 * <p>
	 * The comparison between the elements is done using {@link Object#equals(Object)}.
	 *
	 * @param array
	 *            the array.
	 * @param element
	 *            the element to search.
	 * @param pointer
	 *            the index of the last element of the array.
	 * @param <T>
	 *            the type of array elements.
	 * @return the index of the element in the array or <code>-1</code> if not found.
	 * @throws ArrayIndexOutOfBoundsException
	 *             if the given pointer is greater than the array length.
	 */
	public static <T> int getIndexEquals(T[] array, T element, int pointer) {
		for (int i = pointer; --i >= 0;) {
			if (element.equals(array[i])) {
				return i;
			}
		}
		return -1;
	}

	/**
	 * Allocates a new array of the same type than the given array, and then copy the first <code>(pointer + 1)</code>
	 * elements of an array.
	 *
	 * @param array
	 *            the input array.
	 * @param pointer
	 *            the index of the last element of the array.
	 * @param <T>
	 *            the type of array elements.
	 * @return a new allocated array filled with the content of the input array range <code>[0,pointer]</code>.
	 * @deprecated Use <code>Arrays.copyOf(Object[], int)</code> instead.
	 */
	@Deprecated
	public static <T> T[] copy(T[] array, int pointer) {
		return copyInternal(array, pointer + 1);
	}

	/**
	 * Allocates a new array of the given type, and then copy the first <code>(pointer + 1)</code> elements of an array.
	 *
	 * @param array
	 *            the input array
	 * @param pointer
	 *            the index of the last element of the array
	 * @param type
	 *            the output array type
	 * @param <T>
	 *            the type of array elements.
	 * @return a new allocated array filled with the content of the input array range <code>[0,pointer]</code>.
	 * @throws ArrayStoreException
	 *             if the given type is not an array type
	 * @throws ArrayStoreException
	 *             if the given type mismatch the array elements type
	 * @deprecated Use <code>Arrays.copyOf(Object[], int, Class)</code> instead.
	 */
	@Deprecated
	public static <T> T[] copy(Object[] array, int pointer, Class<T[]> type) {
		return copyInternal(array, pointer + 1, type);
	}

	/**
	 * Adds an element in an array.
	 * <p>
	 * The array returned could be different from the given one, it grows to <code>pointer*2</code> only if the given
	 * array is not large enough to add the given element (<code>ptr == array.length</code>).
	 *
	 * @param array
	 *            the input array.
	 * @param element
	 *            the element to add.
	 * @param pointer
	 *            the index of the element to add.
	 * @return the output array.
	 * @throws ArrayIndexOutOfBoundsException
	 *             if the pointer is greater than the array length.
	 */
	public static int[] add(int[] array, int element, int pointer) {
		try {
			array[pointer] = element;
		} catch (ArrayIndexOutOfBoundsException e) {
			// grow array
			int[] result = new int[(pointer << 1) + 1];
			System.arraycopy(array, 0, result, 0, array.length);
			array = result;
			array[pointer] = element;
		}
		return array;
	}

	/**
	 * Removes an element in an array.
	 * <p>
	 * If the array does not contain the given element, the given array is not modified and the method returns
	 * <code>false</code>, otherwise it returns <code>true</code>.
	 * <p>
	 * If the array contains several times the given element, only the last added is removed.
	 *
	 * @param array
	 *            the input array.
	 * @param element
	 *            the element to remove.
	 * @param pointer
	 *            the index of the last element of the array.
	 * @return <code>true</code> if the element has been removed, <code>false</code> otherwise.
	 */
	public static boolean remove(int[] array, int element, int pointer) {
		int arrayLength = array.length;
		for (int i = arrayLength; --i >= 0;) {
			if (array[i] == element) {
				System.arraycopy(array, 0, array, 0, i);
				System.arraycopy(array, i + 1, array, i, pointer - i);
				array[pointer] = 0;
				return true;
			}
		}
		// nothing removed
		return false;
	}

	/**
	 * Gets whether an array contains an element or not.
	 *
	 * @param array
	 *            the array.
	 * @param element
	 *            the element to search.
	 * @param pointer
	 *            the index of the last element of the array.
	 * @return <code>true</code> if the element exists in the array, <code>false</code> otherwise.
	 */
	public static boolean contains(int[] array, int element, int pointer) {
		for (int i = pointer; --i >= 0;) {
			if (element == array[i]) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Copy the <code>(ptr + 1)</code> elements of an array.
	 *
	 * @param array
	 *            the input array.
	 * @param pointer
	 *            the index of the last element of the array.
	 * @return the output array.
	 * @deprecated Use <code>Arrays.copyOf(int[], int)</code> instead.
	 */
	@Deprecated
	public static int[] copy(int[] array, int pointer) {
		int arrayLength = pointer + 1;
		int[] result = new int[arrayLength];
		System.arraycopy(array, 0, result, 0, arrayLength);
		return result;
	}

	private static <T> T[] copyInternal(Object[] array, int arrayLength, Class<T[]> type) {
		T[] result = Util.newArray(type, arrayLength);
		System.arraycopy(array, 0, result, 0, arrayLength);
		return result;
	}

	private static <T> T[] copyInternal(T[] array, int arrayLength) {
		T[] result = createNewArray(array, arrayLength);
		System.arraycopy(array, 0, result, 0, arrayLength);
		return result;
	}

	/**
	 * Creates a new array with the same type as the given array.
	 *
	 * @param array
	 *            the array.
	 * @param length
	 *            the length of the array to create.
	 * @param <T>
	 *            the type of array elements.
	 * @return the created array as an object
	 */
	@SuppressWarnings("unchecked")
	public static <T> T[] createNewArray(T[] array, int length) {
		return Util.newArray((Class<T[]>) array.getClass(), length);
	}

	/**
	 * Creates a new array from the given type and length.
	 *
	 * @param type
	 *            the type of the array to create.
	 * @param length
	 *            the length of the array to create.
	 * @param <T>
	 *            the type of array elements.
	 * @return the created array as an object.
	 * @throws OutOfMemoryError
	 *             if the array could not be allocated.
	 * @deprecated Use {@link Util#newArray(Class, int)} instead.
	 */
	@Deprecated
	public static <T> T[] createNewArray(Class<T[]> type, int length) {
		return Util.newArray(type, length);
	}

}
