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

namespace CLRUnleashed.IL
{
	interface IBasicArithmetic
	{
		int Add(int a, int b);
		int Subtract(int a, int b);
		int Multiply(int a, int b);
		int Divide(int a, int b);
	}
	struct Complex
	{
		public Complex(float real, float imaginary)
		{
			this.real = real;
			this.imaginary = imaginary;
		}
		public float Real
		{
			get
			{
				return real;
			}
			set
			{
				real = value;
			}
		}
		public float Imaginary
		{
			get
			{
				return imaginary;
			}
			set
			{
				imaginary = value;
			}
		}
		private float real;
		private float imaginary;
	}
	interface IComplexArithmetic
	{
		Complex Add(Complex a, Complex b);
		Complex Subtract(Complex a, Complex b);
		Complex Multiply(Complex a, Complex b);
		Complex Divide(Complex a, Complex b);
	}
	class MathOperations : IBasicArithmetic, IComplexArithmetic
	{
		public enum OperationType {Add, Subtract, Multiply, Divide}
		public delegate void OperationHandler(OperationType type, int result);
		public event OperationHandler Operation;
		private static int constructionCount = 0;
		private int addCount = 0;
		private int subtractCount = 0;
		private int multiplyCount = 0;
		private int divideCount = 0;
		public MathOperations()
		{
			constructionCount++;
		}
		static int Count
		{
			get
			{
				return constructionCount;
			}
		}
		public int Add(int a, int b)
		{
			addCount++;
			int result = a + b;
			if (Operation != null)
			{
				Operation(OperationType.Add, result);
			}
			return result;
		}
		public int Subtract(int a, int b)
		{
			subtractCount++;
			int result = a - b;
			if (Operation != null)
			{
				Operation(OperationType.Subtract, result);
			}
			return result;
		}
		public int Multiply(int a, int b)
		{
			multiplyCount++;
			int result = a * b;
			if (Operation != null)
			{
				Operation(OperationType.Multiply, result);
			}
			return result;
		}
		public int Divide(int a, int b)
		{
			divideCount++;
			int result = a / b;
			if (Operation != null)
			{
				Operation(OperationType.Divide, result);
			}
			return result;
		}
		public Complex Add(Complex a, Complex b)
		{
			return new Complex(a.Real + b.Real, a.Imaginary + b.Imaginary);
		}
		public Complex Subtract(Complex a, Complex b)
		{
			return new Complex(a.Real - b.Real, a.Imaginary - b.Imaginary);
		}
		public Complex Multiply(Complex a, Complex b)
		{
			return new Complex(a.Real * b.Real - a.Imaginary * b.Imaginary,
				               a.Real * b.Imaginary + a.Imaginary * b.Real);
		}
		public Complex Divide(Complex a, Complex b)
		{
			float divisor = b.Real * b.Real + b.Imaginary * b.Imaginary;
			return new Complex((a.Real * b.Real + a.Imaginary * b.Imaginary)/divisor,
				               (a.Real * b.Imaginary - a.Imaginary * b.Real)/divisor);
		}
	}
	class TestObject
	{
		public int testObjectFielda;
		public int testObjectFieldb;
	}
	/// <summary>
	/// Podsumowanie dla ILSampler.
	/// </summary>
	class ILSampler
	{
		private static void OnOperation(MathOperations.OperationType type, int result) 
		{
			Console.WriteLine("Operacja {0} {1} rozpoczęta", type, result);
		}
		int TestManyArguments(
			int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9,
			int a10, int a11, int a12, int a13, int a14, int a15, int a16, int a17, int a18, int a19,
			int a20, int a21, int a22, int a23, int a24, int a25, int a26, int a27, int a28, int a29,
			int a30, int a31, int a32, int a33, int a34, int a35, int a36, int a37, int a38, int a39,
			int a40, int a41, int a42, int a43, int a44, int a45, int a46, int a47, int a48, int a49,
			int a50, int a51, int a52, int a53, int a54, int a55, int a56, int a57, int a58, int a59,
			int a60, int a61, int a62, int a63, int a64, int a65, int a66, int a67, int a68, int a69,
			int a70, int a71, int a72, int a73, int a74, int a75, int a76, int a77, int a78, int a79,
			int a80, int a81, int a82, int a83, int a84, int a85, int a86, int a87, int a88, int a89,
			int a90, int a91, int a92, int a93, int a94, int a95, int a96, int a97, int a98, int a99,
			int a100, int a101, int a102, int a103, int a104, int a105, int a106, int a107, int a108, int a109,
			int a110, int a111, int a112, int a113, int a114, int a115, int a116, int a117, int a118, int a119,
			int a120, int a121, int a122, int a123, int a124, int a125, int a126, int a127, int a128, int a129,
			int a130, int a131, int a132, int a133, int a134, int a135, int a136, int a137, int a138, int a139,
			int a140, int a141, int a142, int a143, int a144, int a145, int a146, int a147, int a148, int a149,
			int a150, int a151, int a152, int a153, int a154, int a155, int a156, int a157, int a158, int a159,
			int a160, int a161, int a162, int a163, int a164, int a165, int a166, int a167, int a168, int a169,
			int a170, int a171, int a172, int a173, int a174, int a175, int a176, int a177, int a178, int a179,
			int a180, int a181, int a182, int a183, int a184, int a185, int a186, int a187, int a188, int a189,
			int a190, int a191, int a192, int a193, int a194, int a195, int a196, int a197, int a198, int a199,
			int a200, int a201, int a202, int a203, int a204, int a205, int a206, int a207, int a208, int a209,
			int a210, int a211, int a212, int a213, int a214, int a215, int a216, int a217, int a218, int a219,
			int a220, int a221, int a222, int a223, int a224, int a225, int a226, int a227, int a228, int a229,
			int a230, int a231, int a232, int a233, int a234, int a235, int a236, int a237, int a238, int a239,
			int a240, int a241, int a242, int a243, int a244, int a245, int a246, int a247, int a248, int a249,
			int a250, int a251, int a252, int a253, int a254, int a255, int a256, int a257, int a258, int a259,
			int a260, int a261, int a262, int a263, int a264, int a265, int a266, int a267, int a268, int a269,
			int a270, int a271, int a272, int a273, int a274, int a275, int a276, int a277, int a278, int a279,
			int a280, int a281, int a282, int a283, int a284, int a285, int a286, int a287, int a288, int a289,
			int a290, int a291, int a292, int a293, int a294, int a295, int a296, int a297, int a298, int a299,
			int a300, int a301, int a302, int a303, int a304, int a305, int a306, int a307, int a308, int a309,
			int a310, int a311, int a312, int a313, int a314, int a315, int a316, int a317, int a318, int a319,
			int a320, int a321, int a322, int a323, int a324, int a325, int a326, int a327, int a328, int a329,
			int a330, int a331, int a332, int a333, int a334, int a335, int a336, int a337, int a338, int a339,
			int a340, int a341, int a342, int a343, int a344, int a345, int a346, int a347, int a348, int a349,
			int a350, int a351, int a352, int a353, int a354, int a355, int a356, int a357, int a358, int a359,
			int a360, int a361, int a362, int a363, int a364, int a365, int a366, int a367, int a368, int a369,
			int a370, int a371, int a372, int a373, int a374, int a375, int a376, int a377, int a378, int a379,
			int a380, int a381, int a382, int a383, int a384, int a385, int a386, int a387, int a388, int a389,
			int a390, int a391, int a392, int a393, int a394, int a395, int a396, int a397, int a398, int a399
			)
		{
			return a254 + a255 + a256 + a393 + a394 + a395 + a396 + a397 + a398 + a399;
		}
		int TestLocal(int i, int j, int k, int l, int m, int n)
		{
			double x = 0;
			float y = 2;
			float z = 1.23F;
			double w = 1.23;
			i = 10;
			int a = 126 * i;
			int b = 127 * j;
			int c = 128 * k;
			int d = -127 * l;
			int e = -126 * m;
			int f = -128 * n;
			int g = 500;
			int h = 50;
			object o = j;
			g = (int)o;
			return a + b + c + d + e + f + g + h;
		}
		void TestAddress(ref int a, out int b)
		{
			int i = a;
			int j;
			a = 10;
			b = 20 + i;
			j = b;
			int [] ia = new int[]{1,2,3,4,5};
			float [] fa = new float [] { 1, 2, 3, 4, 4};
			a = ia[0] + ia[1] + ia[2];
			ia[1] = 10;
			string [] sa = new string[] { "To" , "jest", "nowy", "test" };
			Console.WriteLine(sa[1]);
			Console.WriteLine(sa.Length);
			sa[1] = "nie jest";
			string s;
			s = "Witaj";
			if(i == 0)
				Console.WriteLine(s);
		}
		void TestObject()
		{
			TestObject to = new TestObject();
			to.testObjectFielda = 10;
			to.testObjectFieldb = 20;
			int a;
			if(to.testObjectFielda > 20)
				goto init;
			goto skip;
init:
			a = to.testObjectFielda * 20;
skip:
			a = to.testObjectFieldb + 20;
		}
		static void TestCast(IBasicArithmetic b)
		{
			Console.WriteLine("{0}", b.Add(2,3));
			IComplexArithmetic ic = b as IComplexArithmetic;
			if(ic != null)
				ic.Add(new Complex(1,2), new Complex(3,4));
		}
		/// <summary>
		/// Główny punkt wejścia dla aplikacji.
		/// </summary>
		[STAThread]
		static void Main(string[] args)
		{
			try
			{
				MathOperations c = new MathOperations();
				c.Operation += new MathOperations.OperationHandler(ILSampler.OnOperation);
				IBasicArithmetic ib = c as IBasicArithmetic;
				if(ib == null)
					throw new InvalidCastException("Rzutowanie interfejsu nie jest możliwe");
				int result = ib.Add(1, 2);
				Console.WriteLine("{0}", int.MaxValue);
				TestCast(c);
			}
			catch(Exception e)
			{
				Console.WriteLine("Wyjątek: {0}", e);
			}
			finally
			{
				Console.WriteLine("Blok Finally");
			}
		}
	}
}
