package klasy;

public class Polimorfizm1 {
    public static void main(String[] args) {
        Osoba osoba = new Osoba("Ala", "Kowalska", 30);
        Student student = new Student("Adam", "Abacki", 22, "geologia", 2);
        System.out.println(osoba);
        osoba.przedstawSie();
        System.out.println();

        System.out.println(student);
        student.przedstawSie();
        System.out.println();

        Osoba ktos;
        ktos = osoba;
        ktos.przedstawSie();

        // mimo tego, że zmienna jest typu Osoba, to gdy znajduje się w niej obiekt klasy Student,
        // metoda przedstawSie wykona się w wersji studenckiej
        ktos = student;
        ktos.przedstawSie();
        System.out.println();

        Sklep sklep = new Sklep("Lidl", 6);
        sklep.sprzedajPiwo(osoba);
        sklep.sprzedajPiwo(student);
        sklep.sprzedajPiwo(ktos);

        // Zauważmy, że ze zmiennej ktos nie da się odczytać pól kierunek i rok, czy ocen
        // System.out.println(ktos.kierunek);
        // Bo "nie każda Osoba ma te dane"

        // Ale obiekt można zrzutować do zmiennej typu Student.
        // Jeśli wiemy, że w zmiennej ktos na pewno jest Student, to można tak:
        Student s1 = (Student)ktos;
        System.out.println(s1.kierunek);

        System.out.println( ((Student)ktos).rok );

        // Ale jeśli w zmiennej nie studenta, tylko zwykła osoba, to będzie wyjątek ClassCastException
//		Student s2 = (Student)osoba;
//		System.out.println(s2.kierunek);

        // Próba rzutowania na typ zupełnie niespokrewniony, gdzie ewidentnie widać, że nie ma to szans, jest błedem kompilacji
        // String txt = (String)osoba;
        // to nie to samo, co zamiana na napis za pomocą toString()
        // to już się kompiluje, ale powoduje wyjątek ClassCastException
        // String txt = (String)(Object)osoba;

        // Metoda getClass zwraca aktualną informację o tym, jakiej kalsy jest obiekt.
        System.out.println(ktos.getClass());

        // Aby sprawdzić, czy rzutowanie będzie możliwe, używamy instanceof:
        // Gdyby w zmiennej ktos był obiekt klasy StudentInformatyki, to też wyszłoby true
        if(ktos instanceof Student) {
            // rzutowanie jest bezpieczne
            System.out.println( ((Student)ktos).rok );
        }

        // Od Javy 17 (?) jest dostępne instanceof, które od razu wpisuje wynik do zmiennej:
        if(ktos instanceof Student s5) {
            s5.dodajOcene(4);
            s5.dodajOcene(5);
            System.out.println(s5.sredniaOcen());
        }

        // Przypisanie do zmiennej i rzutowanie nie tworzą nowych obiektów, tylko cały czas odnosimy się do tego samego obiektu.

        student.kierunek = "zoologia";
        student.dodajOcene(5);
        System.out.println();

        ktos.przedstawSie();
        System.out.println(student.oceny);
        System.out.println(student.sredniaOcen());
        System.out.println(((Student)ktos).sredniaOcen());
    }
}
