using System;
using System.Collections.Generic;

// Klasa została uproszczona, aby przedstawić porównywanie
abstract public class Animal : IComparable<Animal>
{
	protected int weight;
	protected string name;

	public Animal(int weight, string name)
	{
		this.weight = weight;
		this.name = name;
	}

	// ** Nowa **
	public static AnimalComparer GetComparer()
	{
		return new Animal.AnimalComparer();
	}

	public int CompareTo(Animal rhs)
	{
		return this.weight.CompareTo(rhs.weight);
	}

	// ** Nowa **
	public int CompareTo(Animal rhs,
	   Animal.AnimalComparer.ComparisonType whichComparison)
	{
		switch (whichComparison)
		{
			case AnimalComparer.ComparisonType.name:
				return this.name.CompareTo(rhs.name);
			case AnimalComparer.ComparisonType.size:
				return this.weight.CompareTo(rhs.weight);
		}
		return -1; // Wszystkie ścieżki muszą zwracać wartość
	}

	// Zagnieżdżona klasa — ** nowa **
	public class AnimalComparer : IComparer<Animal>
	{
		// W jaki sposób należy porównywać?
		public enum ComparisonType
		{
			size,
			name
		};

		private Animal.AnimalComparer.ComparisonType whichComparison;
		public Animal.AnimalComparer.ComparisonType WhichComparison
		{
			get { return whichComparison; }
			set { whichComparison = value; }
		}

		// Porównywanie dwóch obiektów klasy Animal przy użyciu 
		// ustawionej wcześniej wartości whichComparison
		public int Compare(Animal lhs, Animal rhs)
		{
			return lhs.CompareTo(rhs, whichComparison);
		}

		// Potrzebna do implementacji interfejsu
		public bool Equals(Animal lhs, Animal rhs)
		{
			return this.Compare(lhs, rhs) == 0;
		}

		// Potrzebna do implementacji interfejsu
		public int GetHashCode(Animal a)
		{
			return a.weight.GetHashCode();
		}
	} // Koniec zagnieżdżonej klasy
}    // Koniec Animal


public class Dog : Animal
{
	public Dog(int weight, string name, string breed)
		:
	   base(weight, name)
	{ }

	public override string ToString()
	{
		return "Wabię się " + this.name + " i ważę " + this.weight + " kilogramów";
	}
}

public class Cat : Animal
{

	public Cat(int weight, string name)
		:
	   base(weight, name)
	{ }

	public override string ToString()
	{
		return "Wabię się " + this.name + " i ważę " + this.weight + " kilogramów";
	}
}

public class Tester
{
	static void Main()
	{
		List<Animal> myAnimals = new List<Animal>();
		myAnimals.Add(new Dog(36, "Milog", "Golden"));
		myAnimals.Add(new Cat(6, "Szekspir"));
		myAnimals.Add(new Cat(5, "Alegra"));
		myAnimals.Add(new Dog(25, "Dingo", "kundel"));
		myAnimals.Add(new Dog(10, "Brandy", "Beagle"));

		Console.WriteLine("Przed sortowaniem...");
		foreach (Animal a in myAnimals)
		{
			Console.WriteLine(a);
		}

		Console.WriteLine("\nPo domyślnym sortowaniu (według wagi)...");
		myAnimals.Sort();
		foreach (Animal a in myAnimals)
		{
			Console.WriteLine(a);
		}

		Console.WriteLine("\nPo sortowaniu według imion...");
		Animal.AnimalComparer animalComparer = Animal.GetComparer();
		animalComparer.WhichComparison = Animal.AnimalComparer.ComparisonType.name;
		myAnimals.Sort(animalComparer);
		foreach (Animal a in myAnimals)
		{
			Console.WriteLine(a);
		}

		Console.WriteLine("\nPo jawnym sortowaniu według wagi...");
		animalComparer.WhichComparison = Animal.AnimalComparer.ComparisonType.size;
		myAnimals.Sort(animalComparer);
		foreach (Animal a in myAnimals)
		{
			Console.WriteLine(a);
		}
	}  // Koniec Main
}     // Koniec Tester

