#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 *************************************
class Date 
{   //dati membro (giorno, mese, anno) 
	short int gg;
	short int mm;
	int aa;
public:
	//costruttori e distruttori
	Date() {gg=1;mm=1;aa=1999;};
	Date(short int, short int, int);
	~Date() {gg=mm=aa=0;};
    //metodi
	short int GetG() {return gg;}
	short int GetM() {return mm;}
	int GetA() {return aa;}
	void SetG(short int g) {gg=g;}
	void SetM(short int m) {mm=m;}
	void SetA(int a) {aa=a;}
	void Display();
	void Input();
	long int Convert();
};

Date::Date(short int d,short 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;
	}
	return giorni;
}


//*****************************************************************************


class Element
{    
	protected:
		String Codice;
		String Modello;
		float Prezzo;

	public:
		Element(); 
		Element(String, String, float);
		virtual ~Element() {}
		String GetCodice() {return Codice;}
		String GetModello() {return Modello;}
		float GetPrezzo() {return Prezzo;}
		void SetCodice(String c) {Codice = c;}
		void SetModello(String c) {Modello = c;}
		void SetPrezzo(float q) {Prezzo = q;}
		virtual void Input();
		virtual void Display();
//metodi virtuali per AutoVen
		virtual String GetNomeP() {return "";}    
		virtual int GetNRichiamo(int) {return 0;}
		virtual Date GetDataR(int) {return Date();}
		virtual String GetDifettoso(int) {return "";}
		virtual int GetNTagliandi(int) {return 0;}
		virtual Date GetDataT(int) {return Date();}
		virtual void SetNomeP(String t) {}
		virtual void SetNRichiamo(int ,int m) {}
		virtual void SetDataR(int , Date b) {}
		virtual void SetDifettoso(int , String c) {}
		virtual void SetNTagliandi(int ,int a) {}
		virtual void SetDataT(int ,Date t) {}
//metodi virtuali per ADisp
		virtual int GetSconto() {return 0;}
		virtual String GetColore() {return "";}
		virtual void SetSconto(int t) {}
        virtual void SetColore(String c) {} 
};

Element::Element()
{
	Codice = "";
	Modello = "";
	Prezzo = 0.0;
}

Element::Element(String e, String o, float q)
{
	Codice = e;
	Modello = o;
	Prezzo = q;
}

void Element::Input()
{
	cout<<"Inserire il codice veicolo: ";
	cin >> Codice;
	cout<<"Inserire il modello: ";
	cin >> Modello;
	cout<<"Inserire il prezzo di vendita: ";
	cin>> Prezzo;
}

void Element::Display()
{
	cout<<"Codice: "<<Codice<<endl;
	cout<<"Modello: "<<Modello<<endl;
	cout<<"Prezzo: "<<Prezzo<<endl;
}

//*****************************************************************************

class AutoVen: public Element
{
	private:
		String NomeP;
		int NRichiamo[6];
		Date DataR[6];
		String Difettoso[6];
		int NTagliandi[10];
		Date DataT[10];
		int i,g;              
	public:
		AutoVen();
		~AutoVen() {}
		String GetNomeP() {return NomeP;}
		int GetNRichiamo(int i) {return NRichiamo[i];} 
		Date GetDataR(int i) {return DataR[i];}        
		String GetDifettoso(int i) {return Difettoso[i];}
		int GetNTagliandi(int g) {return NTagliandi[g];}
		Date GetDataT(int g) {return DataT[g];}
		void SetNomeP(String t) {NomeP = t;}
		void SetNRichiamo(int m[]) {for (i=1; i<=6; i++){NRichiamo[i] = m[i];};}
		void SetDataR(Date b[]) {for (i=1; i<=6; i++){DataR[i] = b[i];};}
		void SetDifettoso(String c[]) {for (i=1; i<=6; i++){Difettoso[i]=c[i];};} 
		void SetNTagliandi(int a[]) {for (g=1; g<=10; g++){NTagliandi[g] = a[g];};}
		void SetDataT(Date t[]) {for (g=1; g<=10; g++){DataT[g]=t[g];};} 
		void Input();
		void Display();
};

AutoVen::AutoVen()
{
	NomeP="";    
}



void AutoVen::Input()
{
	Element::Input();
	cout<<"Inserire il Nome del proprietario: ";
	cin >> NomeP;
	cout<<"Inserire l'elenco richiami (0 per non darne o interrompere):"<<endl;
	for (i=1; i<=6; i++){
        cout<<"Numero richiamo: ";
	    cin >> NRichiamo[i];            
	    if (NRichiamo[i]==0) break;     
	    cout<<"Data per l'intervento: ";
        DataR[i].Input();
	    cout<<"Elemento difettoso: ";
	    cin>> Difettoso[i];
	}
	cout<<"Inserire l'elenco tagliandi (0 per non darne o interrompere): "<<endl;
	for (int g=1; g<=10; g++) {
		cout<<"Numero tagliando: ";
        cin>>NTagliandi[g];
        if (NTagliandi[g]==0) break;
		cout<<"Data: ";
		DataT[g].Input();
	}
}

void AutoVen::Display()
{
	Element::Display();
	cout<<"Nome proprietario: "<<NomeP<<endl;
	for (i=1; i<=6; i++){
      if (NRichiamo[i]==0) break;
    cout<<"Numero richiamo: "<<NRichiamo[i]<<endl;
	cout<<"Data per l'intervento: ";              
	DataR[i].Display();                           
	cout<<"Elemento difettoso: "<<Difettoso[i]<<endl;
	};
	for (g=1; g<=10; g++) {
        if (NTagliandi[g]==0) break;
		cout<<"Numero tagliando: "<<NTagliandi[g]<<endl;
		cout<<"Data: ";
		DataT[g].Display();
	}
}

//******************************************************************************

class ADisp: public Element
{
	private:
		int Sconto;
		String Colore;
	public:
		ADisp();
		ADisp(int,String);
		~ADisp() {}
		int GetSconto() {return Sconto;}
		String GetColore() {return Colore;}
		void SetSconto(int t) {Sconto = t;}
		void SetColore(String c) {Colore = c;}
		void Input();
		void Display();
};

ADisp::ADisp()
{
	Sconto = 0;
	Colore = "";	
}

ADisp::ADisp(int a, String b)
{
	Sconto = a;
	Colore = b;
}


void ADisp::Input()
{
	Element::Input();
	cout<<"Inserire il tipo di sconto (%): ";
	cin>>Sconto;
	cout<<"Inserire il colore: ";
	cin>>Colore;

}

void ADisp::Display()
{
	Element::Display();
	cout<<"Sconto: "<<Sconto<<endl;
	cout<<"Colore: "<<Colore<<endl;
}


//******************************************************************************


//Classe ARCHIVIO PER L'INSERIMENTO DEGLI Elementi
class Archivio  
{
private:
			SeqList<Element *> Arch;
			SeqListIterator<Element *> Iter;
			int count;
public:
			//costruttore e distruttore
			Archivio():Arch(),Iter(Arch),count(0){} 
			~Archivio();

			//metodi di accesso
			SeqList<Element *> GetArch()const{return Arch;}

			// Elaborazioni richieste
			void inserisci();
			void stampa();
			void aggiorna();
			void scansione();
			void aggiornasconto();

};

//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 - Auto venduta"<<endl;
	cout<<"          2 - Auto disponibile"<<endl;
	cout<<"SCELTA: ";
	cin>>choice;
	switch(choice)
		 {case 1 :p=new AutoVen;
						break;
		  case 2 :p=new ADisp;
                  count++;
						break;
		  default:cout<<"SCELTA ERRATA"<<endl;
						return;
		 }
	p->Input();
	Arch.Insert(p);
	cout<<"                    *Dato inserito*\n";
}

//metodo di modifica
void Archivio::aggiorna() 
{
	String Cod;
	cout<<"\n Inserire il codice del veicolo da aggiornare: "<<endl;
	cin>> Cod;
	for (Iter.Reset(); !Iter.EndOfList(); Iter.Next())
		{
		if (Iter.Data()->GetCodice()==Cod){	
	      Iter.Data()->Input();  
	}
	else 
		cout<<"Impossibile aggiornare."<<endl;
	}
}


//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()     
{                         
	String mod;           
	int richiami=0;       
	int prima=0;
	int verifica=0;
	cout<<"Inserire il nome del modello:";
	cin>>mod;
	for(Iter.Reset();!Iter.EndOfList();Iter.Next()){
		 if(Iter.Data()->GetModello()==mod){
               verifica=1;
			   for (int i=1; i<=6; i++){
			       if(Iter.Data()->GetNRichiamo(i)==i) {
				   richiami++;
                      if((Iter.Data()->GetDataR(i).Convert()<=Iter.Data()->GetDataT(1).Convert())||(Iter.Data()->GetNTagliandi(i)==0)) {
				      prima++;		
					  }
				   }
                   else break;
			 }
        }
	}
	if (verifica!=1){
             cout<<"Modello non trovato."<<endl;
			 verifica=1;
			 }
	else {
	      cout<<"Numero di richiami per questo modello: "<<richiami<<endl;
	      if (richiami!=0){
		     if ((prima!=0)){
		     cout<<"Di cui "<<prima<<" avvenuti prima della data del primo tagliando."<<endl;
			 }
		     else cout<<"Tutti avvenuti dopo il primo tagliando."<<endl;
		  }
	}
	 
}

void Archivio::aggiornasconto()
{	int sco;
    cout<<"Numero auto disponibili: "<<count<<endl;
	if (count>=21) {
		cout<<"Sconto da applicare: ";
		cin>>sco;
        for(Iter.Reset();!Iter.EndOfList();Iter.Next())
		{
			Iter.Data()->SetSconto(sco); 
		}
		cout<<"Sconto applicato."<<endl;
	}
}


//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<<"          5 - conteggio auto disponibili"<<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.aggiorna();
									break;
					  case '4' :A.scansione();
									break;
					  case '5' :A.aggiornasconto();
						  break;
					  case 'u' :cout<<"Fine programma";
									break;
					  default:cout<<"SCELTA ERRATA"<<endl;
					}
		  }
 
};


