#include <iostream.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>


class String
{  
	char *itsString;
	unsigned short itsLen;
	String (unsigned short); //costruttore privato
 public:
	//Costruttori
	String();
	String(const char *const);
	String(const String &);
	~String();

	//Operatori overloaded
	char & operator[](unsigned short offset);
	char operator[](unsigned short offset)const;
	String operator+(const String &);
	void operator+=(const String &);
	String & operator=(const String &);

	friend int operator==(const String &, const String &);

	friend ostream & operator<<(ostream &, const String &);
	friend istream & operator>>(istream &, String &);

	//Metodi di accesso generali
	unsigned short GetLen() const {return itsLen;}
	const char* GetString() const {return itsString;}
};

//Costruttore di default crea una String con 0 byte
String::String()
{	
	itsString=new char[1];
	itsString[0]='\0';
	itsLen=0;
}

//Costruttore privato, usato solo dai metodi della classe per
//creare una nuova String della dimensione richiesta
//inizializzata dal carattere null.
String::String(unsigned short len)
{	
	itsString=new char[len+1];
	for(unsigned short i=0; i<=len; i++)
		itsString[i]='\0';
	itsLen=len;
}

//Costruttore che converte a String un array di caratteri,
//il parametro è un puntatore costante ad oggetto costante
String::String(const char *const cString)
{  
	itsLen=strlen(cString);
	itsString=new char[itsLen+1];
	for(unsigned short i=0; i<=itsLen; i++)
		itsString[i]=cString[i];
	itsString[itsLen]='\0';
}

//Costruttore di copia
String::String(const String &rhs)
{   
	itsLen=rhs.GetLen();
	itsString=new char[itsLen+1];
	for(unsigned short i=0; i<=itsLen; i++)
		itsString[i]=rhs[i];
	itsString[itsLen]='\0';
}

//Distruttore
String::~String()
{  
	delete [] itsString;
	itsLen=0;
}

//Operatore = libera la memoria esistente e poi
//copia la String e le dimensioni
String & String::operator=(const String &rhs)
{  
	if (this==&rhs)
		return *this;
	delete [] itsString;
	itsLen=rhs.GetLen();
	itsString=new char[itsLen+1];
	for(unsigned short i=0; i<=itsLen; i++)
		itsString[i]=rhs[i];
	itsString[itsLen]='\0';
	return *this;
}

//Operatore [] non costante, restituisce un reference
//al carattere indicizzato per poterlo cambiare,
//usato come target di una assegnazione
char & String::operator[](unsigned short offset)
{	
	if(offset>itsLen)
		//Se si esce dalle dimensioni si restituisce l'ultimo char
		return itsString[itsLen-1];
	else
		//Si restituisce l'elemento di indice offset
		return itsString[offset];
}

//Operatore [] costante, da usare con oggetti costanti
//per es. col costruttore copia o nelle espressioni
//dove l'operatore può restituire un non reference o un reference const.
char String::operator[](unsigned short offset) const
{	
	if(offset>itsLen)
		//Se si esce dalle dimensioni si restituisce l'ultimo char
		return itsString[itsLen-1];
	else
		//Si restituisce l'elemento di indice offset
		return itsString[offset];
}

//Crea una nuova String concatenando alla
//String corrente la String rhs.
String String::operator+(const String &rhs)
{	
	unsigned short totLen=itsLen+rhs.GetLen();
	String temp(totLen);	//si chiama il costruttore privato
	for (unsigned short i=0; i<itsLen; i++)
		temp[i]=itsString[i];
	for (unsigned short j=0; j<rhs.GetLen(); j++, i++)
		temp[i]=rhs[j];
	temp[totLen]='\0';
	return temp;
}

//Cambia la String corrente, non restituisce nulla,
//concatenando alla String corrente rhs in coda.
void String::operator+=(const String &rhs)
{	
	unsigned short rhsLen=rhs.GetLen();
	unsigned short totLen=itsLen+rhs.GetLen();
	String temp(totLen);
	for (unsigned short i=0; i<itsLen;i++)
		temp[i]=itsString[i];
	for (unsigned short j=0; j<rhsLen; j++,i++)
		temp[i]=rhs[i-itsLen];	//Si copia rhs
	temp[totLen]='\0';
	*this=temp;
}

int operator==(const String &s1, const String &s2)
{
	return strcmp(s1.GetString(), s2.GetString())==0;
}

ostream & operator<<(ostream &os, const String &s)
{
	return os << s.GetString();
}

istream & operator>>(istream &is, String &s)
{
	char buf[256];

	is >> buf;
	s = buf;

	return is;
}

//CLASSE ITERATORE

template <class T>
class Iterator
{
	protected:
		// Indica se è finita la lista
		// deve essere aggiornata dalla classe derivata
		int iterationComplete;

	public:
		// costruttore
		Iterator();

		// Metodi richiesti per l'iteratore
		virtual void Next() = 0;
		virtual void Reset() = 0;

		// Metodo per recupero e modifica del dato
		virtual T& Data() = 0;

		// test fine lista
		virtual int EndOfList() const;
};

// Pone iterationComplete a 0 (False)
template <class T>
Iterator<T>::Iterator(): iterationComplete(0)
{}

// restituisce il valore iterationComplete.
template <class T>
int Iterator<T>::EndOfList() const
{
	return iterationComplete;
}


//CLASSE LIST

template <class T>
class List
{
	 protected:
		  // Numero di elementi della lista aggiornato dalle classi derivate
		  int size;
	 public:
		  // costruttore
		  List();

		  // distruttore virtuale necessario per classi derivate
		  // che usano allocazione di memoria dinamica
		  virtual ~List();

		  // metodi di accesso alla lista
		  virtual int ListSize() const;
		  virtual int ListEmpty() const;
		  virtual int Find (T& item) = 0;

		  // Metodi di modifica della lista: funzioni virtuali pure
		  virtual void Insert(const T& item) = 0;
		  virtual void Delete(const T& item) = 0;
		  virtual void ClearList() = 0;
};

// costruttore pone size a 0
template <class T>
List<T>::List(): size(0)
{}

//distruttore virtuale
template <class T>
List<T>::~List()
{}

// restituisce size
template <class T>
int List<T>::ListSize() const
{
	 return size;
}

// test per una lista vuota
template <class T>
int List<T>::ListEmpty() const
{
	 return size == 0;
}



//CLASSE NODE
template <class T>
class Node
{	Node<T> *next;	//next è l'indirizzo del nodo successivo
  public:
	T data;	//il dato è pubblico

	//Costruttore
	Node (const T& item, Node<T>* ptrnext =NULL);

	//Metodi per modificare la lista
	void InsertAfter (Node<T> *p);
	Node<T> *DeleteAfter ();

	//Metodo per avere l'indirizzo del nodo successivo
	Node<T> *NextNode () const;
};

//Implementazione della classe  Node

template <class T>
Node<T>::Node (const T& item, Node<T>* ptrnext) :
				data(item), next(ptrnext)
{}

template <class T>
void Node<T>::InsertAfter (Node<T> *p)
{  	//p punta al successore del nodo corrente
	//e il nodo corrente punta a p
	p->next =next;
	next =p;
}

template <class T>
Node<T> *Node<T>::DeleteAfter ()
{	//Salvare l'indirizzo del nodo da cancellare
	Node<T> *tempPtr =next;
	//Se non c'è un successore restituisce NULL
	if (next == NULL)
		return NULL;
	//Il nodo corrente punta al successore di tempPtr
	next = tempPtr->next;
	//Restituisce il puntatore al nodo sconnesso
	return tempPtr;
}

template <class T>
Node<T> *Node<T>::NextNode () const
{	return next;
}


//Classe Lista linkata

template <class T>
class LinkedList
{	//Puntatori per accedere alla testa e alla coda della lista
	Node<T>  *front, *rear;
	//Puntatori per le operaz. di Insert e Delete
	Node<T> *prevPtr, *currPtr;
	//Numero di item nella lista
	int size;
	//Posizione nella lista , usata da Reset
	int position;
	//Metodi privati per allocare e deallocare nodi
	Node<T> *GetNode (const T& item, Node<T>* ptrNext=NULL);
	void FreeNode (Node<T> *p);
	//Copia lista L nella lista corrente
	void CopyList (const LinkedList<T>& L);
  public:
	//Costruttori
	LinkedList ();
	LinkedList (const LinkedList<T>& L);
	//Distruttore
	~ LinkedList ();

	//Operatore di assegnazione
	LinkedList<T>& operator= (const LinkedList<T>& L);

	//Metodi per verificare lo stato della lista
	int ListSize () const;
	int ListEmpty () const;

	//Metodi per attraversare la lista
	void Reset (int pos =0);
	void Next ();
	int EndOfList () const;
	int CurrentPosition () const;

	//Metodi per l'inserzione
	void InsertFront (const T& item);
	void InsertRear (const T& item);
	void InsertAt (const T& item);
	void InsertAfter (const T& item);

	//Metodi per cancellare
	T DeleteFront ();
	void DeleteAt ();

	//Modifica del contenuto informativo
	T& Data ();

	//Metodo per il clear della lista
	void ClearList ();

	//Metodo per dare elemento alla testa
	Node<T>* Front ();
};

 //Implementazione della lista LinkedList

//Metodi privati

template <class T>
Node<T> *LinkedList<T>::GetNode(const T& item,
							 Node<T>* ptrNext)
{
	Node<T> *p;

	p = new Node<T>(item,ptrNext);
	if (p == NULL)
	{
		cout << "Fallita allocazione memoria!\n";
		exit(1);
	}
	return p;
}

template <class T>
void LinkedList<T>::FreeNode(Node<T> *p)
{
	delete p;
}

// copia L nella lista corrente, che si assume vuota
template <class T>
void LinkedList<T>::CopyList(const LinkedList<T>& L)
{
	Node<T> *p = L.front;
	int pos;

	// inserisce ogni elemento in L in coda all'oggetto presente
	while (p != NULL)
	{
		InsertRear(p->data);
		p = p->NextNode();
	}

	// se lista è vuota return
	if (position == -1)
		return;

	// reset prevPtr e currPtr  nella nuova lista
	prevPtr = NULL;
	currPtr = front;
	for (pos = 0; pos != position; pos++)
	{
		prevPtr = currPtr;
		currPtr = currPtr->NextNode();
	}
}

//Metodi pubblici

template <class T>
LinkedList<T>::LinkedList ():
				front (NULL), rear (NULL), prevPtr (NULL),
				currPtr (NULL), size (0), position (-1)
{}

template <class T>
LinkedList<T>::LinkedList(const LinkedList<T>& L)
{
	front = rear = NULL;
	prevPtr = currPtr = NULL;
	size = 0;
	position = -1;
	CopyList(L);
}

template <class T>
void LinkedList<T>::ClearList()
{
	Node<T> *currPosition, *nextPosition;

	currPosition = front;
	while(currPosition != NULL)
	{
		// indirizzo del nodo successivo e cancella il nodo corrente
		nextPosition = currPosition->NextNode();
		FreeNode(currPosition);
		currPosition = nextPosition;
	}
	front = rear = NULL;
	prevPtr = currPtr = NULL;
	size = 0;
	position = -1;
}

template <class T>
LinkedList<T>::~LinkedList()
{
	ClearList();
}

template <class T>
LinkedList<T>& LinkedList<T>::operator=
					(const LinkedList<T>& L)
{
	if (this == &L)      //Non può assegnare lista a sé stessa
		return *this;

	ClearList();
	CopyList(L);
	return *this;
}

template <class T>
int LinkedList<T>::ListSize() const
{
	return size;
}

template <class T>
int LinkedList<T>::ListEmpty() const
{
	return size == 0;
}

// sposta avanti di un nodo prevPtr e currPtr
template <class T>
void LinkedList<T>::Next()
{
	// se la scansione ha raggiunto la fine della lista o
	// la lista è vuota, return
	if (currPtr != NULL)
	{
		// avanzano i due  puntatori al nodo successivo
		prevPtr = currPtr;
		currPtr = currPtr->NextNode();
		position++;
	}
}

// True se il cliente ha attraversato la lista
template <class T>
int LinkedList<T>::EndOfList() const
{
	return currPtr == NULL;
}

// restituisce la posizione del nodo corrente
template <class T>
int LinkedList<T>::CurrentPosition() const
{
	return position;
}

//Reset per attraversare la lista a partire dall'inizio
template <class T>
void LinkedList<T>::Reset (int pos)
{	int startPos;
	//se la lista è vuota return
	if (front == NULL)
		return;
	//se la posizione non è valida terminare il programma
	if (pos <0 || pos> size-1)
	{	cerr << "Reset: posizione non valida: " << pos << endl;
		return;
	}
	//Spostarsi sul nodo pos
	if (pos ==0)
	{	//reset alla testa lista
		prevPtr = NULL;
		currPtr = front;
	position =0;
	}
	else
	{	//Reset dei puntatori
		currPtr = front->NextNode ();
		prevPtr = front;
		startPos = 1;
		//Spostarsi fino a pos
		for (position =startPos; position != pos; position++)
		{	prevPtr = currPtr;
			currPtr = currPtr->NextNode ();
		}
	}
}

// restituisce un reference al valore nel nodo corrente
template <class T>
T& LinkedList<T>::Data()
{
	// errore se lista vota o scansione completa
	if (size == 0 || currPtr == NULL)
	{
		cerr << "Data: reference non valida!" << endl;
		exit(1);
	}
	return currPtr->data;
}

// Inserisce item alla testa di lista
template <class T>
void LinkedList<T>::InsertFront(const T& item)
{
	// chiama Reset se la lista non è vuota
	if (front != NULL)
		Reset();
	InsertAt(item);        // inserisce in testa
}

// Inserisce item in coda a lista
template <class T>
void LinkedList<T>::InsertRear(const T& item)
{
	Node<T> *newNode;

	prevPtr = rear;
	newNode = GetNode(item);	// crea il nuovo nodo
	if (rear == NULL)			// se lista vuota, inserisce in testa
		front = rear = newNode;
	else
	{
		rear->InsertAfter(newNode);
		rear = newNode;
	}
	currPtr = rear;
	position = size;
	size++;
}

// Inserisce item in posizione corrente
template <class T>
void LinkedList<T>::InsertAt(const T& item)
{
	Node<T> *newNode;

	// 2 casi: inserzione in testa o dentro la lista
	if (prevPtr == NULL)
	{
		// inserisce in testa,
		// pone nodo in una lista vuota
		newNode = GetNode(item,front);
		front = newNode;
	}
	else
	{
		// inserisce in lista, pone il nodo dopo prevPtr
		newNode = GetNode(item);
		prevPtr->InsertAfter(newNode);
	}

	// if prevPtr == rear, si sta inserendo in lista vuota
	// o in coda di una lista non vuota; aggiorna rear e position
	if (prevPtr == rear)
	{
		rear = newNode;
		position = size;
	}

	// aggiorna currPtr e incrementa size
	currPtr = newNode;
	size++;
}

// Inserisce item dopo la posizione corrente
template <class T>
void LinkedList<T>::InsertAfter(const T& item)
{
	Node<T> *p;

	p = GetNode(item);
	if (front == NULL)       // inserzione in lista vuota
	{
		front = currPtr = rear = p;
		position = 0;
	}
	else
	{
		// inserzione dopo l'ultimo nodo
		if (currPtr == NULL)
		  currPtr = prevPtr;
		currPtr->InsertAfter(p);
		if (currPtr == rear)
		{
		  rear = p;
		  position = size;
		}
		else
			position++;
			prevPtr = currPtr;
			currPtr = p;
	}
	size++;              // incrementa size
}

// Cancella nodo in testa
template <class T>
T LinkedList<T>::DeleteFront()
{
	T item;

	Reset();
	if (front == NULL)
	{
		cerr << "Cancellazione non valida!" << endl;
		exit(1);
	}
	item = currPtr->data;
	DeleteAt();
	return item;
}

//Cancella nodo in posizione corrente
template <class T>
void LinkedList<T>::DeleteAt()
{
	Node<T> *p;

	// error se lista vuota o fine lista
	if (currPtr == NULL)
	{
		cerr << "Cancellazione non valida!" << endl;
		exit(1);
	}

	// cancella zione in testa o dentro
	if (prevPtr == NULL)
	{
		// salva l'indirizzo della testa
		// se è ultimo nodo  front diventa NULL
		p = front;
		front = front->NextNode();
	}
	else
		// scollega nodo dopo prevPtr, salva indirizzo
		p = prevPtr->DeleteAfter();

	// se rear è cancellato, nuova rear è prevPtr e position
	// è decrementata; altrimenti, position è la stessa
	// se p era ultimo nodo, rear = NULL e position = -1
	if (p == rear)
	{
		rear = prevPtr;
		position--;
	}

	// sposta currPtr dopo il nodo cancellato, se p è ultimo nodo
	//currPtr diventa NULL
	currPtr = p->NextNode();

	// rilascia il nodo e  decrementa size
	cout<< "Cancellare in llist"<<endl;
	FreeNode(p);
	size--;
}

template <class T>
Node<T>* LinkedList<T>::Front ( )
{ return front;
}


// CLASSE SEQLIST

template <class T>
class SeqListIterator;

template <class T>
class SeqList: public List<T>
{
	protected:
		// oggetto lista linkata
		LinkedList<T> llist;

	public:
		// costruttore
		SeqList();

		// metodi di accesso alla lista
		virtual int Find (T& item);
		T GetData(int pos);

		// Metodi di modifica della lista
		virtual void Insert(const T& item);
		virtual void Delete(const T& item);
		T DeleteFront( );
		virtual void ClearList( );

		// SeqListIterator richiede di accedere a llist
		friend class SeqListIterator<T>;
};

// costruttore di default inizializza classe base
template <class T>
SeqList<T>::SeqList(): List<T>()
{}

// usa metodo ClearList per il clear di llist
template <class T>
void SeqList<T>::ClearList()
{
	llist.ClearList();
	size = 0;
}

// usa metodo InsertRear per aggiungere elementi in coda alla lista
template <class T>
void SeqList<T>::Insert(const T& item)
{
	llist.InsertRear(item);
	size++;	// aggiorna size
}

// usa metodo DeleteFront per rimuovere il I elemento
template <class T>
T SeqList<T>::DeleteFront()
{
	size--;
	return llist.DeleteFront();
}

// cancella nodo il cui valore è uguale ad item
template <class T>
void SeqList<T>::Delete(const T& item)
{
	int result = 0;

	// ricerca item se trova, pone result a true
	for(llist.Reset();!llist.EndOfList();llist.Next())
		if (item == llist.Data())
		{
			result++;
			break;
		}

	// se ha trovato item, lo cancella e decrementa size
	if (result)
	{  cout<<"cancellare"<<endl;
		llist.DeleteAt();
		size--;
	}
}

// restituisce il valore di item nella posizione pos
template <class T>
T SeqList<T>::GetData(int pos)
{ // verifica se è posizione valida
	if (pos < 0 || pos >= llist.ListSize())
	{
		cerr << "pos è fuori range!" << endl;
		exit(1);
	}
	// pone a pos posizione corrente nella linked list e return data
	llist.Reset(pos);
	return llist.Data();
}

// Ricerca item in lista, return True se trova
// False altrimenti. Se ha trovato
// assegna l'elemento al parametro reference item
template <class T>
int SeqList<T>::Find (T& item)
{
	int result = 0;

	// ricerca item in lista, se trova, set result a True
	for(llist.Reset();!llist.EndOfList();llist.Next())
		if (item == llist.Data())
		{
			result++;
			break;
		}

	// se True, aggiorna item e return True; else, return False
	if (result)
		item = llist.Data();
	return result;
}


//CLASSE SEQLISTITERATOR DERIVATA DA ITERATOR

template <class T>
class SeqListIterator:   public Iterator<T>
{
	private:
		// puntatore locale a SeqList che si sta scandendo
		SeqList<T> *listPtr;
		// mantiene puntatori previous e current
		// mentre si scandisce la lista
		Node<T> *prevPtr, *currPtr;

	public:
		// costruttore
		SeqListIterator(SeqList<T>& lst);

		// Metodi per la scansione
		virtual void Next();
		virtual void Reset();

		// Metodi per accedere e modificare il dato
		virtual T& Data();

		// fa il reset dell'iteratore per scandire una nuova lista
	  //è l'equivalente del costruttore in run time
		void SetList(SeqList<T>& lst);
};

// costruttore: inizializza costruttore classe base e puntatore SeqList
template <class T>
SeqListIterator<T>::SeqListIterator(SeqList<T>& lst) :
		Iterator<T>(), listPtr(&lst)
{
	// La lista può essere vuota
	iterationComplete = listPtr->llist.ListEmpty();
	// posiziona iterator al front della lista
	Reset();
}

// avanza al successivo elemento di lista
//quando arriva alla fine lista segnala che l'iterazione è completa
template <class T>
void SeqListIterator<T>::Next()
{
	//se currPtr è NULL, si è alla fine di lista
	if (currPtr == NULL)
		return;

	// si sposta prevPtr/currPtr avanti di un nodo
	prevPtr = currPtr;
	currPtr = currPtr->NextNode();

	// se si è alla fine della lista, segnala
	// che l'iterazione è completa
	if (currPtr == NULL)
		iterationComplete = 1;
}

// Inizializza la scansione all'inizio di  lista
template <class T>
void SeqListIterator<T>::Reset()
{
	// riasssegna lo stato della iteratione
	iterationComplete = listPtr->llist.ListEmpty();

	// se lista è vuota, return
	if (listPtr->llist.Front() == NULL)
		return;

	// inizializza al primo nodo della lista
	prevPtr = NULL;
	currPtr = listPtr->llist.Front();
}

// restituisce il valore del nodo corrente nella lista
template <class T>
T& SeqListIterator<T>::Data()
{
	// errore se lista è vuota o scansione completa
	if (listPtr->llist.ListEmpty() || currPtr == NULL)
	{
		cerr << "Data: riferimento non valido!" << endl;
		exit(1);
	}
	return currPtr->data;
}

//L'iteratore attraversa una nuova lista lst passata come parametro,
//riassegna listPtr e chiama Reset
template <class T>
void SeqListIterator<T>::SetList(SeqList<T>& lst)
{
	listPtr = &lst;

	// posiziona al primo dato nella nuova lista
	Reset();
}



//**********************Classe Date (fatta da me)************************
class Date 
{   //dati membro (giorno, mese, anno) 
	int gg;
	int mm;
	int aa;
public:
	//costruttori e distruttori
	Date() {gg=1;mm=1;aa=1999;};
	Date(int, int, int);
	~Date() {gg=mm=aa=0;};
    //metodi
	int GetG() {return gg;}
	int GetM() {return mm;}
	int GetA() {return aa;}
	void SetG(int g) {gg=g;}
	void SetM(int m) {mm=m;}
	void SetA(int a) {aa=a;}
	void Display();
	void Input();
	long int Convert();
};

Date::Date(int d, int o, int y)
{
	gg=d;
	mm=o;
	aa=y;
}

void Date::Display()
{
	cout<<gg<<"/"<<mm<<"/"<<aa<<endl;
}
void Date::Input()
{
	cout<<"Inserire la Data (gg , mm ,aaaa):"<<endl;
	cin>>gg>>mm>>aa;
    if ((gg<=1)&&(gg>=31)&&(mm>=1)&&(mm>=12)&&(aa==0)) {
		cout<<"Data inesistente!"<<endl;
		exit (1);
	}
}
long int Date::Convert()
{
	long int giorni;
	int d;
	if ((gg>=1)&&(gg<=31)&&(mm>=1)&&(mm<=12)&&(aa!=0)) {
		switch (mm) {
		case 1 : d=0;
			break;
        case 2 : d=31;
			break;
		case 3 : d=59;
			break;
		case 4 : d=90;
			break;
		case 5 : d=120;
			break;
		case 6 : d=151;
			break;
		case 7 : d=181;
			break;
		case 8 : d=212;
			break;
		case 9 : d=243;
			break;
		case 10 : d=273;
			break;
		case 11 : d=304;
			break;
		default : d=334;
			break;
		}
		giorni=(aa*365)+d+gg;
	}
	else {
		cout<<"Data inesistente!"<<endl;
		exit (1);
	}
	return giorni;
}


//*****************************************************************************


class element
{    
	protected:
		int Razza;
		int Tipo;
		String Nome;

	public:
		element();
		element(int, int, String);
		virtual ~element() {}
		int GetRazza() {return Razza;}
		int GetTipo() {return Tipo;}
		String GetNome() {return Nome;}
		void SetRazza(int c) {Razza = c;}
		void SetTipo(int c) {Tipo = c;}
		void SetNome(String q) {Nome = q;}
		virtual void Input() ;
		virtual void Display() ;
//metodi virtuali per Single
		virtual int Geteta() { return 0;}
		virtual float Getpeso() { return 0;}
		virtual char Getsesso(){ return '0';}
		virtual String Getcarat1(){ return "";}
		virtual void Seteta(int t){}
		virtual void Setpeso(float m){}
		virtual void Setsesso(char b){}
		virtual void Setcarat1(String a){}
//metodi virtuali per Coppia
		virtual Date Getborn() {return Date ();}
		virtual int Getncucc() {return 0;}
		virtual int Getnprogr() {return 0;}
		virtual String Getcarat2() {return "";}
		virtual long int Getprezzob() {return 0;}
		virtual char Getvenduto() {return '0';}
		virtual long int Getcosto() {return 0;}
		virtual void Setborn(Date t) {}
		virtual void Setncucc(int c) {}
		virtual void Setnprogr(int n) {}
		virtual void Setcarat2(String l) {}
		virtual void Setprezzob(long int p) {}
		virtual void Setvenduto(char s) {}
		virtual void Setcosto(long int k) {}
		virtual void aggiorna() {}
};

element::element()
{
	Razza = 0;
	Tipo = 0;
	Nome = "";
}

element::element(int e, int o, String q)
{
	Razza = e;
	Tipo = o;
	Nome = q;
}

void element::Input()
{
	cout<<"Selezionare razza (1-Labrador,2-S.Bernardo,3-Beagle,4-Chiuaua,5-Meticcio): ";
	cin >> Razza;
	cout<<"Inserire il Nome: ";
	cin >> Nome;
}

void element::Display()
{
	cout<<"Razza: ";
    switch(Razza){
					case 1:cout<<"Labrador"<<endl;
							break;
                    case 2:cout<<"S.Bernardo"<<endl;
						break;
					case 3:cout<<"Beagle"<<endl;
						break;
					case 4:cout<<"Chiuaua"<<endl;
						break;
					default:cout<<"Meticcio"<<endl;
							break;
					}
	cout<<"Tipo: ";
	switch(Tipo){
					case 1:cout<<"Singolo"<<endl;
							break;
					case 2:cout<<"Coppia"<<endl;
							break;
					default : cout<<"boh"<<endl;
					}
	cout<<"Nome: "<<Nome<<endl;
}

//*****************************************************************************

class single: public element
{
	private:
		int eta;
		float peso;
		char sesso;
		String carat;
	public:
		single();
		single(int,float,char,String);
		single(single &);
		~single() {}
		int Geteta() {return eta;}
		float Getpeso() {return peso;}
		char Getsesso() {return sesso;}
		String Getcarat1() {return carat;}
		void Seteta(int t) {eta = t;}
		void Setpeso(float m) {peso = m;}
		void Setsesso(char b) {sesso = b;}
		void Setcarat1(String a) {carat = a;}
		single& operator = (single &);
		int operator == (single &);
		void Input();
		void Display();
};

single::single(): element()
{
	eta = 0;
	peso = 0.0;
	sesso = '0';
	carat = "";
}

single::single(int e, float p, char s, String c)
{
	eta = e;
	peso = p;
	sesso = s;
	carat = c;
}


void single::Input()
{
	element::Input();
	cout<<"Inserire l'eta': ";
	cin >> eta;
	cout<<"Inserire il peso: ";
	cin >> peso;
	cout<<"Dichiarare il sesso (M/F): ";
	cin >> sesso;
	cout<<"Inserire eventuali caratteristiche: ";
	cin>> carat;
}

void single::Display()
{
	element::Display();
	cout<<"L'eta' e': ";
	cout << eta;
	cout<<endl<<"il peso e': "<<peso<<endl;
	cout<<"sesso: "<<sesso<<endl;
	cout<<"caratteristiche: "<<carat<<endl;
}

//******************************************************************************

class coppia: public element
{
	private:
		Date born;
		int ncucc;
		int nprogr;
		String carat;
		long int prezzob;
		char venduto;
		long int costo;
	public:
		coppia();
		coppia(Date, int, int, String, long int, char, long int);
		coppia(coppia &);
		~coppia() {}
		Date Getborn() {return born;}
		int Getncucc() {return ncucc;}
		int Getnprogr() {return nprogr;}
		String Getcarat2() {return carat;}
		long int Getprezzob() {return prezzob;}
		char Getvenduto() {return venduto;}
		long int Getcosto() {return costo;}
		void Setborn(Date t) {born = t;}
		void Setncucc(int c) {ncucc = c;}
		void Setnprogr(int n) {nprogr = n;}
		void Setcarat2(String l) {carat = l;}
		void Setprezzob (long int p) {prezzob = p;}
		void Setvenduto (char s) {venduto = s;}
		void Setcosto (long int k) {costo = k;}
		coppia& operator = (coppia &);
		void aggiorna (); // da definire
		void Input();
		void Display();
};

coppia::coppia()
{
	born = Date ();
	ncucc = 0;
	nprogr = 0;
	carat = "";
	prezzob = 0;
	venduto = '0';
	costo = 0;
}

coppia::coppia(Date a, int b, int c, String d, long int e, char f, long int g)
{
	born = a;
	ncucc = b;
	nprogr = c;
	carat = d;
	prezzob = e;
	venduto = f;
	costo = g;
}




void coppia::Input()
{
	element::Input();
	born.Input();
	cout<<"Inserire il numero di cuccioli: ";
	cin>>ncucc;
	cout<<"Inserire eventuali caratteristiche: ";
	cin>>carat;
	cout<<"Inserire il prezzo base: ";
	cin>>prezzob;
	costo=prezzob;
	cout<<"Specificare se il cane e' venduto (S/N): ";
	cin>>venduto;

}

void coppia::Display()
{
	element::Display();
	cout<<"Data di nascita:";
	born.Display();
	cout<<"Numero cuccioli: ";
	cout<<ncucc;
	cout<<endl<<"Caratteristiche: ";
	cout<<carat;
	cout<<endl<<"Prezzo base: "<<prezzob<<endl;
	cout<<"Cane venduto: "<<venduto;
	cout<<endl<<"Costo attuale:"<<costo<<endl;
}
void coppia::aggiorna()
{
    long int attuale;
    attuale=Getcosto();
	cout<<"Il costo attuale e': "<<attuale<<endl;
	cout<<"Inserire il nuovo costo:";
	cin>>attuale;
	Setcosto(attuale);
	cout<<"Il costo e' stato aggiornato."<<endl;
	char d;
	d=Getvenduto();
	cout<<"Lo stato di vendita attuale e': "<<d<<endl;
	cout<<"Selezionare il nuovo stato di vendita: cane venduto (S/N): ";
	cin>>d;
	Setvenduto(d);
	cout<<"Stato di vendita aggiornato."<<endl;
}


//******************************************************************************


//Classe ARCHIVIO PER L'INSERIMENTO DEGLI ELEMENTI
class Archivio  
{
private:
			SeqList<element *> Arch;
			SeqListIterator<element *> Iter;
public:
			//costruttore e distruttore
			Archivio():Arch(),Iter(Arch){}
			~Archivio();

			//metodi di accesso
			SeqList<element *> GetArch()const{return Arch;}

			// Elaborazioni richieste
			void inserisci();
			void modifica();
			void stampa();
			void scansione();

};

//distruttore
Archivio::~Archivio()
{
	for (Iter.Reset();!Iter.EndOfList();Iter.Next())
	delete Iter.Data();
}

//metodo di inserimento
void Archivio::inserisci()
{  element *p;
   int choice=0;
	cout<<"          1 - Singolo"<<endl;
	cout<<"          2 - Coppia"<<endl;
	cout<<"SCELTA: ";
	cin>>choice;
	switch(choice)
		 {case 1 :p=new single;
						break;
		  case 2 :p=new coppia;
						break;
		  default:cout<<"SCELTA ERRATA"<<endl;
						return;
		 }
	p->SetTipo(choice);
	p->Input();
	Arch.Insert(p);
	cout<<"                    *Dato inserito*\n";
}

//metodo di modifica
void Archivio::modifica()
{
	String Nom;
	cout<<"\n Inserire il nome per l'aggiornamento dei dati: "<<endl;
	cin>> Nom;
	for (Iter.Reset(); !Iter.EndOfList(); Iter.Next())
		{
		if (Iter.Data()->GetNome()==Nom)
			break;
		}
	if (Iter.Data()->GetTipo()==2) {
	 Iter.Data()->aggiorna();
	}
	else {cout<<"Impossibile aggiornare:"<<endl;
		cout<<"nome del cane non presente in archivio o appartenente al tipo single.";
	}
}

//metodo di stampa
 void Archivio::stampa()
 { cout<<"\n      ARCH:\n";
	for(Iter.Reset();!Iter.EndOfList();Iter.Next())
	{Iter.Data()->Display();
	  cout<<"---------------------------------------------------------------------\n";
	  cout<<"             *PREMERE UN TASTO PER CONTINUARE*\n";
	  getch();
	}
 }

//metodo di scansione
void Archivio::scansione()
{
	int n=0;
	int r=1;
	int ntot=0;
	int nati=0;
	int nvend=0;
	Date oggi;
	cout<<"Inserire la data di oggi:";
	oggi.Input();
    for(r ; r<=5; r++)	{
	 for(Iter.Reset();!Iter.EndOfList();Iter.Next())
		{
		 if(Iter.Data()->GetRazza()==r)
				{
				if(Iter.Data()->GetTipo()==1) {
					n++;
				 };
                if(Iter.Data()->GetTipo()==2) {
					ntot+=(Iter.Data()->Getncucc());
					if((oggi.GetA()==Iter.Data()->Getborn().GetA())&&(oggi.GetM()==Iter.Data()->Getborn().GetM())) {
						nati+=ntot;
					}
					else nati=0;
					if(Iter.Data()->Getvenduto()=='s') {
						nvend++;
				}
			}
			
		}
	 }
            cout<<"Razza: ";
            switch(r){
					case 1:cout<<"Labrador"<<endl;
							break;
                    case 2:cout<<"S.Bernardo"<<endl;
						break;
					case 3:cout<<"Beagle"<<endl;
						break;
					case 4:cout<<"Chiuaua"<<endl;
						break;
					default:cout<<"Meticcio"<<endl;
							break;
			}
			cout<<"Numero cani da riproduzione: "<<n<<endl;
			cout<<"Numero totale cuccioli: "<<ntot<<endl;
			cout<<"Numero cuccioli nati in questo mese: "<<nati<<endl;
			n=ntot=nati=0;
		}
	
	
}

//MAIN
void main()
 { Archivio A;
	char choice='?';
	while(choice!='u')
		  { cout<<"\n   ***************************MENU***************************"<<endl;
			 cout<<"          1 - Inserimento"<<endl;
			 cout<<"          2 - Stampa Arch"<<endl;
			 cout<<"          3 - operazioni di modifica"<<endl;
			 cout<<"          4 - scansione"<<endl;
			 cout<<"          u - Per uscire"<<endl;
			 cout<<"   **********************************************************"<<endl;
			 cout<<"SCELTA: ";
			 cin>>choice;
			 switch(choice)
					{ case '1' :A.inserisci();
									break;
					  case '2' :A.stampa();
									break;
					  case '3' :A.modifica();
									break;
					  case '4' :A.scansione();
									break;
					  case 'u' :cout<<"Fine programma";
									break;
					  default:cout<<"SCELTA ERRATA"<<endl;
					}
		  }
 }


