/*
 *				Weronika Trybek I1ISI
 *	Zad. 5 Opis wyjątków w bibliotece standardowej.
 */
 
#include <iostream>
using namespace std;

/* 
 * Klasa Sensor oraz klasa SmokeDetector po niej dziedzicząca, 
 * to proste klasy, posiadające konstruktory i destruktory wyświetlające tekst
 * w celu łatwiejszego zobrazowania mechanizmu obsługi wyjątków.
 */
class Sensor
{
protected:
	int		number_;
	char*	text_;
	bool	alarm_;
public:
	Sensor() : number_(0), text_("Zwykly Czujnik"), alarm_(false)
	{
		cout << " Konstruktor domyslny  Czujnika " << number_ << endl;
	}
	Sensor(int n, char* t) : number_(n), text_(t), alarm_(false)
	{
		cout << " Konstruktor Czujnika, ";
	}
	Sensor(const Sensor& s)
	{
		number_ = s.number_ + 1;
		text_	= s.text_;
		alarm_	= s.alarm_;
		cout << " Konstruktor kopiujacy Czujnika " << s.number_;
		if( text_ == "Zwykly Czujnik" )
			cout << ", powstaje " << number_ << endl;
		else
			cout << ", ";
	}
	virtual ~Sensor()
	{
		cout << "   Destruktor Czujnika " << number_ << endl;
	}
	virtual void alarmOn()
	{
		alarm_ = true;
		throw *this;
	}
	void alarmOff()
	{
		alarm_ = false;
	}
};

class SmokeDetector : public Sensor
{
	static int counter_;
public:
	SmokeDetector() : Sensor(++counter_, "Czujnik Dymu")
	{
		cout << "Czujnika Dymu " << number_ << endl;
	}
	SmokeDetector(const SmokeDetector& m) : Sensor(m)
	{
		++counter_;
		number_ = counter_;
		cout << "Czujnika Dymu, powstaje " << number_ << endl;
	}
	~SmokeDetector()
	{
		--counter_;
		cout << "   Destruktor Czujnika Dymu " << number_;
	}
	void alarmOn()
	{
		alarm_ = true;
		throw *this;
	}
};
int SmokeDetector::counter_ = 0;

int main()
{
	cout << "\n\n***Obsluga wyjatku, bez referencji do obiektu w argumencie catch***\n\n";
	try
	{
		Sensor sensor;		// wywołanie konstruktora domyślnego Sensor (0)
		sensor.alarmOn();	// throw sensor; -> wywołanie konstruktora kopiującego Sensor (1)
		cout << "Jestem tutaj!\n"; // tekst ten nigdy nie będzie wyświetlony, bo sterowanie przechodzi do bloku catch
	}						// sporządzenie kopii statycznej dla catch -> wywołanie konstruktora kopiującego Sensor (2)
							// odwikłanie stosu -> wywołanie destruktora Sensor (0)
	catch(Sensor s)			
	{	
		cout << "catch(Sensor s)\n";
	}						// koniec bloku catch -> wywołanie destruktora Sensor (2) i (1)
	
	cout << "\n\n***Obsluga wyjatku, z referencja do obiektu w argumencie catch***\n\n";
	try
	{
		Sensor sensor;		// wywołanie konstruktora domyślnego Sensor (0)
		sensor.alarmOn();	// throw sensor; -> wywołanie konstruktora kopiującego Sensor (1)
	}						// odwikłanie stosu -> wywołanie destruktora Sensor (0)				
	catch(Sensor& s)		// wybrany catch
	{	
		cout << "catch(Sensor& s)\n";
	}						// koniec bloku catch -> wywołanie destruktora Sensor (1)
	catch(...)				// nie wchodzi tu juz, bo wyjątek został obsłuzony przez wczesniejszy catch
	{
		cout << "catch(...)\n";
	}
	
	cout << "\n\n***Obsluga wyjatku, dziedziczenie oraz zagniezdzone bloki try i catch***\n\n";
	try
	{ // zewnetrzny try
		try // wewnetrzny try
		{
			SmokeDetector smokeDet;	// wywołanie konstruktora Sensor (1) oraz SmokeDetector (1)
			SmokeDetector smokeDet2;// wywołanie konstruktora Sensor (2) oraz SmokeDetector (2)
			smokeDet.alarmOn();		// throw SmokeDetector;-> wywołanie konstruktora kopiującego Sensor (3) i SmokeDetector (3)
		}	// odwikłanie stosu	-> wywołanie destruktorów SmokeDetector (2), Sensor (2) oraz SmokeDetector (1), Sensor (1)
		catch(Sensor& s)			// wybrany catch
		{	
			cout << "catch(Sensor& s)\n";
			throw;					// dalsze rzucenie tego samego obiektu
		}							// koniec bloku catch -> nie wywołany jest destruktor SmokeDetector, bo obiekt rzucony dalej
		catch(SmokeDetector& s)		// nie wchodzi tu juz, mimo iż dopasowanie byłoby lepsze,					
		{							// bo wyjatek zostal obsluzony przez wczesniejszy blok catch
			cout << "catch(MotionSensor& s)\n";
		}
	}					
	catch(SmokeDetector& s)			// wybrany catch, bo wyjątek został rzucony ponownie				
	{							
		cout << "zewnetrzny catch(MotionSensor& s)\n";
	}								// koniec bloku catch -> wywołanie destruktora SmokeDetector, Sensor (2)
	
	cout << "\n\n***Obsluga wyjatku, odwiklanie stosu sprzata tylko to, co zostalo \n   utworzone na stosie,"
		 << " nie usuwa obiektow utworzonych za pomoca new***\n\n";
	try
	{
		Sensor* sensor = new Sensor;// wywołanie konstruktora Sensor (0)
		sensor->alarmOn();			// throw sensor; -> wywołanie konstruktora kopiującego Sensor nr 1
		SmokeDetector smokeDet;		// ten obiekt nigdy nie bedzie utworzony
	}	// odwikłanie stosu -> wywołanie destruktora wskaznika na Sensor (0), ale sam Sensor (0) nie zostaje usuniety
	catch(Sensor& s)
	{
		cout << "catch(Sensor& s)\n";
	}								// koniec bloku catch -> wywołanie destruktora Sensor (1)
	catch(...)
	{
		cout << "catch(...)\n";
	}
	system("PAUSE");
	return 0;
}