//
// 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.Collections;

namespace CLRUnleashed
{
	public class PointEventArgs : EventArgs
	{
		private Point point;
		public PointEventArgs(int x, int y)
		{
			point = new Point(x, y);
		}
		public Point Point
		{
			get
			{
				return point;
			}
			set
			{
				point = value;
			}
		}
	}

	public class Point : System.Collections.IHashCodeProvider
	{
		// Zdarzenie używane przez klienta w celu powiadomienia
		// o zmianie elementów listy:
		public event EventHandler Changed;
		private int _x;
		private int _y;
		// Wywołanie zdarzenia Changed event; używane przy każdej zmianie punktu:
		private void OnChanged(PointEventArgs e) 
		{
			if (Changed != null)
				Changed(this, e);
		}
		public Point(int x, int y)
		{
			_x = x;
			_y = y;
			Changed = null;
		}
		public int X
		{
			get
			{
				return _x;
			}
			set
			{
				_x = value;
				PointEventArgs e = new PointEventArgs(_x, _y);
				OnChanged(e);
			}
		}
		public int Y
		{
			get
			{
				return _y;
			}
			set
			{
				_y = value;
				PointEventArgs e = new PointEventArgs(_x, _y);
				OnChanged(e);
			}
		}
		public Point Coordinate
		{
			get
			{
				return this;
			}
			set
			{
				_x = value._x;
				_y = value._y;
				PointEventArgs e = new PointEventArgs(_x, _y);
				OnChanged(e);
			}
		}
		public override bool Equals(object o)
		{
			bool ret = true;
			try
			{
				Point target = (Point)o;
				ret = (_x == target._x &&
					_y == target._y);
			}
			catch(Exception)
			{
				// Spodziewane niewłaściwe rzutowanie, jeśli metoda Equals 
				// została wywołana z niewłaściwym argumentem.
				// Proszę zauważyć, iż użycie operatora as i przyrównanie wyniku 
				// do pustej wartości spowoduje powstanie rekurencji, 
				// ponieważ ta metoda została użyta w operatorach != oraz ==.
				ret = false;
			}
			return ret;
		}
		public static bool operator == (Point a, Point b)
		{
			return a.Equals(b);
		}
		public static bool operator != (Point a, Point b)
		{
			return !a.Equals(b);
		}
		public override int GetHashCode()
		{
			return _x ^ _y;
		}
		int IHashCodeProvider.GetHashCode(object o)
		{
			return o.GetHashCode();
		}
		public override string ToString()
		{
			return string.Format("{0},{1}", _x, _y);
		}
	}
	/// <summary>
	/// Podsumowanie dla Class1.
	/// </summary>
	class ReferencePoint
	{
		private static void Changed(object sender, EventArgs e) 
		{
			PointEventArgs pe = (PointEventArgs)e;
			Console.WriteLine("Punkt zmienił się. ({0}, {1})", pe.Point.X, pe.Point.Y);
		}
		/// <summary>
		/// Główny punkt wejścia dla aplikacji.
		/// </summary>
		[STAThread]
		static void Main(string[] args)
		{
			Point rp = new Point(0, 0);
			Console.WriteLine("Punkt {0}", rp.GetType().BaseType);
			rp.Changed += new EventHandler(Changed);
			rp.Coordinate = new Point(1, 2);
			Point rp1 = rp;
			Console.WriteLine("p Point == p1 Point-> {0}", rp == rp1);
			Console.WriteLine("p Point Equals(p1 Point)-> {0}", rp.Equals(rp1));
			rp1 = new Point(1, 2);
			Console.WriteLine("p Point == p1 Point-> {0}", rp == rp1);
			Console.WriteLine("p Point Equals(p1 Point)-> {0}", rp.Equals(rp1));
			Console.WriteLine("Punkt {0}", rp.ToString());
		}
	}
}
