using AddisonWesley.Michaelis.EssentialCSharp.Chapter17.Listing17_10;

namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter17.Listing17_11
{
    using System;

    public class BinaryTree<T> 
    {

        public BinaryTree(T value)
        {
            Value = value;
        }

        /// <summary>
        /// Zwraca drzewo typu BinaryTree<typeparamref name="T"/> z określonej lokalizacji.
        /// </summary>
        /// <param name="branches">Tablica elementów typu PairItem
        /// reprezentujących określoną gałąź.</param>
        /// <example>
        /// familyTree.SubItems.Second.SubItems[PairItem.First].Value
        /// </example>
        public BinaryTree<T> this[params PairItem[] branches]
        {
            get
            {
                BinaryTree<T> currentNode = this;

                // Umożliwia przedstawianie korzenia 
                // za pomocą pustej tablicy lub wartości null.
                int totalLevels = branches?.Length ?? 0;
                int currentLevel = 0;

                while (currentLevel < totalLevels)
                {
                    System.Diagnostics.Debug.Assert(branches != null,
                        $"{ nameof(branches) } != null");

                    currentNode = currentNode.SubItems[
                        branches[currentLevel]];
                    if (currentNode == null)
                    {
                        // W tym miejscu drzewo binarne ma wartość null.
                        throw new IndexOutOfRangeException();
                    }
                    currentLevel++;
                }
                return currentNode;
            }
        }

        public T Value { get; set; }

        public Pair<BinaryTree<T>> SubItems {get;set;}

    }

    public class Program
    {
        public static void Main()
        {
            // John Fitzgerald Kennedy
            var jfkFamilyTree = new BinaryTree<string>(
                "John Fitzgerald Kennedy");

            jfkFamilyTree.SubItems = new Pair<BinaryTree<string>>(
                new BinaryTree<string>("Joseph Patrick Kennedy"),
                new BinaryTree<string>("Rose Elizabeth Fitzgerald"));

            // Dziadkowie ze strony ojca.
            jfkFamilyTree.SubItems.First.SubItems =
                new Pair<BinaryTree<string>>(
                new BinaryTree<string>("Patrick Joseph Kennedy"),
                new BinaryTree<string>("Mary Augusta Hickey"));

            // Dziadkowie ze strony matki.
            jfkFamilyTree.SubItems.Second.SubItems =
                new Pair<BinaryTree<string>>(
                new BinaryTree<string>("John Francis Fitzgerald"),
                new BinaryTree<string>("Mary Josephine Hannon"));

            Console.WriteLine(jfkFamilyTree[PairItem.Second, PairItem.First].Value);
            Console.WriteLine(jfkFamilyTree[PairItem.Second, PairItem.Second].Value);
        }
    }
}
