#ifndef _niz_h_
#define _niz_h_
#include <iostream>
#include "greske.h"
using namespace std;

template <typename T, int U>
	class Niz {
	protected:
		int brPod, kap;
		T* niz;
		void brisi();
		void kopiraj(const Niz& n);
		virtual void pisi(ostream &it);
	public:
		explicit Niz(const int& k = 5);
		Niz(const Niz& n) { kopiraj(n); }
		virtual ~Niz() { brisi(); }
		virtual Niz& operator = (const Niz& n);
		
		// dohvatanje kapaciteta niza i broja podataka u nizu
		int getKap() const { return kap; }
		int getBrPod() const { return brPod; }
		
		// dodavanje novog podatka
		virtual Niz& operator += (T pod);
		
		// pristup podatku
		T& operator [] (const int& i);
		const T& operator [] (const int& i) const;
		// izvlacenje podatka sa zadatim red. br. (podatak se uklanja iz niza)
		T operator () (const int& i);

		friend ostream& operator << (ostream& it, Niz<T, U>& n) {
			n.pisi(it);
			return it;
		}
	};

/***************** Definicije metoda *****************/

template<typename T, int U>
void Niz<T, U>::pisi(ostream &it) {
	if (U == 1)
		for (int i = 0; i < brPod; it << *niz[i++] << endl);
	else
		for (int i = 0; i < brPod; it << niz[i++] << endl);
}
// Podrazumevani konstruktor i obican konstruktor (nije konverzije)
template<typename T, int U>
Niz<T, U>::Niz(const int& k) {
	niz = new T[kap = k];
	brPod = 0;
}

// Oslobadjanje memorije i postavljanje pokazivaca i promenljivih na 0
template<typename T, int U>
void Niz<T, U>::brisi() {
	if (U == 1)
		for (int i = 0; i < this->brPod; i++)
			niz[i];
	delete[] niz;
	niz = 0;
	brPod = kap = 0;
}

// Kopiranje sadrzaja objekta niza u tekuci objekat
template<typename T, int U>
void Niz<T, U>::kopiraj(const Niz& n) {
	niz = new T[kap = n.kap];
	brPod = n.brPod;
	for (int i = 0; i < brPod; i++)
		niz[i] = n.niz[i];
}

// Operator =
template<typename T, int U>
Niz<T, U>& Niz<T, U>::operator = (const Niz& n) {
	if (this != &n) {
		brisi();
		kopiraj(n);
	}
	return *this;
}

// Dodavanje podatka na kraj niza
template<typename T, int U>
Niz<T, U>& Niz<T, U>::operator += (T pod) {
	if (brPod == kap)
		throw GPun();
	niz[brPod++] = pod;
	return *this;
}

// Pristup elementu niza sa zadatim indeksom
template<typename T, int U>
T& Niz<T, U>::operator [] (const int& i) {
	if (i < 0 || i >= brPod)
		throw GIndeks();
	else if (brPod == 0)
		throw GPrazan();
	return niz[i];
}
template<typename T, int U>
const T& Niz<T, U>::operator [] (const int& i) const {
	if (i < 0 || i >= brPod)
		throw GIndeks();
	else if (brPod == 0)
		throw GPrazan();
	return niz[i];
}

// Izvlacenje elementa sa zadatim indeksom
template<typename T, int U>
T Niz<T, U>::operator () (const int& i) {
	if (i < 0 || i >= brPod)
		throw GIndeks();
	else if (brPod == 0)
		throw GPrazan();
	T pod = niz[i];
	for (int j = i; j < brPod - 1; j++)
		niz[j] = niz[j + 1];
	brPod--;
	return pod;
}
#endif
