// dwukierunkowa szblonowa lista punktów, napisów,... (Aleksy B.)

// zadanie domowe: dodaj własną interpretację i zaznacz ją
//                  wykorzystaj klasę WyjątekListy

#include <iostream>
#include <cstring>

struct Punkt
  {
   double x,y;
   Punkt():x(0),y(0) {}
   Punkt(double x,double y):x(x),y(y) {}
  };

ostream &operator<<(ostream &cout,const Punkt &P)
  {
   return(cout<<'('<<P.x<<','<<P.y<<')');
  }

class WyjatekListy {};

template<typename Dane> class Lista
  {
   private:
   struct Wezel
     {
      Wezel *Poprzedni,*Nastepny;
      Dane P;
      Wezel(Wezel *Poprzedni,Wezel *Nastepny,Dane P);
     };
   Wezel *Pierwszy,*Ostatni;
   void _zwolnij(); 			  //prywatna metoda zwalniająca wszystko
   void _kopiuj(const Lista &L); //prywatna metoda kopiująca
   public:
   Lista():Pierwszy(0),Ostatni(0) {}
   Lista(const Lista &L):Pierwszy(0),Ostatni(0) { _kopiuj(L); }
   ~Lista() { _zwolnij(); }
   Lista &operator=(const Lista &L);
   Lista &operator<<(const Dane &P);
   Lista &operator>>(Dane &P);
   operator const Dane&()const;
   operator bool()const { return(Pierwszy); }
   void Wyczysz() { _zwolnij(); Ostatni=0; } // Pierwszy będzie już 0
   friend ostream &operator<<(ostream &cout,const Lista &L);
  };

template<typename Dane> Lista<Dane>::Wezel::Wezel(Wezel *Poprzedni,
  Wezel *Nastepny,Dane P):Poprzedni(Poprzedni),Nastepny(Nastepny),P(P)
  {
  }

template<typename Dane> void Lista<Dane>::_zwolnij()
  {
   while(Pierwszy)
     {
      Wezel *Stary=Pierwszy;
      Pierwszy=Pierwszy->Nastepny;
      delete Stary;
     }
  } // po wykonaniu Pierwszy=0 zaś Ostatni nie koniecznie



template<typename Dane> void Lista<Dane>::_kopiuj(const Lista<Dane> &L)
  {
   for(Wezel *i=L.Pierwszy;i;i=i->Nastepny) operator<<(i->P);
  }

template<typename Dane> Lista<Dane>
				&Lista<Dane>::operator=(const Lista<Dane> &L)
  {
   _zwolnij(); // Pierwszy będzie już 0
   Ostatni=0;
   _kopiuj(L);
   return(*this);
  }

template<typename Dane> Lista<Dane>
				&Lista<Dane>::operator<<(const Dane &P)
  {
   Wezel *Nowy=new Wezel(Ostatni,0,P);
   if(Ostatni) Ostatni->Nastepny=Nowy;
   else        Pierwszy=Nowy;
   Ostatni=Nowy;
   return(*this);
  }

template<typename Dane> Lista<Dane> &Lista<Dane>::operator>>(Dane &P)
  {
   if(!Pierwszy) throw WyjatekListy();
   Wezel *Stary=Pierwszy;
   P=Stary->P;
   if(Stary->Nastepny) Stary->Nastepny->Poprzedni=0;
   else                Ostatni=0;
   Pierwszy=Stary->Nastepny;
   return(*this);
  }

template<typename Dane> Lista<Dane>::operator const Dane&()const
  {
   if(!Pierwszy) throw WyjatekListy();
   return(Pierwszy->P);
  }

template<typename Dane>
				ostream &operator<<(ostream &cout,const Lista<Dane> &L)
  { // argument zasłania zmienna globalną
   cout<<'{';
   // deklaracja zmiennej i !!!
   for(Lista<Dane>::Wezel *i=L.Pierwszy;i;i=i->Nastepny)
     {
      cout<<(i->P);
      if(i->Nastepny) cout<<',';
     }
   return(cout<<'}');
  }







  int main()
  {
   Punkt A(3,4),B;
   cout	<<"Punkt A(3,4),B;"<<endl
   		<<"\tA="<<A<<" B="<<B<<endl;
   Lista<Punkt> L;
   cout<<"Lista<Punkt> L;"<<endl<<"\tL="<<L<<endl;
   L<<A<<Punkt(5,12)<<B<<Punkt(7,7);
   cout	<<"L<<A<<Punkt(5,12)<<B<<Punkt(7,7);"<<endl
   		<<"\tL="<<L<<endl;
   L>>B>>A;
   cout<<"L>>B>>A;"<<endl<<"\tA="<<A<<" B="<<B<<" L="<<L<<endl;
   Punkt P=L;
   cout<<"Punkt P=L;"<<endl<<"\tP="<<P<<" L="<<L<<endl;
   while(L)
     {
      cout<<"while(L) -> prawda"<<endl;
      L>>P;
      cout<<"L>>P;"<<endl<<"\tP="<<P<<" L="<<L<<endl;
     }
   cout<<"while(L) -> falsz"<<endl;
   cin.get();

   string a("Ala"),b("Ewa");
   cout	<<"string a(\"Ala\"),b(\"Ewa\");"<<endl
   		<<"\ta=\""<<a<<"\" b=\""<<b<<'"'<<endl;
   Lista<string> l;
   cout	<<"Lista<string> l;"<<endl<<"\tl="<<l<<endl;
   l<<a<<string("Marek")<<b<<string("Adam");
   cout	<<"l<<a<<string(\"Marek\")<<b<<string(\"Adam\");"<<endl
   		<<"\tl="<<l<<endl;
   l>>b>>a;
   cout	<<"L>>b>>a;"<<endl
   		<<"\ta=\""<<a<<"\" b="<<b<<"\" l="<<l<<endl;
   string s=l;
   cout<<"string s=l;"<<endl<<"\ts=\""<<s<<"\" l="<<l<<endl;
   while(l)
     {
      cout<<"while(l) -> prawda"<<endl;
      l>>s;
      cout<<"l>>ss"<<endl<<"\ts=\""<<s<<"\" l="<<l<<endl;
     }
   cout<<"while(l) -> falsz"<<endl;

   cin.get();
   return(0);
  }





