#ifndef __ARRAYLIST_H__
#define	__ARRAYLIST_H__

#include <cstdio>
#include <cstdlib>
//algunos compiladores necesitan cstring para memcpy
#include <cstring>

#ifndef NULL
#define NULL 0
#endif

template<class TYPE>
class ArrayList {
protected:
	static const int INICIAL = 20;
	static const int GROW = 10;
	TYPE *args;
	int numArgs;
	int total;

public:
	ArrayList();
	ArrayList(int);
	~ArrayList();
	TYPE &operator[](int);
	const TYPE &operator[](int) const;
	void add(TYPE);
	void add(TYPE, int);
	TYPE del(int);
	int search(TYPE);
	int size();
	bool isEmpty();
	void flush();
};

template<class TYPE>
ArrayList<TYPE>::ArrayList(){
	args = new TYPE[INICIAL];
	numArgs = 0;
	total = INICIAL;
}
template<class TYPE>
ArrayList<TYPE>::ArrayList(int tam){
	args = new TYPE[tam];
	numArgs = 0;
	total = tam;
}
template <class TYPE>
TYPE &ArrayList<TYPE>::operator [](int indice){
	if(indice < 0 || indice >= numArgs)
		return args[-1];
	return args[indice];
}
template <class TYPE>
const TYPE &ArrayList<TYPE>::operator [](int indice) const{
	if(indice < 0 || indice >= numArgs)
		return NULL;
	return args[indice];
}
template<class TYPE>
void ArrayList<TYPE>::add(TYPE arg){
        if( numArgs == total )
        {
			TYPE *tmp = args;

            args = new TYPE[total + GROW];
			for(int i = 0 ; i < total ; i++)
				*(args + i) = *(tmp + i);

			delete [] tmp;
			total = total + GROW;
        }
        args[ numArgs++ ] = arg;
}

template<class TYPE>
void ArrayList<TYPE>::add(TYPE arg, int pos){
	if(pos < 0 || pos >= numArgs)
		return;
    if( numArgs == total )
    {
		TYPE *tmp = args;

        args = new TYPE[total + GROW];
		for(int i = 0 ; i < total ; i++)
			*(args + i) = *(tmp + i);

		delete [] tmp;
		total = total + GROW;
    }
    for( int i = numArgs; i >= pos; i-- )
    {
        args[ i + 1 ] = args[ i ];
    }
    numArgs++;
    args[ pos ] = arg;
}
template <class TYPE>
TYPE ArrayList<TYPE>::del(int pos){
	if( pos < 0 || pos >= numArgs )
    {
         return NULL;
    }
    TYPE dele = args[ pos ];
    for( int i = pos; i < numArgs - 1; i++ )
    {
        args[ i ] = args[ i + 1 ];
    }
    args[ --numArgs] = NULL;
    return dele;
}
template <class TYPE>
int ArrayList<TYPE>::search(TYPE arg){
		int pos = 0;
        for( ; pos < numArgs && arg != args[ pos ] ; pos++ );
        return pos == numArgs ? -1 : pos;
}
template <class TYPE>
int ArrayList<TYPE>::size(){
	return numArgs;
}

template <class TYPE>
bool ArrayList<TYPE>::isEmpty(){
	return !numArgs;
}

template <class TYPE>
void ArrayList<TYPE>::flush(){
	delete [] args;
	args = new TYPE[INICIAL];
	numArgs = 0;
	total = INICIAL;

}
template<class TYPE>
ArrayList<TYPE>::~ArrayList(){
	delete []args;
}
#endif
