/*
 * template_1.cc
 */

#include <iostream>

using namespace std;

class out_of_bounds_exception_class : public exception {
public:
    virtual const char * get_message() {
        return "Index out of bounds exception";
    }
};

class out_of_LOW_bounds_exception_class : public out_of_bounds_exception_class {
public:
    const char * get_message() {
        return "Index out of LOW bounds exception";
    }
};


class out_of_HIGH_bounds_exception_class : public out_of_bounds_exception_class {
public:
    const char * get_message() {
        return "Index out of HIGH bounds exception";
    }
};


out_of_bounds_exception_class out_of_bounds_exception;
out_of_LOW_bounds_exception_class out_of_low_bounds_exception;
out_of_HIGH_bounds_exception_class out_of_high_bounds_exception;


template <class T>
class Vector {
    T * data;
    int current_size, array_size;
    static const int space = 20;
public:
    Vector();
    ~Vector();
    int size() { return current_size; };
    Vector& operator+=(T item);
    T operator[](int index);
};

template <class T>
Vector<T>::Vector()
{
    data = new T[space];
    current_size = 0;
    array_size = space;
}


template <class T>
Vector<T>::~Vector()
{
    delete [] data;
}


template <class T>
Vector<T>& Vector<T>::operator+=(T item)
{
    T * new_data;
    if (current_size < array_size) {
        data[current_size] = item;
        current_size++;
    }
    else {
        array_size += space;
        new_data = new T[array_size];
        for (int i = 0;i < current_size;i++)
            new_data[i] = data[i];
        new_data[current_size] = item;
        current_size++;
        data = new_data;
    }
    return *this;
}


template <class T>
T Vector<T>::operator[](int index)
{
    if (index < 0)
        throw out_of_low_bounds_exception;
    if (index >= current_size)
        throw out_of_high_bounds_exception;
    return data[index];
}


template <class T> ostream& operator<<(ostream& out, Vector<T> & s)
{
    for (int i = 0; i < s.size();i++) {
        out << s[i] << " ";
    }
    return out;
}

main()
{
    Vector<float> f_Vector;
    Vector<int>   i_Vector;

    i_Vector += 4;
    i_Vector += 3;
    i_Vector += 2;
    i_Vector += 1;

    f_Vector += 3.14;
    f_Vector += 2.71;

    cout << "INT VECTOR=" << i_Vector << endl;
    cout << "FLOAT VECTOR=" << f_Vector << endl << endl;

    for (;;) {
        int index;
        cout << "Enter index ";
        cin >> index;
        try {
            cout << "Value = " << f_Vector[index] << endl;
        }
        catch (out_of_LOW_bounds_exception_class & exc) {
            cout << "ERROR (LOW): " << exc.get_message() << endl;
        }
        catch (out_of_HIGH_bounds_exception_class & exc) {
            cout << "ERROR (HIGH): " << exc.get_message() << endl;
        }
    }

}
