#include <iostream>
#include <assert.h>

using namespace std;

template <class T>
class List {
    private:
        T* data;
        int* next;
        int* free;
        int head;
        int current;
        int size;
        int next_free;
    public:
        List(int size);
        bool insert(T e);
        bool remove();
        bool find_first();
        bool find_next();
        bool find_prior();
        bool find_last();
        bool find(T e);
        bool full();
        bool empty();
        T retrieve();
        void update(T e);
};

template <class T>
List<T>::List(int size) : size(size), head(-1), current(-1), next_free(size-1) {
    this->data = new T[size];
    this->next = new int[size];
    this->free = new int[size];
    for(int i = 0; i < size; i++) {
        this->next[i] = -1;
        this->free[i] = i;
    }
}

template <class T>
bool List<T>::full() {
    return (this->next_free == -1);
}

template <class T>
bool List<T>::empty() {
    return (this->head == -1);
}

template <class T>
bool List<T>::insert(T e) {
    if(this->full()) return false;
    int p = this->free[next_free--];
    this->data[p] = e;
    if(this->empty()) {
        this->head = p;
    } else {
        this->next[p] = this->next[this->current];
        this->next[this->current] = p;
    }
    this->current = p;
    return true;
}


template <class T>
bool List<T>::find(T e) {
    if(!this->find_first()) return false;
    do {
        if(this->retrieve() == e){
            return true;
        }
    } while(this->find_next());
    return false;
}

template <class T>
bool List<T>::find_prior() {
    if(this->empty()) return false;
    int p = this->head;
    while(p!=-1 && this->next[p] != this->current) {
        p = this->next[p];
    }
    if(p == -1) {
        return false;
    } else {
        this->current = p;
        return true;
    }
}

template <class T>
bool List<T>::remove() {
    if(this->empty()) return false;
    int node_rem = this->current;
    if(node_rem == this->head) {
        this->head = this->next[node_rem];
        this->current = this->head;
    } else {
        assert(this->find_prior());
        this->next[this->current] = this->next[node_rem];
    }
    this->next[node_rem] = -1;
    this->free[++this->next_free] = node_rem;
    return true;
}

template <class T>
bool List<T>::find_next() {
    if(this->empty()) return false;
    if(this->next[this->current] == -1) return false;
    this->current = this->next[this->current];
    return true;
}

template <class T>
bool List<T>::find_first() {
    if(this->empty()) return false;
    this->current = this->head;
    return true;
}

template <class T>
bool List<T>::find_last() {
    if(!this->find_first()) return false;
    while(this->find_next());
    return true;
}

template <class T>
T List<T>::retrieve() {
    assert(!this->empty());
    return this->data[current];
}

template <class T>
void List<T>::update(T e) {
    assert(!this->empty());
    this->data[current] = e;
}

int main( int argc, char *argv[] ) {
	List<int> l(20);
    int i;
    for(i = 0; !l.full(); i++) {
        l.insert(i);
    }
    assert(i == 20);

    // Delete half
    l.find_first();
    for(i = 0; i < 10; i++) l.remove();

    // Delete 14
    assert(l.find(14));
    assert(l.remove());
    assert(!l.find(14));

    assert()

    // Show values
    assert(l.find_first());
    do {
        cout << l.retrieve() << endl;
    } while(l.find_next());


    // Delete all
    assert(l.find_first());
    while(!l.empty()) l.remove();


    assert(!l.find_first());

	return 0;
}