//
// Copyright (c) 2002
// Ronald Kevin Burton
//
// Z poniższym kodem nie jest związana żadna gwarancja poprawności działania.
// Program został dołączony do książki ".NET CLR. Księga eksperta" w celu
// ilustracji koncepcji i zasad przedstawionych w tej książce. Program może być 
// używany na własne ryzyko.
//
// Przyznaje się prawo do użycia lub kopiowania tego oprogramowania do dowolnego celu
// bez konieczności ponoszenia żadnych opłat pod warunkiem, że powyższe uwagi zostaną 
// zachowane we wszystkich kopiach. Przyznaje się także prawo do modyfikacji kodu
// i dystrybucji zmodyfikowanego kodu pod warunkiem zachowania powyższych uwag
// oraz dołączenia informacji mówiącej o modyfikacji kodu.
//
//
using System;
using System.Threading;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.IO;
using System.Text;

namespace Exceptions
{
	class Recurse
	{
		public static void StackOverflow()
		{
			Recurse.StackOverflow();
		}
	}
	// Własna klasa wyjątków wywodząca się z ApplicationException
	class Custom1Exception : ApplicationException
	{
		public Custom1Exception(String msg) : base(msg)
		{
		}
	}
	class Custom2Exception : ApplicationException
	{
		public Custom2Exception(String msg) : base(msg)
		{
		}
	}
	class Custom3Exception : ApplicationException
	{
		public Custom3Exception(String msg) : base(msg)
		{
		}
	}
	class Custom4Exception : ApplicationException
	{
		public Custom4Exception(String msg) : base(msg)
		{
		}
	}
	class CustomException : ApplicationException
	{
		public CustomException(String msg) : base(msg)
		{
		}
	}

	class UnmanagedException
	{
		public UnmanagedException(int err)
		{
			this.err = err;
		}
		public int err;
	}

	/// <summary>
	/// Podsumowanie BasicExceptions.
	/// </summary>
	// Być może nienajlepsza procedura obsługi zdarzenia.
	class BasicExceptions
	{
		[DllImport("user32.dll")]
		public static extern int MessageBox(int hWnd, string text, string caption, uint type);

		static void SecretMethod()
		{
			// Utworzenie obiektu uprawnień zabezpieczeń w celu opisania
			// uprawnienia UnmanagedCode:
			SecurityPermission perm = 
				new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);

			// Odrzuca UnmanagedCode z aktualnego zestawu uprawnień.
			// Żadna metoda wywoływana w tym wątku nie uzyska dostępu 
			// do niezarządzanego kodu aż do momentu powrotu tej metody.

			perm.Deny();
			MessageBox(0, "Oto moja tajna metoda.", "Ściśle tajne", 0);
		}
		static void Main(string[] args)
		{
			// Ustawienie procedury obsługi wyjątku
			Thread.GetDomain().UnhandledException += 
				new UnhandledExceptionEventHandler(UnhandledExceptionHandler);

			Console.WriteLine("\nDzielenie przez zero\n");

			// Próba dzielenia przez zero
			try
			{
				int x = 0;
				x = 1/x;
			}
			catch(DivideByZeroException e)
			{
				// Pobranie interesujących informacji o wyjątku
				Console.WriteLine (e.ToString());
			}

			Console.WriteLine("\nNaruszenie dostępu\n");

			// Próba naruszenia dostępu
			try
			{
				Object o = null;
				Console.WriteLine(o.ToString());
			}
			catch(NullReferenceException e)
			{
				// Pobranie interesujących informacji o wyjątku
				Console.WriteLine (e.ToString());
			}

			Console.WriteLine("\nPrzepełnienie stosu\n");
			try
			{
				// Recurse.StackOverflow();
			}
			catch(StackOverflowException e)
			{
				// Pobranie interesujących informacji o wyjątku
				Console.WriteLine (e.ToString());
			}

			Console.WriteLine("\nWłasny wyjątek\n");

			// Próba zgłoszenia własnego wyjątku
			try
			{
				throw new CustomException("Zgłaszam własny wyjątek");
			}
			catch(CustomException e)
			{
				// Pobranie interesujących informacji o wyjątku
				Console.WriteLine (e.ToString());
			}

			Console.WriteLine("\nWyjątek związany z obiektem\n");

			// Próba zgłoszenia wyjątku związanego z obiektem (InvalidCast)
			try
			{
				int n = 5;
				Object o = n;
				string s = (string)o;
			}
			catch(InvalidCastException e)
			{
				// Pobranie interesujących informacji o wyjątku
				Console.WriteLine (e.ToString());
			}

			Console.WriteLine("\nUprawnienie zabezpieczeń\n");
			try
			{
				SecretMethod();
			}
			catch(SecurityException e)
			{
				// Pobranie interesujących informacji o wyjątku
				Console.WriteLine (e.ToString());
			}

			Console.WriteLine("\nWyjątki wejścia-wyjścia pliku\n");
			StreamReader streamReader = null;
			try 
			{
				FileStream stream = File.OpenRead(@"..\..\BasicExceptions.cs");
				streamReader = new StreamReader(stream, Encoding.ASCII);
				streamReader.BaseStream.Seek(0, SeekOrigin.Begin);
				string s = streamReader.ReadToEnd();
				streamReader.BaseStream.Seek(0, SeekOrigin.Begin);
				// Console.WriteLine(s);
			}
			catch(Exception e)
			{
				// Pobranie interesujących informacji o wyjątku
				Console.WriteLine ("Wystąpił błąd:\n{0}", e.ToString());
			}
			finally
			{
				Console.WriteLine ("Zamknięcie pliku");
				if(streamReader != null)
					streamReader.Close();
			}


			Console.WriteLine("\nWyjątki filtrowania\n");
			try 
			{
				Random r = new Random();
				switch(r.Next(4) + 1)
				{
					case 1:
						throw new Custom1Exception("Zgłaszam wyjątek Custom1Exception");
					case 2:
						throw new Custom2Exception("Zgłaszam wyjątek Custom2Exception");
					case 3:
						throw new Custom3Exception("Zgłaszam wyjątek Custom3Exception");
					case 4:
						throw new Custom4Exception("Zgłaszam wyjątek Custom4Exception");
				}
			}
			catch(Custom1Exception e)
			{
				Console.WriteLine ("Wystąpił błąd Custom1Exception.\n{0}", e.ToString());
			}
			catch(Custom2Exception e)
			{
				Console.WriteLine ("Wystąpił błąd Custom2Exception.\n{0}", e.ToString());
			}
			catch(Custom3Exception e)
			{
				Console.WriteLine ("Wystąpił błąd Custom3Exception.\n{0}", e.ToString());
			}
			catch(Custom4Exception e)
			{
				Console.WriteLine ("Wystąpił błąd Custom4Exception.\n{0}", e.ToString());
			}

			// Przykład złego stylu programowania.
			int sum = 0;
			int i = 0;
			int [] array = new int [] {1,2,3,4,5,6};
			try
			{
				while(true)
				{
					sum += array[i++];
				}
			}
			catch(Exception e)
			{
				Console.WriteLine ("\nWyjątek granicy tablicy:\n{0}", e);
			}
			Console.WriteLine("\nSuma to {0}\n", sum);

			Console.WriteLine("\nDzielenie przez zero\n");

			Console.WriteLine("\nZagnieżdżone wyjątki\n");
			try
			{
				// Próba dzielenia przez zero
				try
				{
					int x = 0;
					x = 1/x;
				}
				catch(DivideByZeroException e)
				{
					// Pobranie interesujących informacji o wyjątku
					Console.WriteLine (e.ToString());
					throw;
				}
			}
			catch(DivideByZeroException e)
			{
				// Pobranie interesujących informacji o wyjątku
				Console.WriteLine (e.ToString());
			}

			Console.WriteLine("\nNieobsługiwany wyjątek\n");

			// Próba dzielenia przez zero i sprawdzenie efektów.
			int y = 0;
			y = 1 / y;

			Console.WriteLine("\nTo miejsce nigdy nie zostanie osiągnięte.\n");
		}
		public static void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs args)
		{
			ConsoleWriteLine("Nieobsługiwany wyjątek!");
			ConsoleWriteLine("Nadawca: {0}", sender.ToString());
			ConsoleWriteLine("Typ: {0}", args.ExceptionObject.GetType().ToString());
			ConsoleWriteLine("Przerywany: {0}", args.IsTerminating);
		}
	}
}
