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

import java.util.AbstractList;
import java.util.Collection;

/**
 * <p>
 * Specjalna wersja listy, oszczędzająca pamięć w maksymalnym możliwym stopniu.
 * Dokonuje realokacji po dowolnej modyfikacji, odpowiednio zwiększając lub
 * zmniejszając zużycie pamięci w czasie rzeczywistym. W szczególności pusta
 * lista wprowadza minimalny narzut pamięciowy, tzn nie alokuje żadnej pamięci na bufor.
 * </p><p>
 * Klasa wzorowana na {@link javax.swing.event.EventListenerList}, szczególnie
 * przydatna do obsługi kolekcji, które przez większość czasu nie są modyfikowane,
 * posiadają mało elementów, lub w ogóle pozostają puste.
 * </p>
 * całej zawartości
 * @param <T>
 * @author ranides
 */
@SuppressWarnings("unchecked")
public class RTList<T> extends AbstractList<T> {

    private final static Object[] EMPTY = new Object[0];
    private Object[] content = EMPTY;

    /**
     * Tworzy nową pustą listę.
     */
    public RTList() {
        // do nothing
    }

    /**
     * Tworzy nową listę, zawierającą podane elementy.
     * @param values
     */
    public RTList(Collection<? extends T> values) {
        content = values.toArray();
    }

    @Override
    public T get(int index) {
        return (T)content[index];
    }

    @Override
    public int size() {
        return content.length;
    }

    @Override
    public void clear() {
        content = EMPTY;
    }

    @Override
    public T set(int index, T element) {
        T prev = (T)content[index];
        content[index] = element;
        return prev;
    }

    @Override
    public void add(int index, T element) {
        if(index > content.length) {
            throw new IndexOutOfBoundsException(index + " out of bound " + content.length);
        }
        if(content == EMPTY) {
            content = new Object[]{ element };
            return;
        }
        Object[] buffer = new Object[content.length + 1];
        if(index > 0) {
            System.arraycopy(content, 0, buffer, 0, index);
        }
        if(index < content.length) {
            System.arraycopy(content, index, buffer, index+1, content.length - index);
        }
        buffer[index] = element;
        content = buffer;
    }

    @Override
    public T remove(int index) {
        if(index > content.length) {
            throw new IndexOutOfBoundsException(index + " out of bound " + content.length);
        }
        T prev = (T)content[index];
        if(content.length == 1) {
            content = EMPTY;
            return prev;
        }
        Object[] buffer = new Object[content.length - 1];
        if(index > 0) {
            System.arraycopy(content, 0, buffer, 0, index);
        }
        if( content.length - index > 1) {
            System.arraycopy(content, index+1, buffer, index, content.length - index - 1);
        }

        content = buffer;
        return prev;
    }

}
