using BibliotekaWspolna;
using static System.Console;

// Konfigurowanie i wypisywanie wartości pól

// var bartek = new Osoba(); // C# 1.0 lub nowsze
Osoba bartek = new();
// WriteLine(bob.ToString());

bartek.Nazwisko = "Bartek Nowak";
bartek.DataUrodzenia = new DateTime(1965, 12, 22); // C# 1.0 lub nowsze

WriteLine(format: "{0} urodził się {1:dddd, d MMMM yyyy}",
  arg0: bartek.Nazwisko,
  arg1: bartek.DataUrodzenia);

Osoba alicja = new()
{
  Nazwisko = "Alicja Kowalska",
  DataUrodzenia = new(1998, 3, 7) // C# 9.0 lub nowsze
};

WriteLine(format: "{0} urodziła się {1:dd MMM yy}",
  arg0: alicja.Nazwisko,
  arg1: alicja.DataUrodzenia);

// Zapisywanie wartości za pomocą typów enum

bartek.UlubionyAntycznyCud = AntyczneCudaSwiata.PosagZeusaWOlimpii;

WriteLine(
  format: "Ulubiony cud {0} to {1}. Jego liczbowa reprezentacja to {2}.",
  arg0: bartek.Nazwisko,
  arg1: bartek.UlubionyAntycznyCud,
  arg2: (int)bartek.UlubionyAntycznyCud);

// Zapisywanie wielu wartości za pomocą typów enum

bartek.DoOdwiedzenia =
  AntyczneCudaSwiata.WiszaceOgrodyBabilonu
  | AntyczneCudaSwiata.MauzoleumWHalikarnasie;

// bartek.BucketList = (AntyczneCudaSwiata)18; 

WriteLine($"{bartek.Nazwisko} chce odwiedz {bartek.DoOdwiedzenia}");

// Zapisywanie wielu wartości za pomocą kolekcji

bartek.Dzieci.Add(new Osoba { Nazwisko = "Alfred" }); // C# 3.0 lub nowsze
bartek.Dzieci.Add(new() { Nazwisko = "Zuza" }); // C# 9.0 lub nowsze

WriteLine(
  $"{bartek.Nazwisko} ma {bartek.Dzieci.Count} dzieci:");

for (int dziecko = 0; dziecko < bartek.Dzieci.Count; dziecko++)
{
  WriteLine($"  {bartek.Dzieci[dziecko].Nazwisko}");
}

// Tworzenie pól statycznych

KontoBankowe.Oprocentowanie = 0.012M; // przechowywanie wspólnej wartości

KontoBankowe kb1 = new(); // C# 9.0 i nowsze
kb1.NazwaKonta = "Pani Jadzia";
kb1.Saldo = 2400;

WriteLine(format: "{0} zarobiła {1:C} na odsetkach.",
  arg0: kb1.NazwaKonta,
  arg1: kb1.Saldo * KontoBankowe.Oprocentowanie);

KontoBankowe kb2 = new();
kb2.NazwaKonta = "Pan Hilary";
kb2.Saldo = 98;

WriteLine(format: "{0} zarobił {1:C} na odsetkach.",
  arg0: kb2.NazwaKonta,
  arg1: kb2.Saldo * KontoBankowe.Oprocentowanie);

// Tworzenie stałych pól

WriteLine($"{bartek.Nazwisko} to {Osoba.Gatunek}");

// Tworzenie pól tylko do odczytu

WriteLine($"{bartek.Nazwisko} pochodzi z planety {bartek.Planeta}");

// Inicjowanie pól w konstruktorach

Osoba o3 = new();

WriteLine(format:
  "{0} z planety {1}, utworzono o godzinie {2:hh:mm:ss} w dniu {2:dddd}"
  arg0: o3.Nazwisko,
  arg1: o3.Planeta,
  arg2: o3.Utworzono
);


Osoba o4 = new(wstepneNazwisko: "Artur", wstepnaPlanetaPochodzenia: "Mars");

WriteLine(format:
  "{0} z planety {1}, utworzono o godzinie {2:hh:mm:ss} w dniu {2:dddd}",
  arg0: o4.Nazwisko,
  arg1: o4.Planeta,
  arg2: o4.Utworzono);


// Zwracanie wartości z metody

bartek.WypiszWKonsoli();
WriteLine(bartek.PodajPochodzenie());

// Łączenie wielu wartości za pomocą krotki

(string, int) owoc = bartek.WezOwoce();
WriteLine($"{owoc.Item1}, jest ich {owoc.Item2}.");

// Nazywanie pól krotki

var nazwanyOwoc = bartek.PobierzNazwaneOwoce();
WriteLine($"Czy masz {nazwanyOwoc.Liczba} {nazwanyOwoc.Nazwa}?");

// Wnioskowanie nazw krotek

var krotka1 = ("Mateusz", 4);
WriteLine($"{krotka1.Item1} ma {krotka1.Item2} dzieci.");

var rzecz2 = (bartek.Nazwisko, bartek.Dzieci.Count);
WriteLine($"{rzecz2.Nazwisko} ma {rzecz2.Count} dzieci.");

// Dekonstruowanie krotek

(string nazwaOwocu, int liczbaOwoców) = bartek.WezOwoce();
WriteLine($"Po dekonstrukcji: {nazwaOwocu}, {liczbaOwoców}");

// Dekonstruowanie typów

var (nazwisko1, dataUrodzenia1) = bartek;
WriteLine($"Po dekonstrukcji: {nazwisko1}, {dataUrodzenia1}");

var (nazwisko2, dataUrodzenia2, ulubiony2) = bartek;
WriteLine($"Po dekonstrukcji: {nazwisko2}, {dataUrodzenia2}, {ulubiony2}");

// Sterowanie przekazywaniem parametrów

WriteLine(bartek.PowiedzCzesc());
WriteLine(bartek.PowiedzCzesc("Emilia"));

// Parametry opcjonalne i nazywane

WriteLine(bartek.ParametryOpcjonalne());

WriteLine(bartek.ParametryOpcjonalne("Skacz!", 98.5));

WriteLine(bartek.ParametryOpcjonalne(
  liczba: 52.7, polecenie: "Hide!"));

WriteLine(bartek.ParametryOpcjonalne("Poke!", aktywne: false));

// Sterowanie przekazywaniem parametrów

int a = 10;
int b = 20;
int c = 30;

WriteLine($"Przed: a = {a}, b = {b}, c = {c}");

bartek.PrzekazywanieParametrów(a, ref b, out c);

WriteLine($"Po: a = {a}, b = {b}, c = {c}");

int d = 10;
int e = 20;

WriteLine(
  $"Przed: d = {d}, e = {e}, f jeszcze nie istnieje!");

// uproszczona składnia parametrów out z języka C# 7
bartek.PrzekazywanieParametrów(d, ref e, out int f);

WriteLine($"Po: d = {d}, e = {e}, f = {f}");

// Definiowanie własciwości tylko do odczytu

Osoba staszek = new()
{
  Nazwisko = "Staszek",
  DataUrodzenia = new(1972, 1, 27)
};

WriteLine(staszek.Pochodzenie);
WriteLine(staszek.Pozdrowienie);
WriteLine(staszek.Wiek);

// Definiowanie właściwości z możliwością przypisania wartości

staszek.UlubioneLody = "czekoladowe";

WriteLine($"Stanisław najchętniej je lody {staszek.UlubioneLody}.");

staszek.UlubionyKolorPodstawowy = "czerwony";

WriteLine($"Stanisław najbardziej lubi kolor {staszek.UlubionyKolorPodstawowy}.");

// Definiowanie indekserów

staszek.Dzieci.Add(new() { Nazwisko = "Karol" });
staszek.Dzieci.Add(new() { Nazwisko = "Zosia" });

WriteLine($"Pierwsze dziecko stanisława to {staszek.Dzieci[0].Nazwisko}");
WriteLine($"Drugie dziecko stanisława to {staszek.Dzieci[1].Nazwisko}");
WriteLine($"Pierwsze dziecko stanisława to {staszek[0].Nazwisko}");
WriteLine($"Drugie dziecko stanisława to {staszek[1].Nazwisko}");

// Dopasowywanie wzorców

object[] pasazerowie = {
        new PasazerKlasyPierwszej { Mile = 1_419 },
        new PasazerKlasyPierwszej { Mile = 16_562 },
        new PasazerKlasyBiznesowej(),
        new PasazerKlasyEkonomicznej { BagazPodreczny = 25.7 },
        new PasazerKlasyEkonomicznej { BagazPodreczny = 0 },
      };

foreach (object pasazer in pasazerowie)
{
  decimal kosztPrzelotu = pasazer switch
  {

     /* składnia C# 8
     PasazerKlasyPierwszej p when p.Mile > 35000 => 1500M,
     PasazerKlasyPierwszej p when p.Mile > 15000 => 1750M,
     PasazerKlasyPierwszej                       => 2000M, */

     // składnia C# 9 
     PasazerKlasyPierwszej p => p.Mile switch
    {
      > 35000 => 1500M,
      > 15000 => 1750M,
      _ => 2000M
    },

    PasazerKlasyBiznesowej => 1000M,
    PasazerKlasyEkonomicznej p when p.BagazPodreczny < 10.0 => 500M,
    PasazerKlasyEkonomicznej => 650M,
    _ => 800M
  };

  WriteLine($"Lot pasażera {pasazer} kosztuje {kosztPrzelotu:C}");
}

// Praca z rekordami

NiezmiennaOsoba jurek = new()
{
  Imie = "Jurek",
  Nazwisko = "Wiurek"
};

// Użycie właściwości z modyfikatorem init uniemożliwia zastosowanie poniższej instrukcji
// jurek.Imie = "Grześ";

NiezmiennyPojazd samochod = new()
{
  Marka = "Mazda MX-5",
  Kolor = "Soul Red Crystal Metallic",
  Kola = 4
};

NiezmiennyPojazd przemalowanySamochod = samochod
  with { Kolor = "Polymetallic Grey" };

WriteLine($"Pierwotnie auto miało kolor {samochod.Kolor}.");
WriteLine($"A teraz ma kolor {przemalowanySamochod.Kolor}.");

NiezmienneZwierze oscar = new("Oskar", "Labrador");
var (kto, co) = oscar; // wywołuje metodę Deconstruct
WriteLine($"{kto} to {co}.");