/*******************************************************************************
 * Copyright 2011 See AUTHORS file.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/

package com.badlogic.gdx.utils;

import java.util.Comparator;

/** Queues any removals done after {@link #begin()} is called to occur once {@link #end()} is called. This can allow code out of
 * your control to remove items without affecting iteration. Between begin and end, most mutator methods will throw
 * IllegalStateException. Only {@link #removeIndex(int)}, {@link #removeValue(Object, boolean)}, and add methods are allowed.
 * <p>
 * Code using this class must not rely on items being removed immediately. Consider using {@link SnapshotArray} if this is a
 * problem..
 * @author Nathan Sweet */
public class DelayedRemovalArray<T> extends Array<T> {
	private boolean iterating;
	private IntArray remove = new IntArray(0);

	public DelayedRemovalArray () {
		super();
	}

	public DelayedRemovalArray (Array array) {
		super(array);
	}

	public DelayedRemovalArray (boolean ordered, int capacity, Class arrayType) {
		super(ordered, capacity, arrayType);
	}

	public DelayedRemovalArray (boolean ordered, int capacity) {
		super(ordered, capacity);
	}

	public DelayedRemovalArray (boolean ordered, T[] array, int startIndex, int count) {
		super(ordered, array, startIndex, count);
	}

	public DelayedRemovalArray (Class arrayType) {
		super(arrayType);
	}

	public DelayedRemovalArray (int capacity) {
		super(capacity);
	}

	public DelayedRemovalArray (T[] array) {
		super(array);
	}

	public void begin () {
		iterating = true;
	}

	public void end () {
		iterating = false;
		for (int i = 0, n = remove.size; i < n; i++)
			removeIndex(remove.pop());
	}

	private void remove (int index) {
		for (int i = 0, n = remove.size; i < n; i++) {
			int removeIndex = remove.get(i);
			if (index == removeIndex) return;
			if (index < removeIndex) {
				remove.insert(i, index);
				return;
			}
		}
		remove.add(index);
	}

	public boolean removeValue (T value, boolean identity) {
		if (iterating) {
			int index = indexOf(value, identity);
			if (index == -1) return false;
			remove(index);
			return true;
		}
		return super.removeValue(value, identity);
	}

	public T removeIndex (int index) {
		if (iterating) {
			remove(index);
			return get(index);
		}
		return super.removeIndex(index);
	}

	public void set (int index, T value) {
		if (iterating) throw new IllegalStateException("Invalid between begin/end.");
		super.set(index, value);
	}

	public void insert (int index, T value) {
		if (iterating) throw new IllegalStateException("Invalid between begin/end.");
		super.insert(index, value);
	}

	public void swap (int first, int second) {
		if (iterating) throw new IllegalStateException("Invalid between begin/end.");
		super.swap(first, second);
	}

	public T pop () {
		if (iterating) throw new IllegalStateException("Invalid between begin/end.");
		return super.pop();
	}

	public void clear () {
		if (iterating) throw new IllegalStateException("Invalid between begin/end.");
		super.clear();
	}

	public void sort () {
		if (iterating) throw new IllegalStateException("Invalid between begin/end.");
		super.sort();
	}

	public void sort (Comparator<T> comparator) {
		if (iterating) throw new IllegalStateException("Invalid between begin/end.");
		super.sort(comparator);
	}

	public void reverse () {
		if (iterating) throw new IllegalStateException("Invalid between begin/end.");
		super.reverse();
	}

	public void shuffle () {
		if (iterating) throw new IllegalStateException("Invalid between begin/end.");
		super.shuffle();
	}

	public void truncate (int newSize) {
		if (iterating) throw new IllegalStateException("Invalid between begin/end.");
		super.truncate(newSize);
	}
}
