// lab.cpp : Defines the entry point for the console application.
//
#include <vector>
#include <iostream>
using namespace std;

template <class T>
class data{
T d;
T err;
public:
	data() {d=(T)0.; err=(T)0.;} 
	data(const T a, const T b){
		d=a; 
		err=b;
	}
//	
	data(const data &old){d=old.d; err=old.err;} // questo creatore COPIA un vecchio oggetto in uno nuovo.
	// Ma e' piu' elegante una volta creato l'oggetto ridefinire l'operatore =
	~data(){};
	
	data& operator=(const data &old){d=old.d; err=old.err; return *this;}
	
	
	data& operator+=(const data &A){
	d=d+A.d;
	err=err+A.err;
	return *this;
	}
	const data operator+(const data &A){
	data result;
	result.d=d+A.d;
	result.err=err+A.err;
	return result;
	}
/*	Avrei potuto anche definirlo anche così usando l'operatore +=
    già definito.

    const data data::operator+(const data &A){ 
	data result = *this;     // Copio me stesso.... come dire  data result(*this);
    result += A;            // Uso += per fare la somma.
    return result; 
	}
*/
	T  getd() {return d;}
    T  geterr() {return err;}
	void setd(const T a){d=a;}
	void seterr(const T a){err=a;}
};




/*
Una classe contenitore definita da noi.
*/
template <class T>
class logbook{
public:

	logbook(){n=0;} // Il creatore vuoto non deve fare nulla.

	logbook(const class data<T> A):lemisure(1,A), n(1){
		
		/*n=0; lemisure.push_back(A); n++;*/
	
	} // Il creatore con un argomento inserisce il primo elemento
	
	logbook(const  logbook &old) : lemisure(old.lemisure), n(old.n)
	{ 
		
		/* 
		 
		int i;
		n=old.n;
                lemisure.erase(lemisure.begin(),lemisure.end()); //svuoto il vettore di partenza
		for(i=0;i<n;i++){lemisure.push_back(old.lemisure[i]);} //e lo riempio coi nuovi dati
		*/ 
	}


	~logbook(){};
/*
Di nuovo ridefinisco l'operatore =
*/
    logbook& operator=(const logbook &old){ 
		int i;
		n=old.n; 
		lemisure.erase(lemisure.begin(),lemisure.end()); //svuoto il vettore di partenza
		for(i=0;i<n;i++){lemisure.push_back(old.lemisure[i]);} //e lo riempio coi nuovi dati
		return *this;}

	int	getn(){return n;};
	void addm(const class data<T> A){
		lemisure.push_back(A);
		n++;
	}
/*
Un esempio (molto banale) di funzione che opera sui dati.
*/
T mean(){int i; 
T media;
media=0;
for(i=0;i<n;i++){media=media+lemisure[i].getd();}
return media /( T ) n;
}
/*
In questo caso TUTTI gli attributi della classe sono privati
*/
private:
 	vector<class data<T> > lemisure;
	int n; //numero di misure
};

int main()
{

	vector<int>::iterator primo ; // in questa riga ho definito un iteratore
	double a,b;
	int i;
	a=3.14;
	b=0.11;
	data<int> thedata; // ok NB thedata() e' errato !
	data<double> celafa(a,b); //ok
	logbook<double> thelog(celafa); // creo il logbook
	logbook<double> copylog(thelog);
	copylog.addm(celafa); // aggiungo una misura
	thelog=copylog; // Copio fra loro i due log book.
	cout << "Quanti elementi ha Copylog :" << copylog.getn() << endl;
	data<float> nuovodato(10.,1.); //ok
//	data  ildato(nuovodato); NON FUNZIONA !
//	data<float> ildato(celafa); NON FUNZIONA !
	data<double> ildato(celafa); // ho copiato un dato.
	ildato.setd((double)1.);
	ildato.seterr((double)1.);

	ildato+=ildato;
	
	celafa=ildato+ildato ; // La ridefinizione dell'operatore = mi permette di fare questo !
	thelog.addm(ildato); // aggiungo una misura
	
	cout << "Stampo celafa dovrebbe essere 2 "<< celafa.getd()<< " "<< celafa.geterr()<<" "<< thelog.getn() <<" media: "<< thelog.mean()<< endl;
	cout << "Stampo ildato "<< ildato.getd()<< " "<< ildato.geterr()<<" "<< thelog.getn() <<" "<< thelog.mean()<< endl;
	
	cout << "Stampo il dato  "<< thedata.getd()<< " "<< thedata.geterr() << endl;


	vector<data<double> > ilvettore; //questo e' un contenitore di OGGETTI di tipo data(double)
	cout << "Stampo quanti elementi: "<< ilvettore.capacity() << endl;
	ilvettore.push_back(ildato); // inserisco un primo dato nel vettore
	ildato.setd((double)1.414);
	cout << "Stampo quanti elementi: "<< ilvettore.capacity()<< " E chiamo un metodo del primo elemento: "<< ilvettore[0].getd() << endl;	
	/**/	
	for(i=0;i<10;i++){ildato.setd((double) i); ilvettore.push_back(ildato);
	cout << ilvettore[i].getd() << endl;}
	
	cout << "Stampo quanti elementi: " << ilvettore.capacity() << endl;
vector<data<double> >::iterator first =ilvettore.begin(); // in questa riga ho definito un iteratore
	
vector<data<double> >::iterator last = ilvettore.end(); // in questa riga ho definito un iteratore
	
	while (first != last ) {
	cout << (*first).getd() << endl; // OK !!!!!!!!! 

		cout << " " << endl;
	first++;
	}
/*		vector<int> pippo;
//	pippo[0]=1; ecco l'errore stupido.... non viene visto dal compilatore ma 
//              in esecuzione è un disastro !......  spiegate voi perchè....
    for(i=0;i<10;i++){ pippo.push_back(i);
                     cout << i << " "<< ilvettore[i].getd() << endl;
    }




	primo=pippo.begin(); // primo è stato definito all'inizio.

	for (; primo != pippo.end(); primo++)
    {
        cout << " " << *primo;
    }
    cout << endl;
	vector<int>::iterator ultimo =pippo.end(); // in questa riga ho definito un iteratore
primo=pippo.begin();
	while (primo != pippo.end() ) {
 cout << *primo++ << endl; 

	}

*/

/**/
	return 0;
}

