namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter08.Listing08_02
{
    using System;

    public class Program
    {
        public static void Main()
        {
            Contact[] contacts = new Contact[]
            {
      new Contact(
        "Jan", "Kowal",
        "ul. Budowlanych 12/13, Opole 45-287",
        "123-123-1234"),
      new Contact(
        "Andrzej", "Litwin",
        "ul. Krótka 1/23, 30-037 Kraków",
        "555-123-4567"),
      new Contact(
        "Maria", "Harbiel",
        "ul. Liliowa 7, 25-129 Kępno",
        "444-123-4567"),
      new Contact(
        "Janusz", "Stocki",
        "ul. Opolska 5/7, 43-290 Wrocław",
        "222-987-6543"),
      new Contact(
        "Patrycja", "Wielgosz",
        "ul. Kościuszki 321, 28-092 Sochaczew",
        "123-456-7890"),
      new Contact(
        "Janina", "Frątczak",
        "ul. Majowa 9/18, 01-154 Warszawa",
        "333-345-6789")
            };

            // Klasy są niejawnie rzutowane na
            // zaimplementowane w nich interfejsy.
            ConsoleListControl.List(Contact.Headers, contacts);

            Console.WriteLine();

            Publication[] publications = new Publication[3] {
      new Publication("Dyscypliny życia duchowego",
        "Richard Foster", 1978),
      new Publication("Ortodoksja",
        "G.K. Chesterton", 1908),
      new Publication(
        "Autostopem przez galaktykę",
        "Douglas Adams", 1979)
                };
            ConsoleListControl.List(
                Publication.Headers, publications);
        }
    }

    interface IListable
    {
        // Zwracanie wartości każdej kolumny z wiersza
        string[] ColumnValues
        {
            get;
        }
    }

    public abstract class PdaItem
    {
        public PdaItem(string name)
        {
            Name = name;
        }

        public virtual string Name { get; set; }
    }

    class Contact : PdaItem, IListable
    {
        public Contact(string firstName, string lastName,
            string address, string phone)
            : base(null)
        {
            FirstName = firstName;
            LastName = lastName;
            Address = address;
            Phone = phone;
        }

        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Address { get; set; }
        public string Phone { get; set; }

        public string[] ColumnValues
        {
            get
            {
                return new string[]
                {
                    FirstName,
                    LastName,
                    Phone,
                    Address
                };
            }
        }

        public static string[] Headers
        {
            get
            {
                return new string[] {
                    "Imię", "Nazwisko    ", 
                    "Telefon       ",
                    "Adres                       " };
            }
        }

        // ...
    }

    class Publication : IListable
    {
        public Publication(string title, string author, int year)
        {
            Title = title;
            Author = author;
            Year = year;
        }

        public string Title { get; set; }
        public string Author { get; set; }
        public int Year { get; set; }

        public string[] ColumnValues
        {
            get
            {
                return new string[]
                {
                    Title,
                    Author,
                    Year.ToString()
                };
            }
        }

        public static string[] Headers
        {
            get
            {
                return new string[] {
                    "Tytuł                                                    ", 
                    "Autor             ", 
                    "Rok " };
            }
        }

        // ...
    }


    class ConsoleListControl
    {
        public static void List(string[] headers, IListable[] items)
        {
            int[] columnWidths = DisplayHeaders(headers);

            for(int count = 0; count < items.Length; count++)
            {
                string[] values = items[count].ColumnValues;
                DisplayItemRow(columnWidths, values);
            }
        }

        /// <summary>Wyświetla nagłówki kolumn</summary>
        /// <returns>Zwraca tablicę szerokości kolumn</returns>
        private static int[] DisplayHeaders(string[] headers)
        {
            var columnWidths = new int[headers.Length];
            for(int index = 0; index < headers.Length; index++)
            {
                Console.Write(headers[index]);
                columnWidths[index] = headers[index].Length;
            }
            Console.WriteLine();
            return columnWidths;
        }

        private static void DisplayItemRow(
            int[] columnWidths, string[] values)
        {
            if(columnWidths.Length != values.Length)
            {
                throw new ArgumentOutOfRangeException(
                    $"{ nameof(columnWidths) },{ nameof(values) }",
                    "Liczba szerokości kolumn musi pasować do liczby wyświetlanych wartości");
            }

            for(int index = 0; index < values.Length; index++)
            {
                string itemToPrint = values[index].PadRight(columnWidths[index], ' ');
                Console.Write(itemToPrint);
            }
            Console.WriteLine();
        }
    }
}
