using System;
using System.Collections.Generic;
using System.Text;

namespace WorkingWithDelegates
{
	public enum Comparison
	{
		theFirstComesFirst = 1,
		theSecondComesFirst = 2
	}

	// Prosta kolekcja przechowująca dwa elementy
	public class Pair<T>
	{

		// Prywatna tablica przechowująca dwa obiekty 
		private T[] thePair = new T[2];

		// Deklaracja delegata
		public delegate Comparison
		   WhichIsFirst(T obj1, T obj2);

		// Konstruktor przyjmuje dwa obiekty i
		// umieszcza je w takiej kolejności, w jakiej je otrzymał
		public Pair(
		   T firstObject,
		   T secondObject)
		{
			thePair[0] = firstObject;
			thePair[1] = secondObject;
		}

		// Publiczna metoda porządkująca dwa obiekty według
		// określonych przez nie kryteriów
		public void Sort(
		   WhichIsFirst theDelegatedFunc)
		{
			if (theDelegatedFunc(thePair[0], thePair[1])
				 == Comparison.theSecondComesFirst)
			{
				T temp = thePair[0];
				thePair[0] = thePair[1];
				thePair[1] = temp;
			}
		}
		// Publiczna metoda porządkująca dwa obiekty odwrotnie
		// do określonych przez nie kryteriów
		public void ReverseSort(
		   WhichIsFirst theDelegatedFunc)
		{
			if (theDelegatedFunc(thePair[0], thePair[1]) ==
				 Comparison.theFirstComesFirst)
			{
				T temp = thePair[0];
				thePair[0] = thePair[1];
				thePair[1] = temp;
			}
		}

		// Pobieranie łańcuchów znaków reprezentujących oba obiekty 
		public override string ToString()
		{
			return thePair[0].ToString() + ", "
			   + thePair[1].ToString();
		}
	} // Koniec Pair

	public class Dog
	{
		private int weight;

		public Dog(int weight)
		{
			this.weight = weight;
		}

		// Psy są porządkowane według wagi
		public static Comparison WhichDogComesFirst(
		   Dog d1, Dog d2)
		{
			return d1.weight < d2.weight ?
			   Comparison.theFirstComesFirst :
			   Comparison.theSecondComesFirst;
		}
		public override string ToString()
		{
			return weight.ToString();
		}
	} // Koniec Dog

	public class Student
	{
		private string name;

		public Student(string name)
		{
			this.name = name;
		}
		// Studenci są porządkowani alfabetycznie
		public static Comparison
		WhichStudentComesFirst(Student s1, Student s2)
		{
			return (String.Compare(s1.name, s2.name) < 0 ?
			   Comparison.theFirstComesFirst :
			   Comparison.theSecondComesFirst);
		}

		public override string ToString()
		{
			return name;
		}
	} // Koniec Student

	public class Test
	{
		public static void Main()
		{
			// Tworzenie dwóch studentów i dwóch psów
			// oraz umieszczanie ich w obiektach klasy Pair
			Student Jesse = new Student("Jarek");
			Student Stacey = new Student("Sandra");
			Dog Milo = new Dog(65);
			Dog Fred = new Dog(12);

			Pair<Student> studentPair = new Pair<Student>(Jesse, Stacey);
			Pair<Dog> dogPair = new Pair<Dog>(Milo, Fred);
			Console.WriteLine("Para studentPair\t\t\t: {0}",
			   studentPair.ToString());
			Console.WriteLine("Para dogPair\t\t\t\t: {0}",
			   dogPair.ToString());

			// Tworzenie egzemplarzy delegata
			Pair<Student>.WhichIsFirst theStudentDelegate =
			   new Pair<Student>.WhichIsFirst(
			   Student.WhichStudentComesFirst);

			Pair<Dog>.WhichIsFirst theDogDelegate =
			   new Pair<Dog>.WhichIsFirst(
			   Dog.WhichDogComesFirst);

			// Sortowanie przy użyciu delegatów
			studentPair.Sort(theStudentDelegate);
			Console.WriteLine("Para studentPair po sortowaniu\t\t: {0}",
			   studentPair.ToString());
			studentPair.ReverseSort(theStudentDelegate);
			Console.WriteLine("Para studentPair po odwrotnym sortowaniu\t: {0}",
			   studentPair.ToString());

			dogPair.Sort(theDogDelegate);
			Console.WriteLine("Para dogPair po sortowaniu\t\t: {0}",
			   dogPair.ToString());
			dogPair.ReverseSort(theDogDelegate);
			Console.WriteLine("Para dogPair po odwrotnym sortowaniu\t: {0}",
			   dogPair.ToString());
		}
	}
}
